From 774cda6f12d5ad11410c4cda223554c3735ee862 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 27 Apr 2021 22:59:55 +0200 Subject: dt-bindings: nvmem: mediatek: remove duplicate mt8192 line The same patch was accidentally merged twice, resulting in a duplicate line for the mt8192 SoC. Fixes: f2674c0c7488 ("dt-bindings: nvmem: mediatek: add support for MediaTek mt8192 SoC") Fixes: 2a1405a14c3a ("dt-bindings: nvmem: mediatek: add support for MediaTek mt8192 SoC") Signed-off-by: Arnd Bergmann --- Documentation/devicetree/bindings/nvmem/mtk-efuse.txt | 1 - 1 file changed, 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/nvmem/mtk-efuse.txt b/Documentation/devicetree/bindings/nvmem/mtk-efuse.txt index d479ad977e24..b6791702bcfc 100644 --- a/Documentation/devicetree/bindings/nvmem/mtk-efuse.txt +++ b/Documentation/devicetree/bindings/nvmem/mtk-efuse.txt @@ -9,7 +9,6 @@ Required properties: "mediatek,mt8173-efuse" or "mediatek,efuse": for MT8173 "mediatek,mt8192-efuse", "mediatek,efuse": for MT8192 "mediatek,mt8516-efuse", "mediatek,efuse": for MT8516 - "mediatek,mt8192-efuse", "mediatek,efuse": for MT8192 - reg: Should contain registers location and length = Data cells = -- cgit v1.3.1 From 46a63924b05f335b0765ad13dae4d2d7569f25c9 Mon Sep 17 00:00:00 2001 From: Siddharth Chandrasekaran Date: Mon, 3 May 2021 14:00:58 +0200 Subject: doc/kvm: Fix wrong entry for KVM_CAP_X86_MSR_FILTER The capability that exposes new ioctl KVM_X86_SET_MSR_FILTER to userspace is specified incorrectly as the ioctl itself (instead of KVM_CAP_X86_MSR_FILTER). This patch fixes it. Fixes: 1a155254ff93 ("KVM: x86: Introduce MSR filtering") Reviewed-by: Alexander Graf Signed-off-by: Siddharth Chandrasekaran Message-Id: <20210503120059.9283-1-sidcha@amazon.de> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 22d077562149..7fcb2fd38f42 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -4803,7 +4803,7 @@ KVM_PV_VM_VERIFY 4.126 KVM_X86_SET_MSR_FILTER ---------------------------- -:Capability: KVM_X86_SET_MSR_FILTER +:Capability: KVM_CAP_X86_MSR_FILTER :Architectures: x86 :Type: vm ioctl :Parameters: struct kvm_msr_filter @@ -6715,7 +6715,7 @@ accesses that would usually trigger a #GP by KVM into the guest will instead get bounced to user space through the KVM_EXIT_X86_RDMSR and KVM_EXIT_X86_WRMSR exit notifications. -8.27 KVM_X86_SET_MSR_FILTER +8.27 KVM_CAP_X86_MSR_FILTER --------------------------- :Architectures: x86 -- cgit v1.3.1 From 059e5c321a65657877924256ea8ad9c0df257b45 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Tue, 27 Apr 2021 06:16:36 -0500 Subject: x86/msr: Rename MSR_K8_SYSCFG to MSR_AMD64_SYSCFG The SYSCFG MSR continued being updated beyond the K8 family; drop the K8 name from it. Suggested-by: Borislav Petkov Signed-off-by: Brijesh Singh Signed-off-by: Borislav Petkov Acked-by: Joerg Roedel Link: https://lkml.kernel.org/r/20210427111636.1207-4-brijesh.singh@amd.com --- Documentation/virt/kvm/amd-memory-encryption.rst | 2 +- Documentation/x86/amd-memory-encryption.rst | 6 +++--- arch/x86/include/asm/msr-index.h | 6 +++--- arch/x86/kernel/cpu/amd.c | 4 ++-- arch/x86/kernel/cpu/mtrr/cleanup.c | 2 +- arch/x86/kernel/cpu/mtrr/generic.c | 4 ++-- arch/x86/kernel/mmconf-fam10h_64.c | 2 +- arch/x86/kvm/svm/svm.c | 4 ++-- arch/x86/kvm/x86.c | 2 +- arch/x86/mm/mem_encrypt_identity.c | 6 +++--- arch/x86/pci/amd_bus.c | 2 +- arch/x86/realmode/rm/trampoline_64.S | 4 ++-- drivers/edac/amd64_edac.c | 2 +- tools/arch/x86/include/asm/msr-index.h | 6 +++--- 14 files changed, 26 insertions(+), 26 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/amd-memory-encryption.rst b/Documentation/virt/kvm/amd-memory-encryption.rst index 5ec8a1902e15..5c081c8c7164 100644 --- a/Documentation/virt/kvm/amd-memory-encryption.rst +++ b/Documentation/virt/kvm/amd-memory-encryption.rst @@ -22,7 +22,7 @@ to SEV:: [ecx]: Bits[31:0] Number of encrypted guests supported simultaneously -If support for SEV is present, MSR 0xc001_0010 (MSR_K8_SYSCFG) and MSR 0xc001_0015 +If support for SEV is present, MSR 0xc001_0010 (MSR_AMD64_SYSCFG) and MSR 0xc001_0015 (MSR_K7_HWCR) can be used to determine if it can be enabled:: 0xc001_0010: diff --git a/Documentation/x86/amd-memory-encryption.rst b/Documentation/x86/amd-memory-encryption.rst index c48d452d0718..a1940ebe7be5 100644 --- a/Documentation/x86/amd-memory-encryption.rst +++ b/Documentation/x86/amd-memory-encryption.rst @@ -53,7 +53,7 @@ CPUID function 0x8000001f reports information related to SME:: system physical addresses, not guest physical addresses) -If support for SME is present, MSR 0xc00100010 (MSR_K8_SYSCFG) can be used to +If support for SME is present, MSR 0xc00100010 (MSR_AMD64_SYSCFG) can be used to determine if SME is enabled and/or to enable memory encryption:: 0xc0010010: @@ -79,7 +79,7 @@ The state of SME in the Linux kernel can be documented as follows: The CPU supports SME (determined through CPUID instruction). - Enabled: - Supported and bit 23 of MSR_K8_SYSCFG is set. + Supported and bit 23 of MSR_AMD64_SYSCFG is set. - Active: Supported, Enabled and the Linux kernel is actively applying @@ -89,7 +89,7 @@ The state of SME in the Linux kernel can be documented as follows: SME can also be enabled and activated in the BIOS. If SME is enabled and activated in the BIOS, then all memory accesses will be encrypted and it will not be necessary to activate the Linux memory encryption support. If the BIOS -merely enables SME (sets bit 23 of the MSR_K8_SYSCFG), then Linux can activate +merely enables SME (sets bit 23 of the MSR_AMD64_SYSCFG), then Linux can activate memory encryption by default (CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT=y) or by supplying mem_encrypt=on on the kernel command line. However, if BIOS does not enable SME, then Linux will not be able to activate memory encryption, even diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 742d89a00721..211ba3375ee9 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -537,9 +537,9 @@ /* K8 MSRs */ #define MSR_K8_TOP_MEM1 0xc001001a #define MSR_K8_TOP_MEM2 0xc001001d -#define MSR_K8_SYSCFG 0xc0010010 -#define MSR_K8_SYSCFG_MEM_ENCRYPT_BIT 23 -#define MSR_K8_SYSCFG_MEM_ENCRYPT BIT_ULL(MSR_K8_SYSCFG_MEM_ENCRYPT_BIT) +#define MSR_AMD64_SYSCFG 0xc0010010 +#define MSR_AMD64_SYSCFG_MEM_ENCRYPT_BIT 23 +#define MSR_AMD64_SYSCFG_MEM_ENCRYPT BIT_ULL(MSR_AMD64_SYSCFG_MEM_ENCRYPT_BIT) #define MSR_K8_INT_PENDING_MSG 0xc0010055 /* C1E active bits in int pending message */ #define K8_INTP_C1E_ACTIVE_MASK 0x18000000 diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 2d11384dc9ab..0adb0341cd7c 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -593,8 +593,8 @@ static void early_detect_mem_encrypt(struct cpuinfo_x86 *c) */ if (cpu_has(c, X86_FEATURE_SME) || cpu_has(c, X86_FEATURE_SEV)) { /* Check if memory encryption is enabled */ - rdmsrl(MSR_K8_SYSCFG, msr); - if (!(msr & MSR_K8_SYSCFG_MEM_ENCRYPT)) + rdmsrl(MSR_AMD64_SYSCFG, msr); + if (!(msr & MSR_AMD64_SYSCFG_MEM_ENCRYPT)) goto clear_all; /* diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c index 0c3b372318b7..b5f43049fa5f 100644 --- a/arch/x86/kernel/cpu/mtrr/cleanup.c +++ b/arch/x86/kernel/cpu/mtrr/cleanup.c @@ -836,7 +836,7 @@ int __init amd_special_default_mtrr(void) if (boot_cpu_data.x86 < 0xf) return 0; /* In case some hypervisor doesn't pass SYSCFG through: */ - if (rdmsr_safe(MSR_K8_SYSCFG, &l, &h) < 0) + if (rdmsr_safe(MSR_AMD64_SYSCFG, &l, &h) < 0) return 0; /* * Memory between 4GB and top of mem is forced WB by this magic bit. diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c index b90f3f437765..558108296f3c 100644 --- a/arch/x86/kernel/cpu/mtrr/generic.c +++ b/arch/x86/kernel/cpu/mtrr/generic.c @@ -53,13 +53,13 @@ static inline void k8_check_syscfg_dram_mod_en(void) (boot_cpu_data.x86 >= 0x0f))) return; - rdmsr(MSR_K8_SYSCFG, lo, hi); + rdmsr(MSR_AMD64_SYSCFG, lo, hi); if (lo & K8_MTRRFIXRANGE_DRAM_MODIFY) { pr_err(FW_WARN "MTRR: CPU %u: SYSCFG[MtrrFixDramModEn]" " not cleared by BIOS, clearing this bit\n", smp_processor_id()); lo &= ~K8_MTRRFIXRANGE_DRAM_MODIFY; - mtrr_wrmsr(MSR_K8_SYSCFG, lo, hi); + mtrr_wrmsr(MSR_AMD64_SYSCFG, lo, hi); } } diff --git a/arch/x86/kernel/mmconf-fam10h_64.c b/arch/x86/kernel/mmconf-fam10h_64.c index b5cb49e57df8..c94dec6a1834 100644 --- a/arch/x86/kernel/mmconf-fam10h_64.c +++ b/arch/x86/kernel/mmconf-fam10h_64.c @@ -95,7 +95,7 @@ static void get_fam10h_pci_mmconf_base(void) return; /* SYS_CFG */ - address = MSR_K8_SYSCFG; + address = MSR_AMD64_SYSCFG; rdmsrl(address, val); /* TOP_MEM2 is not enabled? */ diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index b649f92287a2..433e8e4fb3a6 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -858,8 +858,8 @@ static __init void svm_adjust_mmio_mask(void) return; /* If memory encryption is not enabled, use existing mask */ - rdmsrl(MSR_K8_SYSCFG, msr); - if (!(msr & MSR_K8_SYSCFG_MEM_ENCRYPT)) + rdmsrl(MSR_AMD64_SYSCFG, msr); + if (!(msr & MSR_AMD64_SYSCFG_MEM_ENCRYPT)) return; enc_bit = cpuid_ebx(0x8000001f) & 0x3f; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 6eda2834fc05..853c40e89335 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3402,7 +3402,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_IA32_LASTBRANCHTOIP: case MSR_IA32_LASTINTFROMIP: case MSR_IA32_LASTINTTOIP: - case MSR_K8_SYSCFG: + case MSR_AMD64_SYSCFG: case MSR_K8_TSEG_ADDR: case MSR_K8_TSEG_MASK: case MSR_VM_HSAVE_PA: diff --git a/arch/x86/mm/mem_encrypt_identity.c b/arch/x86/mm/mem_encrypt_identity.c index 04aba7e80a36..a9639f663d25 100644 --- a/arch/x86/mm/mem_encrypt_identity.c +++ b/arch/x86/mm/mem_encrypt_identity.c @@ -529,7 +529,7 @@ void __init sme_enable(struct boot_params *bp) /* * No SME if Hypervisor bit is set. This check is here to * prevent a guest from trying to enable SME. For running as a - * KVM guest the MSR_K8_SYSCFG will be sufficient, but there + * KVM guest the MSR_AMD64_SYSCFG will be sufficient, but there * might be other hypervisors which emulate that MSR as non-zero * or even pass it through to the guest. * A malicious hypervisor can still trick a guest into this @@ -542,8 +542,8 @@ void __init sme_enable(struct boot_params *bp) return; /* For SME, check the SYSCFG MSR */ - msr = __rdmsr(MSR_K8_SYSCFG); - if (!(msr & MSR_K8_SYSCFG_MEM_ENCRYPT)) + msr = __rdmsr(MSR_AMD64_SYSCFG); + if (!(msr & MSR_AMD64_SYSCFG_MEM_ENCRYPT)) return; } else { /* SEV state cannot be controlled by a command line option */ diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c index ae744b6a0785..dd40d3fea74e 100644 --- a/arch/x86/pci/amd_bus.c +++ b/arch/x86/pci/amd_bus.c @@ -284,7 +284,7 @@ static int __init early_root_info_init(void) /* need to take out [4G, TOM2) for RAM*/ /* SYS_CFG */ - address = MSR_K8_SYSCFG; + address = MSR_AMD64_SYSCFG; rdmsrl(address, val); /* TOP_MEM2 is enabled? */ if (val & (1<<21)) { diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S index 84c5d1b33d10..cc8391f86cdb 100644 --- a/arch/x86/realmode/rm/trampoline_64.S +++ b/arch/x86/realmode/rm/trampoline_64.S @@ -123,9 +123,9 @@ SYM_CODE_START(startup_32) */ btl $TH_FLAGS_SME_ACTIVE_BIT, pa_tr_flags jnc .Ldone - movl $MSR_K8_SYSCFG, %ecx + movl $MSR_AMD64_SYSCFG, %ecx rdmsr - bts $MSR_K8_SYSCFG_MEM_ENCRYPT_BIT, %eax + bts $MSR_AMD64_SYSCFG_MEM_ENCRYPT_BIT, %eax jc .Ldone /* diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 9fa4dfc6ebee..f0d8f60acee1 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -3083,7 +3083,7 @@ static void read_mc_regs(struct amd64_pvt *pvt) edac_dbg(0, " TOP_MEM: 0x%016llx\n", pvt->top_mem); /* Check first whether TOP_MEM2 is enabled: */ - rdmsrl(MSR_K8_SYSCFG, msr_val); + rdmsrl(MSR_AMD64_SYSCFG, msr_val); if (msr_val & BIT(21)) { rdmsrl(MSR_K8_TOP_MEM2, pvt->top_mem2); edac_dbg(0, " TOP_MEM2: 0x%016llx\n", pvt->top_mem2); diff --git a/tools/arch/x86/include/asm/msr-index.h b/tools/arch/x86/include/asm/msr-index.h index 45029354e0a8..c60b09e7602f 100644 --- a/tools/arch/x86/include/asm/msr-index.h +++ b/tools/arch/x86/include/asm/msr-index.h @@ -533,9 +533,9 @@ /* K8 MSRs */ #define MSR_K8_TOP_MEM1 0xc001001a #define MSR_K8_TOP_MEM2 0xc001001d -#define MSR_K8_SYSCFG 0xc0010010 -#define MSR_K8_SYSCFG_MEM_ENCRYPT_BIT 23 -#define MSR_K8_SYSCFG_MEM_ENCRYPT BIT_ULL(MSR_K8_SYSCFG_MEM_ENCRYPT_BIT) +#define MSR_AMD64_SYSCFG 0xc0010010 +#define MSR_AMD64_SYSCFG_MEM_ENCRYPT_BIT 23 +#define MSR_AMD64_SYSCFG_MEM_ENCRYPT BIT_ULL(MSR_AMD64_SYSCFG_MEM_ENCRYPT_BIT) #define MSR_K8_INT_PENDING_MSG 0xc0010055 /* C1E active bits in int pending message */ #define K8_INTP_C1E_ACTIVE_MASK 0x18000000 -- cgit v1.3.1 From 00c8b0b1e6e1314bb57aab6438fbc2803c637d9d Mon Sep 17 00:00:00 2001 From: Bartosz Dudziak Date: Sun, 2 May 2021 13:53:03 +0200 Subject: regulator: qcom: Document PM8226 smd regulator Document the PM8226 SMD-RPM regulator entry. Signed-off-by: Bartosz Dudziak Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210502115304.8570-1-bartosz.dudziak@snejp.pl Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml index a35c6cb9bf97..83b53579f463 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml @@ -24,6 +24,10 @@ description: For mp5496, s2 + For pm8226, s1, s2, s3, s4, s5, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, + l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, + l26, l27, l28, lvs1 + For pm8841, s1, s2, s3, s4, s5, s6, s7, s8 For pm8916, s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, @@ -68,6 +72,7 @@ properties: compatible: enum: - qcom,rpm-mp5496-regulators + - qcom,rpm-pm8226-regulators - qcom,rpm-pm8841-regulators - qcom,rpm-pm8916-regulators - qcom,rpm-pm8941-regulators -- cgit v1.3.1 From 029d32a892a860017d33ff8d9598259731e776ad Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 May 2021 13:52:59 +0200 Subject: spi: dw-apb-ssi: Integrate Renesas RZ/N1 SPI controller Originally, the Renesas RZ/N1 SPI Controller DT bindings were not integrated in the main DT bindings for the Synopsys DesignWare Synchronous Serial Interface, but in its own file, as the RZ/N1 controller has additional registers for software CS control and DMA. As so far DMA is not supported on RZ/N1, and json-schema can handle any possible differences fine, integrate the RZ/N1 compatible values in the main DT bindings for the Synopsys DW SSI. Signed-off-by: Geert Uytterhoeven Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/aef15aa119ed02487ded4691141678bc1040c3b4.1620301936.git.geert+renesas@glider.be Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/renesas,rzn1-spi.txt | 11 ----------- Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml | 6 ++++++ 2 files changed, 6 insertions(+), 11 deletions(-) delete mode 100644 Documentation/devicetree/bindings/spi/renesas,rzn1-spi.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/renesas,rzn1-spi.txt b/Documentation/devicetree/bindings/spi/renesas,rzn1-spi.txt deleted file mode 100644 index fb1a6728638d..000000000000 --- a/Documentation/devicetree/bindings/spi/renesas,rzn1-spi.txt +++ /dev/null @@ -1,11 +0,0 @@ -Renesas RZ/N1 SPI Controller - -This controller is based on the Synopsys DW Synchronous Serial Interface and -inherits all properties defined in snps,dw-apb-ssi.txt except for the -compatible property. - -Required properties: -- compatible : The device specific string followed by the generic RZ/N1 string. - Therefore it must be one of: - "renesas,r9a06g032-spi", "renesas,rzn1-spi" - "renesas,r9a06g033-spi", "renesas,rzn1-spi" diff --git a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml index 4825157cd92e..ca91201a9926 100644 --- a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml +++ b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml @@ -67,6 +67,12 @@ properties: const: baikal,bt1-sys-ssi - description: Canaan Kendryte K210 SoS SPI Controller const: canaan,k210-spi + - description: Renesas RZ/N1 SPI Controller + items: + - enum: + - renesas,r9a06g032-spi # RZ/N1D + - renesas,r9a06g033-spi # RZ/N1S + - const: renesas,rzn1-spi # RZ/N1 reg: minItems: 1 -- cgit v1.3.1 From 6c05cdbb9ef1de0264cac9135f6e90dad1e8763f Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 25 Apr 2021 12:32:53 -0300 Subject: usb: Restore the reference to ch9.h Keep the textual reference to ch9.h as it was prior to commit caa93d9bd2d7 ("usb: Fix up movement of USB core kerneldoc location"). As linux/usb/ch9.h does not contain comments anymore, explain that drivers/usb/common/common.c includes such header and provides declarations of a few utilities routines for manipulating the data types from ch9.h. Also mention that drivers/usb/common/debug.c contains some functions for creating debug output. Fixes: caa93d9bd2d7 ("usb: Fix up movement of USB core kerneldoc location") Reported-by: Alan Stern Suggested-by: Alan Stern Acked-by: Alan Stern Signed-off-by: Fabio Estevam Link: https://lore.kernel.org/r/20210425153253.2542816-1-festevam@gmail.com Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/usb/usb.rst | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/driver-api/usb/usb.rst b/Documentation/driver-api/usb/usb.rst index 543e70434da2..820e867af45a 100644 --- a/Documentation/driver-api/usb/usb.rst +++ b/Documentation/driver-api/usb/usb.rst @@ -109,16 +109,19 @@ well as to make sure they aren't relying on some HCD-specific behavior. USB-Standard Types ================== -In ``drivers/usb/common/common.c`` and ``drivers/usb/common/debug.c`` you -will find the USB data types defined in chapter 9 of the USB specification. -These data types are used throughout USB, and in APIs including this host -side API, gadget APIs, usb character devices and debugfs interfaces. +In ``include/uapi/linux/usb/ch9.h`` you will find the USB data types defined +in chapter 9 of the USB specification. These data types are used throughout +USB, and in APIs including this host side API, gadget APIs, usb character +devices and debugfs interfaces. That file is itself included by +``include/linux/usb/ch9.h``, which also contains declarations of a few +utility routines for manipulating these data types; the implementations +are in ``drivers/usb/common/common.c``. .. kernel-doc:: drivers/usb/common/common.c :export: -.. kernel-doc:: drivers/usb/common/debug.c - :export: +In addition, some functions useful for creating debugging output are +defined in ``drivers/usb/common/debug.c``. Host-Side Data Types and Macros =============================== -- cgit v1.3.1 From f75297853470627c4ee4e2b80eed40af7441c96b Mon Sep 17 00:00:00 2001 From: Wei Ming Chen Date: Thu, 6 May 2021 20:20:20 +0800 Subject: docs: usb: function: Modify path name Original path does not exists, so changed to "Documentation/ABI/testing/configfs-usb-gadget" Signed-off-by: Wei Ming Chen Link: https://lore.kernel.org/r/20210506122020.7117-1-jj251510319013@gmail.com Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/gadget_configfs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/usb/gadget_configfs.rst b/Documentation/usb/gadget_configfs.rst index 158e48dab586..e4566ffb223f 100644 --- a/Documentation/usb/gadget_configfs.rst +++ b/Documentation/usb/gadget_configfs.rst @@ -140,7 +140,7 @@ is an arbitrary string allowed in a filesystem, e.g.:: Each function provides its specific set of attributes, with either read-only or read-write access. Where applicable they need to be written to as appropriate. -Please refer to Documentation/ABI/*/configfs-usb-gadget* for more information. +Please refer to Documentation/ABI/testing/configfs-usb-gadget for more information. 4. Associating the functions with their configurations ------------------------------------------------------ -- cgit v1.3.1 From 5311221304fa60e357aada75efdf2f2da8c30a57 Mon Sep 17 00:00:00 2001 From: Wan Jiabing Date: Thu, 6 May 2021 19:49:39 +0800 Subject: dt-bindings: phy: cadence-torrent: update reference file of docs In commit fd7abc3c5b87 ("phy: cadence-torrent: Use a common header file for Cadence SERDES"), phy-cadence-torrent.h was renamed to phy-cadence.h. Fix it of the Documentation. Signed-off-by: Wan Jiabing Link: https://lore.kernel.org/r/20210506114940.22215-1-wanjiabing@vivo.com Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml index 01dcd14e7b2a..320a232c7208 100644 --- a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml +++ b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml @@ -118,7 +118,7 @@ patternProperties: description: Specifies the Spread Spectrum Clocking mode used. It can be NO_SSC, EXTERNAL_SSC or INTERNAL_SSC. - Refer include/dt-bindings/phy/phy-cadence-torrent.h for the constants to be used. + Refer include/dt-bindings/phy/phy-cadence.h for the constants to be used. $ref: /schemas/types.yaml#/definitions/uint32 enum: [0, 1, 2] default: 0 -- cgit v1.3.1 From bf9e262fcfa6350269f00a95658f701f2595db13 Mon Sep 17 00:00:00 2001 From: Wan Jiabing Date: Sat, 8 May 2021 11:07:33 +0800 Subject: docs/zh_CN: Remove obsolete translation file This translation file was replaced by Documentation/translations/zh_CN/admin-guide/security-bugs.rst which was created in commit 2d153571003b ("docs/zh_CN: Add zh_CN/admin-guide/security-bugs.rst"). This is a translation left over from history. Remove it. Signed-off-by: Wan Jiabing Acked-by: Wu XiangCheng Link: https://lore.kernel.org/r/20210508030741.82655-1-wanjiabing@vivo.com Signed-off-by: Jonathan Corbet --- Documentation/translations/zh_CN/SecurityBugs | 50 --------------------------- 1 file changed, 50 deletions(-) delete mode 100644 Documentation/translations/zh_CN/SecurityBugs (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/SecurityBugs b/Documentation/translations/zh_CN/SecurityBugs deleted file mode 100644 index 2d0fffd122ce..000000000000 --- a/Documentation/translations/zh_CN/SecurityBugs +++ /dev/null @@ -1,50 +0,0 @@ -Chinese translated version of Documentation/admin-guide/security-bugs.rst - -If you have any comment or update to the content, please contact the -original document maintainer directly. However, if you have a problem -communicating in English you can also ask the Chinese maintainer for -help. Contact the Chinese maintainer if this translation is outdated -or if there is a problem with the translation. - -Chinese maintainer: Harry Wei ---------------------------------------------------------------------- -Documentation/admin-guide/security-bugs.rst 的中文翻译 - -如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文 -交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 -译存在问题,请联系中文版维护者。 - -中文版维护者: 贾威威 Harry Wei -中文版翻译者: 贾威威 Harry Wei -中文版校译者: 贾威威 Harry Wei - - -以下为正文 ---------------------------------------------------------------------- -Linux内核开发者认为安全非常重要。因此,我们想要知道当一个有关于 -安全的漏洞被发现的时候,并且它可能会被尽快的修复或者公开。请把这个安全 -漏洞报告给Linux内核安全团队。 - -1) 联系 - -linux内核安全团队可以通过email来联系。这是 -一组独立的安全工作人员,可以帮助改善漏洞报告并且公布和取消一个修复。安 -全团队有可能会从部分的维护者那里引进额外的帮助来了解并且修复安全漏洞。 -当遇到任何漏洞,所能提供的信息越多就越能诊断和修复。如果你不清楚什么 -是有帮助的信息,那就请重温一下admin-guide/reporting-bugs.rst文件中的概述过程。任 -何攻击性的代码都是非常有用的,未经报告者的同意不会被取消,除非它已经 -被公布于众。 - -2) 公开 - -Linux内核安全团队的宗旨就是和漏洞提交者一起处理漏洞的解决方案直 -到公开。我们喜欢尽快地完全公开漏洞。当一个漏洞或者修复还没有被完全地理 -解,解决方案没有通过测试或者供应商协调,可以合理地延迟公开。然而,我们 -期望这些延迟尽可能的短些,是可数的几天,而不是几个星期或者几个月。公开 -日期是通过安全团队和漏洞提供者以及供应商洽谈后的结果。公开时间表是从很 -短(特殊的,它已经被公众所知道)到几个星期。作为一个基本的默认政策,我 -们所期望通知公众的日期是7天的安排。 - -3) 保密协议 - -Linux内核安全团队不是一个正式的团体,因此不能加入任何的保密协议。 -- cgit v1.3.1 From 9e255e2b9afe948fb795cbaa854acc3904d4212c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 6 May 2021 16:19:07 -0700 Subject: Documentation: drop optional BOMs A few of the Documentation .rst files begin with a Unicode byte order mark (BOM). The BOM may signify endianess for 16-bit or 32-bit encodings or indicate that the text stream is indeed Unicode. We don't need it for either of those uses. It may also interfere with (confuse) some software. Since we don't need it and its use is optional, just delete the uses of it in Documentation/. https://en.wikipedia.org/wiki/Byte_order_mark Signed-off-by: Randy Dunlap Reviewed-by: Matthew Wilcox (Oracle) Reviewed-by: Greg Kroah-Hartman Cc: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210506231907.14359-1-rdunlap@infradead.org Signed-off-by: Jonathan Corbet --- Documentation/block/data-integrity.rst | 2 +- Documentation/process/kernel-enforcement-statement.rst | 2 +- Documentation/security/tpm/xen-tpmfront.rst | 2 +- Documentation/timers/no_hz.rst | 2 +- Documentation/usb/mtouchusb.rst | 2 +- Documentation/usb/usb-serial.rst | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/block/data-integrity.rst b/Documentation/block/data-integrity.rst index 4f2452a95c43..07a97aa26668 100644 --- a/Documentation/block/data-integrity.rst +++ b/Documentation/block/data-integrity.rst @@ -1,4 +1,4 @@ -============== +============== Data Integrity ============== diff --git a/Documentation/process/kernel-enforcement-statement.rst b/Documentation/process/kernel-enforcement-statement.rst index e5a1be476047..dc2d813b2e79 100644 --- a/Documentation/process/kernel-enforcement-statement.rst +++ b/Documentation/process/kernel-enforcement-statement.rst @@ -1,4 +1,4 @@ -.. _process_statement_kernel: +.. _process_statement_kernel: Linux Kernel Enforcement Statement ---------------------------------- diff --git a/Documentation/security/tpm/xen-tpmfront.rst b/Documentation/security/tpm/xen-tpmfront.rst index 00d5b1db227d..31c67522f2ad 100644 --- a/Documentation/security/tpm/xen-tpmfront.rst +++ b/Documentation/security/tpm/xen-tpmfront.rst @@ -1,4 +1,4 @@ -============================= +============================= Virtual TPM interface for Xen ============================= diff --git a/Documentation/timers/no_hz.rst b/Documentation/timers/no_hz.rst index c4c70e1aada3..6cadad7c3aad 100644 --- a/Documentation/timers/no_hz.rst +++ b/Documentation/timers/no_hz.rst @@ -1,4 +1,4 @@ -====================================== +====================================== NO_HZ: Reducing Scheduling-Clock Ticks ====================================== diff --git a/Documentation/usb/mtouchusb.rst b/Documentation/usb/mtouchusb.rst index d1111b74bf75..5ae1f74fe74b 100644 --- a/Documentation/usb/mtouchusb.rst +++ b/Documentation/usb/mtouchusb.rst @@ -1,4 +1,4 @@ -================ +================ mtouchusb driver ================ diff --git a/Documentation/usb/usb-serial.rst b/Documentation/usb/usb-serial.rst index 8fa7dbd3da9a..69586aeb60bb 100644 --- a/Documentation/usb/usb-serial.rst +++ b/Documentation/usb/usb-serial.rst @@ -1,4 +1,4 @@ -========== +========== USB serial ========== -- cgit v1.3.1 From 1b55767dfdd93c42712e67e986ac14f0c4debd0c Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Tue, 11 May 2021 00:25:05 +0800 Subject: erofs: fix broken illustration in documentation Illustration was broken after ReST conversion by accident. (checked by 'make SPHINXDIRS="filesystems" htmldocs') Link: https://lore.kernel.org/r/20210510162506.28637-1-xiang@kernel.org Fixes: e66d8631ddb3 ("docs: filesystems: convert erofs.txt to ReST") Reviewed-by: Chao Yu Cc: Mauro Carvalho Chehab Signed-off-by: Gao Xiang --- Documentation/filesystems/erofs.rst | 119 ++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 60 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/erofs.rst b/Documentation/filesystems/erofs.rst index bf145171c2bf..869b183ff215 100644 --- a/Documentation/filesystems/erofs.rst +++ b/Documentation/filesystems/erofs.rst @@ -113,31 +113,31 @@ may not. All metadatas can be now observed in two different spaces (views): :: - |-> aligned with 8B - |-> followed closely - + meta_blkaddr blocks |-> another slot - _____________________________________________________________________ - | ... | inode | xattrs | extents | data inline | ... | inode ... - |________|_______|(optional)|(optional)|__(optional)_|_____|__________ - |-> aligned with the inode slot size - . . - . . - . . - . . - . . - . . - .____________________________________________________|-> aligned with 4B - | xattr_ibody_header | shared xattrs | inline xattrs | - |____________________|_______________|_______________| - |-> 12 bytes <-|->x * 4 bytes<-| . - . . . - . . . - . . . - ._______________________________.______________________. - | id | id | id | id | ... | id | ent | ... | ent| ... | - |____|____|____|____|______|____|_____|_____|____|_____| - |-> aligned with 4B - |-> aligned with 4B + |-> aligned with 8B + |-> followed closely + + meta_blkaddr blocks |-> another slot + _____________________________________________________________________ + | ... | inode | xattrs | extents | data inline | ... | inode ... + |________|_______|(optional)|(optional)|__(optional)_|_____|__________ + |-> aligned with the inode slot size + . . + . . + . . + . . + . . + . . + .____________________________________________________|-> aligned with 4B + | xattr_ibody_header | shared xattrs | inline xattrs | + |____________________|_______________|_______________| + |-> 12 bytes <-|->x * 4 bytes<-| . + . . . + . . . + . . . + ._______________________________.______________________. + | id | id | id | id | ... | id | ent | ... | ent| ... | + |____|____|____|____|______|____|_____|_____|____|_____| + |-> aligned with 4B + |-> aligned with 4B Inode could be 32 or 64 bytes, which can be distinguished from a common field which all inode versions have -- i_format:: @@ -175,13 +175,13 @@ may not. All metadatas can be now observed in two different spaces (views): Each share xattr can also be directly found by the following formula: xattr offset = xattr_blkaddr * block_size + 4 * xattr_id - :: +:: - |-> aligned by 4 bytes - + xattr_blkaddr blocks |-> aligned with 4 bytes - _________________________________________________________________________ - | ... | xattr_entry | xattr data | ... | xattr_entry | xattr data ... - |________|_____________|_____________|_____|______________|_______________ + |-> aligned by 4 bytes + + xattr_blkaddr blocks |-> aligned with 4 bytes + _________________________________________________________________________ + | ... | xattr_entry | xattr data | ... | xattr_entry | xattr data ... + |________|_____________|_____________|_____|______________|_______________ Directories ----------- @@ -193,19 +193,18 @@ algorithm (could refer to the related source code). :: - ___________________________ - / | - / ______________|________________ - / / | nameoff1 | nameoffN-1 - ____________.______________._______________v________________v__________ - | dirent | dirent | ... | dirent | filename | filename | ... | filename | - |___.0___|____1___|_____|___N-1__|____0_____|____1_____|_____|___N-1____| - \ ^ - \ | * could have - \ | trailing '\0' - \________________________| nameoff0 - - Directory block + ___________________________ + / | + / ______________|________________ + / / | nameoff1 | nameoffN-1 + ____________.______________._______________v________________v__________ + | dirent | dirent | ... | dirent | filename | filename | ... | filename | + |___.0___|____1___|_____|___N-1__|____0_____|____1_____|_____|___N-1____| + \ ^ + \ | * could have + \ | trailing '\0' + \________________________| nameoff0 + Directory block Note that apart from the offset of the first filename, nameoff0 also indicates the total number of directory entries in this block since it is no need to @@ -216,22 +215,22 @@ Compression Currently, EROFS supports 4KB fixed-sized output transparent file compression, as illustrated below:: - |---- Variant-Length Extent ----|-------- VLE --------|----- VLE ----- - clusterofs clusterofs clusterofs - | | | logical data - _________v_______________________________v_____________________v_______________ - ... | . | | . | | . | ... - ____|____.________|_____________|________.____|_____________|__.__________|____ - |-> cluster <-|-> cluster <-|-> cluster <-|-> cluster <-|-> cluster <-| - size size size size size - . . . . - . . . . - . . . . - _______._____________._____________._____________._____________________ - ... | | | | ... physical data - _______|_____________|_____________|_____________|_____________________ - |-> cluster <-|-> cluster <-|-> cluster <-| - size size size + |<- variable-sized extent ->|<- VLE ->| + clusterofs clusterofs clusterofs + | | | + _________v_________________________________v_______________________v________ + ... | . | | . | | . ... + ____|____._________|______________|________.___ _|______________|__.________ + |-> lcluster <-|-> lcluster <-|-> lcluster <-|-> lcluster <-| + size size size size . . + . . . . + . . . . + . . . . + _______.______________.______________.______________._________________ + ... | | | | ... + _______|______________|______________|______________|_________________ + |-> pcluster <-|-> pcluster <-|-> pcluster <-| + size size size Currently each on-disk physical cluster can contain 4KB (un)compressed data at most. For each logical cluster, there is a corresponding on-disk index to -- cgit v1.3.1 From 46f2e04484aee056c97f79162da83ac7d2d621bb Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Tue, 11 May 2021 16:44:14 +0800 Subject: erofs: update documentation about data compression Add more description about (NON)HEAD lclusters, and the new big pcluster feature. Link: https://lore.kernel.org/r/20210511084414.21305-1-xiang@kernel.org Reviewed-by: Chao Yu Signed-off-by: Gao Xiang --- Documentation/filesystems/erofs.rst | 68 ++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 19 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/erofs.rst b/Documentation/filesystems/erofs.rst index 869b183ff215..832839fcf4c3 100644 --- a/Documentation/filesystems/erofs.rst +++ b/Documentation/filesystems/erofs.rst @@ -50,8 +50,8 @@ Here is the main features of EROFS: - Support POSIX.1e ACLs by using xattrs; - - Support transparent file compression as an option: - LZ4 algorithm with 4 KB fixed-sized output compression for high performance. + - Support transparent data compression as an option: + LZ4 algorithm with the fixed-sized output compression for high performance. The following git tree provides the file system user-space tools under development (ex, formatting tool mkfs.erofs): @@ -210,10 +210,21 @@ Note that apart from the offset of the first filename, nameoff0 also indicates the total number of directory entries in this block since it is no need to introduce another on-disk field at all. -Compression ------------ -Currently, EROFS supports 4KB fixed-sized output transparent file compression, -as illustrated below:: +Data compression +---------------- +EROFS implements LZ4 fixed-sized output compression which generates fixed-sized +compressed data blocks from variable-sized input in contrast to other existing +fixed-sized input solutions. Relatively higher compression ratios can be gotten +by using fixed-sized output compression since nowadays popular data compression +algorithms are mostly LZ77-based and such fixed-sized output approach can be +benefited from the historical dictionary (aka. sliding window). + +In details, original (uncompressed) data is turned into several variable-sized +extents and in the meanwhile, compressed into physical clusters (pclusters). +In order to record each variable-sized extent, logical clusters (lclusters) are +introduced as the basic unit of compress indexes to indicate whether a new +extent is generated within the range (HEAD) or not (NONHEAD). Lclusters are now +fixed in block size, as illustrated below:: |<- variable-sized extent ->|<- VLE ->| clusterofs clusterofs clusterofs @@ -222,18 +233,37 @@ as illustrated below:: ... | . | | . | | . ... ____|____._________|______________|________.___ _|______________|__.________ |-> lcluster <-|-> lcluster <-|-> lcluster <-|-> lcluster <-| - size size size size . . - . . . . - . . . . - . . . . - _______.______________.______________.______________._________________ + (HEAD) (NONHEAD) (HEAD) (NONHEAD) . + . CBLKCNT . . + . . . + . . . + _______._____________________________.______________._________________ ... | | | | ... _______|______________|______________|______________|_________________ - |-> pcluster <-|-> pcluster <-|-> pcluster <-| - size size size - -Currently each on-disk physical cluster can contain 4KB (un)compressed data -at most. For each logical cluster, there is a corresponding on-disk index to -describe its cluster type, physical cluster address, etc. - -See "struct z_erofs_vle_decompressed_index" in erofs_fs.h for more details. + |-> big pcluster <-|-> pcluster <-| + +A physical cluster can be seen as a container of physical compressed blocks +which contains compressed data. Previously, only lcluster-sized (4KB) pclusters +were supported. After big pcluster feature is introduced (available since +Linux v5.13), pcluster can be a multiple of lcluster size. + +For each HEAD lcluster, clusterofs is recorded to indicate where a new extent +starts and blkaddr is used to seek the compressed data. For each NONHEAD +lcluster, delta0 and delta1 are available instead of blkaddr to indicate the +distance to its HEAD lcluster and the next HEAD lcluster. A PLAIN lcluster is +also a HEAD lcluster except that its data is uncompressed. See the comments +around "struct z_erofs_vle_decompressed_index" in erofs_fs.h for more details. + +If big pcluster is enabled, pcluster size in lclusters needs to be recorded as +well. Let the delta0 of the first NONHEAD lcluster store the compressed block +count with a special flag as a new called CBLKCNT NONHEAD lcluster. It's easy +to understand its delta0 is constantly 1, as illustrated below:: + + __________________________________________________________ + | HEAD | NONHEAD | NONHEAD | ... | NONHEAD | HEAD | HEAD | + |__:___|_(CBLKCNT)_|_________|_____|_________|__:___|____:_| + |<----- a big pcluster (with CBLKCNT) ------>|<-- -->| + a lcluster-sized pcluster (without CBLKCNT) ^ + +If another HEAD follows a HEAD lcluster, there is no room to record CBLKCNT, +but it's easy to know the size of such pcluster is 1 lcluster as well. -- cgit v1.3.1 From 918d9c77791cc8267b5b5ab556c868dfa57e0d93 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 11 May 2021 17:01:28 +0200 Subject: docs: cdrom-standard.rst: get rid of uneeded UTF-8 chars This file was converted from a LaTeX one. The conversion used some UTF-8 characters at the literal blocks. Replace them by normal ASCII characters. Signed-off-by: Mauro Carvalho Chehab Acked-by: Jens Axboe Link: https://lore.kernel.org/r/79c3f482da17ea48d69b6e6ad1b7fb102b9dd7bf.1620744606.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/cdrom/cdrom-standard.rst | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cdrom/cdrom-standard.rst b/Documentation/cdrom/cdrom-standard.rst index 70500b189cc8..5845960ca382 100644 --- a/Documentation/cdrom/cdrom-standard.rst +++ b/Documentation/cdrom/cdrom-standard.rst @@ -146,18 +146,18 @@ with the kernel as a block device by registering the following general *struct file_operations*:: struct file_operations cdrom_fops = { - NULL, /∗ lseek ∗/ - block _read , /∗ read—general block-dev read ∗/ - block _write, /∗ write—general block-dev write ∗/ - NULL, /∗ readdir ∗/ - NULL, /∗ select ∗/ - cdrom_ioctl, /∗ ioctl ∗/ - NULL, /∗ mmap ∗/ - cdrom_open, /∗ open ∗/ - cdrom_release, /∗ release ∗/ - NULL, /∗ fsync ∗/ - NULL, /∗ fasync ∗/ - NULL /∗ revalidate ∗/ + NULL, /* lseek */ + block _read , /* read--general block-dev read */ + block _write, /* write--general block-dev write */ + NULL, /* readdir */ + NULL, /* select */ + cdrom_ioctl, /* ioctl */ + NULL, /* mmap */ + cdrom_open, /* open */ + cdrom_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL /* revalidate */ }; Every active CD-ROM device shares this *struct*. The routines @@ -250,12 +250,12 @@ The drive-specific, minor-like information that is registered with `cdrom.c`, currently contains the following fields:: struct cdrom_device_info { - const struct cdrom_device_ops * ops; /* device operations for this major */ + const struct cdrom_device_ops * ops; /* device operations for this major */ struct list_head list; /* linked list of all device_info */ struct gendisk * disk; /* matching block layer disk */ void * handle; /* driver-dependent data */ - int mask; /* mask of capability: disables them */ + int mask; /* mask of capability: disables them */ int speed; /* maximum speed for reading data */ int capacity; /* number of discs in a jukebox */ @@ -569,7 +569,7 @@ the *CDC_CLOSE_TRAY* bit in *mask*. In the file `cdrom.c` you will encounter many constructions of the type:: - if (cdo->capability & ∼cdi->mask & CDC _⟨capability⟩) ... + if (cdo->capability & ~cdi->mask & CDC _) ... There is no *ioctl* to set the mask... The reason is that I think it is better to control the **behavior** rather than the -- cgit v1.3.1 From 8d3926c09e043448d4d26896b8225943f12d0933 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 11 May 2021 17:01:29 +0200 Subject: docs: ABI: remove a meaningless UTF-8 character MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Those two files have this character: - U+00ac ('¬'): NOT SIGN at the end of the first line, apparently for no reason. Drop them. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/6cd3f0b47568fecb7889fd18d1d744c3aaf73866.1620744606.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/ABI/obsolete/sysfs-kernel-fadump_registered | 2 +- Documentation/ABI/obsolete/sysfs-kernel-fadump_release_mem | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/obsolete/sysfs-kernel-fadump_registered b/Documentation/ABI/obsolete/sysfs-kernel-fadump_registered index 0360be39c98e..dae880b1a5d5 100644 --- a/Documentation/ABI/obsolete/sysfs-kernel-fadump_registered +++ b/Documentation/ABI/obsolete/sysfs-kernel-fadump_registered @@ -1,4 +1,4 @@ -This ABI is renamed and moved to a new location /sys/kernel/fadump/registered.¬ +This ABI is renamed and moved to a new location /sys/kernel/fadump/registered. What: /sys/kernel/fadump_registered Date: Feb 2012 diff --git a/Documentation/ABI/obsolete/sysfs-kernel-fadump_release_mem b/Documentation/ABI/obsolete/sysfs-kernel-fadump_release_mem index 6ce0b129ab12..ca2396edb5f1 100644 --- a/Documentation/ABI/obsolete/sysfs-kernel-fadump_release_mem +++ b/Documentation/ABI/obsolete/sysfs-kernel-fadump_release_mem @@ -1,4 +1,4 @@ -This ABI is renamed and moved to a new location /sys/kernel/fadump/release_mem.¬ +This ABI is renamed and moved to a new location /sys/kernel/fadump/release_mem. What: /sys/kernel/fadump_release_mem Date: Feb 2012 -- cgit v1.3.1 From 6f3bceba03b4f18e0b83261e2fb761e0ad5da625 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 11 May 2021 17:01:30 +0200 Subject: docs: ABI: remove some spurious characters The KernelVersion tag contains some spurious UTF-8 characters for no reason. Drop them. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/6d774ad6cb3795a177309503a39f8f1b5e309d64.1620744606.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/ABI/testing/sysfs-module | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-module b/Documentation/ABI/testing/sysfs-module index a485434d2a0f..88bddf192ceb 100644 --- a/Documentation/ABI/testing/sysfs-module +++ b/Documentation/ABI/testing/sysfs-module @@ -37,13 +37,13 @@ Description: Maximum time allowed for periodic transfers per microframe (μs) What: /sys/module/*/{coresize,initsize} Date: Jan 2012 -KernelVersion:»·3.3 +KernelVersion: 3.3 Contact: Kay Sievers Description: Module size in bytes. What: /sys/module/*/taint Date: Jan 2012 -KernelVersion:»·3.3 +KernelVersion: 3.3 Contact: Kay Sievers Description: Module taint flags: == ===================== -- cgit v1.3.1 From d1f2722d5357d7a5138b1be8bd64946f0a14c81e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 11 May 2021 17:01:31 +0200 Subject: docs: hwmon: tmp103.rst: fix bad usage of UTF-8 chars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While UTF-8 characters can be used at the Linux documentation, the best is to use them only when ASCII doesn't offer a good replacement. So, replace the occurences of the following UTF-8 characters: - U+2013 ('–'): EN DASH In this specific case, EN DASH was used instead of a minus sign. So, replace it by a single hyphen. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/73b3c7c1eef5c12ddc941624d23689313bd56529.1620744606.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/hwmon/tmp103.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/tmp103.rst b/Documentation/hwmon/tmp103.rst index e195a7d14309..b3ef81475cf8 100644 --- a/Documentation/hwmon/tmp103.rst +++ b/Documentation/hwmon/tmp103.rst @@ -21,10 +21,10 @@ Description The TMP103 is a digital output temperature sensor in a four-ball wafer chip-scale package (WCSP). The TMP103 is capable of reading temperatures to a resolution of 1°C. The TMP103 is specified for -operation over a temperature range of –40°C to +125°C. +operation over a temperature range of -40°C to +125°C. Resolution: 8 Bits -Accuracy: ±1°C Typ (–10°C to +100°C) +Accuracy: ±1°C Typ (-10°C to +100°C) The driver provides the common sysfs-interface for temperatures (see Documentation/hwmon/sysfs-interface.rst under Temperatures). -- cgit v1.3.1 From 5e716ec68b4a75a84e28c0efa68db613deb64981 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 11 May 2021 17:01:32 +0200 Subject: docs: networking: device_drivers: fix bad usage of UTF-8 chars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Probably because the original file was pre-processed by some tool, both i40e.rst and iavf.rst files are using this character: - U+2013 ('–'): EN DASH meaning an hyphen when calling a command line application, which is obviously wrong. So, replace them by an hyphen, ensuring that it will be properly displayed as literals when building the documentation. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/95eb2a48d0ca3528780ce0dfce64359977fa8cb3.1620744606.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/networking/device_drivers/ethernet/intel/i40e.rst | 4 ++-- Documentation/networking/device_drivers/ethernet/intel/iavf.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/device_drivers/ethernet/intel/i40e.rst b/Documentation/networking/device_drivers/ethernet/intel/i40e.rst index 8a9b18573688..2d3f6bd969a2 100644 --- a/Documentation/networking/device_drivers/ethernet/intel/i40e.rst +++ b/Documentation/networking/device_drivers/ethernet/intel/i40e.rst @@ -173,7 +173,7 @@ Director rule is added from ethtool (Sideband filter), ATR is turned off by the driver. To re-enable ATR, the sideband can be disabled with the ethtool -K option. For example:: - ethtool –K [adapter] ntuple [off|on] + ethtool -K [adapter] ntuple [off|on] If sideband is re-enabled after ATR is re-enabled, ATR remains enabled until a TCP-IP flow is added. When all TCP-IP sideband rules are deleted, ATR is @@ -688,7 +688,7 @@ shaper bw_rlimit: for each tc, sets minimum and maximum bandwidth rates. Totals must be equal or less than port speed. For example: min_rate 1Gbit 3Gbit: Verify bandwidth limit using network -monitoring tools such as ifstat or sar –n DEV [interval] [number of samples] +monitoring tools such as `ifstat` or `sar -n DEV [interval] [number of samples]` 2. Enable HW TC offload on interface:: diff --git a/Documentation/networking/device_drivers/ethernet/intel/iavf.rst b/Documentation/networking/device_drivers/ethernet/intel/iavf.rst index 52e037b11c97..25330b7b5168 100644 --- a/Documentation/networking/device_drivers/ethernet/intel/iavf.rst +++ b/Documentation/networking/device_drivers/ethernet/intel/iavf.rst @@ -179,7 +179,7 @@ shaper bw_rlimit: for each tc, sets minimum and maximum bandwidth rates. Totals must be equal or less than port speed. For example: min_rate 1Gbit 3Gbit: Verify bandwidth limit using network -monitoring tools such as ifstat or sar –n DEV [interval] [number of samples] +monitoring tools such as ``ifstat`` or ``sar -n DEV [interval] [number of samples]`` NOTE: Setting up channels via ethtool (ethtool -L) is not supported when the -- cgit v1.3.1 From 7240cd200541543008a7ce4fcaf2ba5a5556128f Mon Sep 17 00:00:00 2001 From: Desmond Cheong Zhi Xi Date: Tue, 11 May 2021 09:49:37 -0400 Subject: Remove link to nonexistent rocket driver docs The rocket driver and documentation were removed in this commit, but the corresponding entry in index.rst was not removed. Signed-off-by: Desmond Cheong Zhi Xi Fixes: 3b00b6af7a5b ("tty: rocket, remove the driver") Link: https://lore.kernel.org/r/20210511134937.2442291-1-desmondcheongzx@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/driver-api/serial/index.rst | 1 - 1 file changed, 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/driver-api/serial/index.rst b/Documentation/driver-api/serial/index.rst index 21351b8c95a4..8f7d7af3b90b 100644 --- a/Documentation/driver-api/serial/index.rst +++ b/Documentation/driver-api/serial/index.rst @@ -19,7 +19,6 @@ Serial drivers moxa-smartio n_gsm - rocket serial-iso7816 serial-rs485 -- cgit v1.3.1 From 0bd50826a40e012a35c58ed3576b3873643e7a7d Mon Sep 17 00:00:00 2001 From: Wan Jiabing Date: Thu, 6 May 2021 15:08:24 +0800 Subject: leds: Fix reference file name of documentation In commit 56b01acc1c79a ("dt-bindings: gpio: fairchild,74hc595: Convert to json-schema"), gpio-74x164.txt was deleted and replaced by fairchild,74hc595.yaml. Fix the reference file name. Signed-off-by: Wan Jiabing Acked-by: Pavel Machek Link: https://lore.kernel.org/r/20210506070824.10965-1-wanjiabing@vivo.com Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/leds/leds-bcm6328.txt | 4 ++-- Documentation/devicetree/bindings/leds/leds-bcm6358.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/leds/leds-bcm6328.txt b/Documentation/devicetree/bindings/leds/leds-bcm6328.txt index ccebce597f37..a555d94084b7 100644 --- a/Documentation/devicetree/bindings/leds/leds-bcm6328.txt +++ b/Documentation/devicetree/bindings/leds/leds-bcm6328.txt @@ -4,8 +4,8 @@ This controller is present on BCM6318, BCM6328, BCM6362 and BCM63268. In these SoCs it's possible to control LEDs both as GPIOs or by hardware. However, on some devices there are Serial LEDs (LEDs connected to a 74x164 controller), which can either be controlled by software (exporting the 74x164 -as spi-gpio. See Documentation/devicetree/bindings/gpio/gpio-74x164.txt), or -by hardware using this driver. +as spi-gpio. See Documentation/devicetree/bindings/gpio/fairchild,74hc595.yaml), +or by hardware using this driver. Some of these Serial LEDs are hardware controlled (e.g. ethernet LEDs) and exporting the 74x164 as spi-gpio prevents those LEDs to be hardware controlled, so the only chance to keep them working is by using this driver. diff --git a/Documentation/devicetree/bindings/leds/leds-bcm6358.txt b/Documentation/devicetree/bindings/leds/leds-bcm6358.txt index da5708e7b43b..6e51c6b91ee5 100644 --- a/Documentation/devicetree/bindings/leds/leds-bcm6358.txt +++ b/Documentation/devicetree/bindings/leds/leds-bcm6358.txt @@ -3,7 +3,7 @@ LEDs connected to Broadcom BCM6358 controller This controller is present on BCM6358 and BCM6368. In these SoCs there are Serial LEDs (LEDs connected to a 74x164 controller), which can either be controlled by software (exporting the 74x164 as spi-gpio. -See Documentation/devicetree/bindings/gpio/gpio-74x164.txt), or +See Documentation/devicetree/bindings/gpio/fairchild,74hc595.yaml), or by hardware using this driver. Required properties: -- cgit v1.3.1 From 08389d888287c3823f80b0216766b71e17f0aba5 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 11 May 2021 22:35:17 +0200 Subject: bpf: Add kconfig knob for disabling unpriv bpf by default Add a kconfig knob which allows for unprivileged bpf to be disabled by default. If set, the knob sets /proc/sys/kernel/unprivileged_bpf_disabled to value of 2. This still allows a transition of 2 -> {0,1} through an admin. Similarly, this also still keeps 1 -> {1} behavior intact, so that once set to permanently disabled, it cannot be undone aside from a reboot. We've also added extra2 with max of 2 for the procfs handler, so that an admin still has a chance to toggle between 0 <-> 2. Either way, as an additional alternative, applications can make use of CAP_BPF that we added a while ago. Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/74ec548079189e4e4dffaeb42b8987bb3c852eee.1620765074.git.daniel@iogearbox.net --- Documentation/admin-guide/sysctl/kernel.rst | 17 ++++++++++++++--- kernel/bpf/Kconfig | 10 ++++++++++ kernel/bpf/syscall.c | 3 ++- kernel/sysctl.c | 29 ++++++++++++++++++++++++----- 4 files changed, 50 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst index 1d56a6b73a4e..24ab20d7a50a 100644 --- a/Documentation/admin-guide/sysctl/kernel.rst +++ b/Documentation/admin-guide/sysctl/kernel.rst @@ -1457,11 +1457,22 @@ unprivileged_bpf_disabled ========================= Writing 1 to this entry will disable unprivileged calls to ``bpf()``; -once disabled, calling ``bpf()`` without ``CAP_SYS_ADMIN`` will return -``-EPERM``. +once disabled, calling ``bpf()`` without ``CAP_SYS_ADMIN`` or ``CAP_BPF`` +will return ``-EPERM``. Once set to 1, this can't be cleared from the +running kernel anymore. -Once set, this can't be cleared. +Writing 2 to this entry will also disable unprivileged calls to ``bpf()``, +however, an admin can still change this setting later on, if needed, by +writing 0 or 1 to this entry. +If ``BPF_UNPRIV_DEFAULT_OFF`` is enabled in the kernel config, then this +entry will default to 2 instead of 0. + += ============================================================= +0 Unprivileged calls to ``bpf()`` are enabled +1 Unprivileged calls to ``bpf()`` are disabled without recovery +2 Unprivileged calls to ``bpf()`` are disabled += ============================================================= watchdog ======== diff --git a/kernel/bpf/Kconfig b/kernel/bpf/Kconfig index b4edaefc6255..26b591e23f16 100644 --- a/kernel/bpf/Kconfig +++ b/kernel/bpf/Kconfig @@ -61,6 +61,16 @@ config BPF_JIT_DEFAULT_ON def_bool ARCH_WANT_DEFAULT_BPF_JIT || BPF_JIT_ALWAYS_ON depends on HAVE_EBPF_JIT && BPF_JIT +config BPF_UNPRIV_DEFAULT_OFF + bool "Disable unprivileged BPF by default" + depends on BPF_SYSCALL + help + Disables unprivileged BPF by default by setting the corresponding + /proc/sys/kernel/unprivileged_bpf_disabled knob to 2. An admin can + still reenable it by setting it to 0 later on, or permanently + disable it by setting it to 1 (from which no other transition to + 0 is possible anymore). + source "kernel/bpf/preload/Kconfig" config BPF_LSM diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 941ca06d9dfa..ea04b0deb5ce 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -50,7 +50,8 @@ static DEFINE_SPINLOCK(map_idr_lock); static DEFINE_IDR(link_idr); static DEFINE_SPINLOCK(link_idr_lock); -int sysctl_unprivileged_bpf_disabled __read_mostly; +int sysctl_unprivileged_bpf_disabled __read_mostly = + IS_BUILTIN(CONFIG_BPF_UNPRIV_DEFAULT_OFF) ? 2 : 0; static const struct bpf_map_ops * const bpf_map_types[] = { #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index f91d327273c1..6df7c81f7cdd 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -225,7 +225,27 @@ static int bpf_stats_handler(struct ctl_table *table, int write, mutex_unlock(&bpf_stats_enabled_mutex); return ret; } -#endif + +static int bpf_unpriv_handler(struct ctl_table *table, int write, + void *buffer, size_t *lenp, loff_t *ppos) +{ + int ret, unpriv_enable = *(int *)table->data; + bool locked_state = unpriv_enable == 1; + struct ctl_table tmp = *table; + + if (write && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + tmp.data = &unpriv_enable; + ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); + if (write && !ret) { + if (locked_state && unpriv_enable != 1) + return -EPERM; + *(int *)table->data = unpriv_enable; + } + return ret; +} +#endif /* CONFIG_BPF_SYSCALL && CONFIG_SYSCTL */ /* * /proc/sys support @@ -2600,10 +2620,9 @@ static struct ctl_table kern_table[] = { .data = &sysctl_unprivileged_bpf_disabled, .maxlen = sizeof(sysctl_unprivileged_bpf_disabled), .mode = 0644, - /* only handle a transition from default "0" to "1" */ - .proc_handler = proc_dointvec_minmax, - .extra1 = SYSCTL_ONE, - .extra2 = SYSCTL_ONE, + .proc_handler = bpf_unpriv_handler, + .extra1 = SYSCTL_ZERO, + .extra2 = &two, }, { .procname = "bpf_stats_enabled", -- cgit v1.3.1 From e4042ad492357fa995921376462b04a025dd53b6 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 4 May 2021 22:43:32 +0200 Subject: delayacct: Default disabled Assuming this stuff isn't actually used much; disable it by default and avoid allocating and tracking the task_delay_info structure. taskstats is changed to still report the regular sched and sched_info and only skip the missing task_delay_info fields instead of not reporting anything. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Thomas Gleixner Reviewed-by: Ingo Molnar Link: https://lkml.kernel.org/r/20210505111525.308018373@infradead.org --- Documentation/accounting/delay-accounting.rst | 8 ++++---- Documentation/admin-guide/kernel-parameters.txt | 2 +- include/linux/delayacct.h | 16 ++++------------ kernel/delayacct.c | 19 +++++++++++-------- 4 files changed, 20 insertions(+), 25 deletions(-) (limited to 'Documentation') diff --git a/Documentation/accounting/delay-accounting.rst b/Documentation/accounting/delay-accounting.rst index 7cc7f5852da0..f20b282d6de0 100644 --- a/Documentation/accounting/delay-accounting.rst +++ b/Documentation/accounting/delay-accounting.rst @@ -69,13 +69,13 @@ Compile the kernel with:: CONFIG_TASK_DELAY_ACCT=y CONFIG_TASKSTATS=y -Delay accounting is enabled by default at boot up. -To disable, add:: +Delay accounting is disabled by default at boot up. +To enable, add:: - nodelayacct + delayacct to the kernel boot options. The rest of the instructions -below assume this has not been done. +below assume this has been done. After the system has booted up, use a utility similar to getdelays.c to access the delays diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index cb89dbdedc46..ef5048c127a3 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3244,7 +3244,7 @@ noclflush [BUGS=X86] Don't use the CLFLUSH instruction - nodelayacct [KNL] Disable per-task delay accounting + delayacct [KNL] Enable per-task delay accounting nodsp [SH] Disable hardware DSP at boot time. diff --git a/include/linux/delayacct.h b/include/linux/delayacct.h index 57fefa54b53a..225c8e01a111 100644 --- a/include/linux/delayacct.h +++ b/include/linux/delayacct.h @@ -61,7 +61,7 @@ struct task_delay_info { #include #ifdef CONFIG_TASK_DELAY_ACCT -DECLARE_STATIC_KEY_TRUE(delayacct_key); +DECLARE_STATIC_KEY_FALSE(delayacct_key); extern int delayacct_on; /* Delay accounting turned on/off */ extern struct kmem_cache *delayacct_cache; extern void delayacct_init(void); @@ -69,7 +69,7 @@ extern void __delayacct_tsk_init(struct task_struct *); extern void __delayacct_tsk_exit(struct task_struct *); extern void __delayacct_blkio_start(void); extern void __delayacct_blkio_end(struct task_struct *); -extern int __delayacct_add_tsk(struct taskstats *, struct task_struct *); +extern int delayacct_add_tsk(struct taskstats *, struct task_struct *); extern __u64 __delayacct_blkio_ticks(struct task_struct *); extern void __delayacct_freepages_start(void); extern void __delayacct_freepages_end(void); @@ -116,7 +116,7 @@ static inline void delayacct_tsk_free(struct task_struct *tsk) static inline void delayacct_blkio_start(void) { - if (!static_branch_likely(&delayacct_key)) + if (!static_branch_unlikely(&delayacct_key)) return; delayacct_set_flag(current, DELAYACCT_PF_BLKIO); @@ -126,7 +126,7 @@ static inline void delayacct_blkio_start(void) static inline void delayacct_blkio_end(struct task_struct *p) { - if (!static_branch_likely(&delayacct_key)) + if (!static_branch_unlikely(&delayacct_key)) return; if (p->delays) @@ -134,14 +134,6 @@ static inline void delayacct_blkio_end(struct task_struct *p) delayacct_clear_flag(p, DELAYACCT_PF_BLKIO); } -static inline int delayacct_add_tsk(struct taskstats *d, - struct task_struct *tsk) -{ - if (!delayacct_on || !tsk->delays) - return 0; - return __delayacct_add_tsk(d, tsk); -} - static inline __u64 delayacct_blkio_ticks(struct task_struct *tsk) { if (tsk->delays) diff --git a/kernel/delayacct.c b/kernel/delayacct.c index 63012fd39ae2..3f086903b295 100644 --- a/kernel/delayacct.c +++ b/kernel/delayacct.c @@ -14,23 +14,23 @@ #include #include -DEFINE_STATIC_KEY_TRUE(delayacct_key); -int delayacct_on __read_mostly = 1; /* Delay accounting turned on/off */ +DEFINE_STATIC_KEY_FALSE(delayacct_key); +int delayacct_on __read_mostly; /* Delay accounting turned on/off */ struct kmem_cache *delayacct_cache; -static int __init delayacct_setup_disable(char *str) +static int __init delayacct_setup_enable(char *str) { - delayacct_on = 0; + delayacct_on = 1; return 1; } -__setup("nodelayacct", delayacct_setup_disable); +__setup("delayacct", delayacct_setup_enable); void delayacct_init(void) { delayacct_cache = KMEM_CACHE(task_delay_info, SLAB_PANIC|SLAB_ACCOUNT); delayacct_tsk_init(&init_task); - if (!delayacct_on) - static_branch_disable(&delayacct_key); + if (delayacct_on) + static_branch_enable(&delayacct_key); } void __delayacct_tsk_init(struct task_struct *tsk) @@ -83,7 +83,7 @@ void __delayacct_blkio_end(struct task_struct *p) delayacct_end(&delays->lock, &delays->blkio_start, total, count); } -int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) +int delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) { u64 utime, stime, stimescaled, utimescaled; unsigned long long t2, t3; @@ -118,6 +118,9 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) d->cpu_run_virtual_total = (tmp < (s64)d->cpu_run_virtual_total) ? 0 : tmp; + if (!tsk->delays) + return 0; + /* zero XXX_total, non-zero XXX_count implies XXX stat overflowed */ raw_spin_lock_irqsave(&tsk->delays->lock, flags); -- cgit v1.3.1 From 0cd7c741f01de13dc1eecf22557593b3514639bb Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 10 May 2021 14:01:00 +0200 Subject: delayacct: Add sysctl to enable at runtime Just like sched_schedstats, allow runtime enabling (and disabling) of delayacct. This is useful if one forgot to add the delayacct boot time option. Signed-off-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r/YJkhebGJAywaZowX@hirez.programming.kicks-ass.net --- Documentation/accounting/delay-accounting.rst | 6 +++-- include/linux/delayacct.h | 4 +++ kernel/delayacct.c | 36 +++++++++++++++++++++++++-- kernel/sysctl.c | 12 +++++++++ 4 files changed, 54 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/accounting/delay-accounting.rst b/Documentation/accounting/delay-accounting.rst index f20b282d6de0..1b8b46deeb29 100644 --- a/Documentation/accounting/delay-accounting.rst +++ b/Documentation/accounting/delay-accounting.rst @@ -74,8 +74,10 @@ To enable, add:: delayacct -to the kernel boot options. The rest of the instructions -below assume this has been done. +to the kernel boot options. The rest of the instructions below assume this has +been done. Alternatively, use sysctl kernel.task_delayacct to switch the state +at runtime. Note however that only tasks started after enabling it will have +delayacct information. After the system has booted up, use a utility similar to getdelays.c to access the delays diff --git a/include/linux/delayacct.h b/include/linux/delayacct.h index 225c8e01a111..af7e6eb50283 100644 --- a/include/linux/delayacct.h +++ b/include/linux/delayacct.h @@ -65,6 +65,10 @@ DECLARE_STATIC_KEY_FALSE(delayacct_key); extern int delayacct_on; /* Delay accounting turned on/off */ extern struct kmem_cache *delayacct_cache; extern void delayacct_init(void); + +extern int sysctl_delayacct(struct ctl_table *table, int write, void *buffer, + size_t *lenp, loff_t *ppos); + extern void __delayacct_tsk_init(struct task_struct *); extern void __delayacct_tsk_exit(struct task_struct *); extern void __delayacct_blkio_start(void); diff --git a/kernel/delayacct.c b/kernel/delayacct.c index 3f086903b295..51530d5b15a8 100644 --- a/kernel/delayacct.c +++ b/kernel/delayacct.c @@ -18,6 +18,17 @@ DEFINE_STATIC_KEY_FALSE(delayacct_key); int delayacct_on __read_mostly; /* Delay accounting turned on/off */ struct kmem_cache *delayacct_cache; +static void set_delayacct(bool enabled) +{ + if (enabled) { + static_branch_enable(&delayacct_key); + delayacct_on = 1; + } else { + delayacct_on = 0; + static_branch_disable(&delayacct_key); + } +} + static int __init delayacct_setup_enable(char *str) { delayacct_on = 1; @@ -29,9 +40,30 @@ void delayacct_init(void) { delayacct_cache = KMEM_CACHE(task_delay_info, SLAB_PANIC|SLAB_ACCOUNT); delayacct_tsk_init(&init_task); - if (delayacct_on) - static_branch_enable(&delayacct_key); + set_delayacct(delayacct_on); +} + +#ifdef CONFIG_PROC_SYSCTL +int sysctl_delayacct(struct ctl_table *table, int write, void *buffer, + size_t *lenp, loff_t *ppos) +{ + int state = delayacct_on; + struct ctl_table t; + int err; + + if (write && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + t = *table; + t.data = &state; + err = proc_dointvec_minmax(&t, write, buffer, lenp, ppos); + if (err < 0) + return err; + if (write) + set_delayacct(state); + return err; } +#endif void __delayacct_tsk_init(struct task_struct *tsk) { diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 14edf84cc571..0afbfc83157a 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -71,6 +71,7 @@ #include #include #include +#include #include "../lib/kstrtox.h" @@ -1727,6 +1728,17 @@ static struct ctl_table kern_table[] = { .extra2 = SYSCTL_ONE, }, #endif /* CONFIG_SCHEDSTATS */ +#ifdef CONFIG_TASK_DELAY_ACCT + { + .procname = "task_delayacct", + .data = NULL, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = sysctl_delayacct, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, +#endif /* CONFIG_TASK_DELAY_ACCT */ #ifdef CONFIG_NUMA_BALANCING { .procname = "numa_balancing", -- cgit v1.3.1 From 3dd4fe4b4dfa34e7487edfe159ef787ba397cfa9 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 21 Apr 2021 00:05:28 -0700 Subject: MAINTAINERS: Move nvdimm mailing list After seeing some users have subscription management trouble, more spam than other Linux development lists, and considering some of the benefits of kernel.org hosted lists, nvdimm and persistent memory development is moving to nvdimm@lists.linux.dev. The old list will remain up until v5.14-rc1 and shutdown thereafter. Cc: Ira Weiny Cc: Oliver O'Halloran Cc: Matthew Wilcox Cc: Jan Kara Cc: Jonathan Corbet Cc: Dave Jiang Cc: Vishal Verma Link: https://lore.kernel.org/r/161898872871.3406469.4054282559340528393.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- Documentation/ABI/obsolete/sysfs-class-dax | 2 +- Documentation/ABI/removed/sysfs-bus-nfit | 2 +- Documentation/ABI/testing/sysfs-bus-nfit | 40 +++++++++++++-------------- Documentation/ABI/testing/sysfs-bus-papr-pmem | 4 +-- Documentation/driver-api/nvdimm/nvdimm.rst | 2 +- MAINTAINERS | 14 +++++----- 6 files changed, 32 insertions(+), 32 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/obsolete/sysfs-class-dax b/Documentation/ABI/obsolete/sysfs-class-dax index 0faf1354cd05..5bcce27458e3 100644 --- a/Documentation/ABI/obsolete/sysfs-class-dax +++ b/Documentation/ABI/obsolete/sysfs-class-dax @@ -1,7 +1,7 @@ What: /sys/class/dax/ Date: May, 2016 KernelVersion: v4.7 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: Device DAX is the device-centric analogue of Filesystem DAX (CONFIG_FS_DAX). It allows memory ranges to be allocated and mapped without need of an intervening file diff --git a/Documentation/ABI/removed/sysfs-bus-nfit b/Documentation/ABI/removed/sysfs-bus-nfit index ae8c1ca53828..277437005def 100644 --- a/Documentation/ABI/removed/sysfs-bus-nfit +++ b/Documentation/ABI/removed/sysfs-bus-nfit @@ -1,7 +1,7 @@ What: /sys/bus/nd/devices/regionX/nfit/ecc_unit_size Date: Aug, 2017 KernelVersion: v4.14 (Removed v4.18) -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) Size of a write request to a DIMM that will not incur a read-modify-write cycle at the memory controller. diff --git a/Documentation/ABI/testing/sysfs-bus-nfit b/Documentation/ABI/testing/sysfs-bus-nfit index 63ef0b9ecce7..e7282d184a74 100644 --- a/Documentation/ABI/testing/sysfs-bus-nfit +++ b/Documentation/ABI/testing/sysfs-bus-nfit @@ -5,7 +5,7 @@ Interface Table (NFIT)' section in the ACPI specification What: /sys/bus/nd/devices/nmemX/nfit/serial Date: Jun, 2015 KernelVersion: v4.2 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) Serial number of the NVDIMM (non-volatile dual in-line memory module), assigned by the module vendor. @@ -14,7 +14,7 @@ Description: What: /sys/bus/nd/devices/nmemX/nfit/handle Date: Apr, 2015 KernelVersion: v4.2 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) The address (given by the _ADR object) of the device on its parent bus of the NVDIMM device containing the NVDIMM region. @@ -23,7 +23,7 @@ Description: What: /sys/bus/nd/devices/nmemX/nfit/device Date: Apr, 2015 KernelVersion: v4.1 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) Device id for the NVDIMM, assigned by the module vendor. @@ -31,7 +31,7 @@ Description: What: /sys/bus/nd/devices/nmemX/nfit/rev_id Date: Jun, 2015 KernelVersion: v4.2 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) Revision of the NVDIMM, assigned by the module vendor. @@ -39,7 +39,7 @@ Description: What: /sys/bus/nd/devices/nmemX/nfit/phys_id Date: Apr, 2015 KernelVersion: v4.2 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) Handle (i.e., instance number) for the SMBIOS (system management BIOS) Memory Device structure describing the NVDIMM @@ -49,7 +49,7 @@ Description: What: /sys/bus/nd/devices/nmemX/nfit/flags Date: Jun, 2015 KernelVersion: v4.2 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) The flags in the NFIT memory device sub-structure indicate the state of the data on the nvdimm relative to its energy @@ -68,7 +68,7 @@ What: /sys/bus/nd/devices/nmemX/nfit/format1 What: /sys/bus/nd/devices/nmemX/nfit/formats Date: Apr, 2016 KernelVersion: v4.7 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) The interface codes indicate support for persistent memory mapped directly into system physical address space and / or a @@ -84,7 +84,7 @@ Description: What: /sys/bus/nd/devices/nmemX/nfit/vendor Date: Apr, 2016 KernelVersion: v4.7 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) Vendor id of the NVDIMM. @@ -92,7 +92,7 @@ Description: What: /sys/bus/nd/devices/nmemX/nfit/dsm_mask Date: May, 2016 KernelVersion: v4.7 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) The bitmask indicates the supported device specific control functions relative to the NVDIMM command family supported by the @@ -102,7 +102,7 @@ Description: What: /sys/bus/nd/devices/nmemX/nfit/family Date: Apr, 2016 KernelVersion: v4.7 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) Displays the NVDIMM family command sets. Values 0, 1, 2 and 3 correspond to NVDIMM_FAMILY_INTEL, @@ -118,7 +118,7 @@ Description: What: /sys/bus/nd/devices/nmemX/nfit/id Date: Apr, 2016 KernelVersion: v4.7 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) ACPI specification 6.2 section 5.2.25.9, defines an identifier for an NVDIMM, which refelects the id attribute. @@ -127,7 +127,7 @@ Description: What: /sys/bus/nd/devices/nmemX/nfit/subsystem_vendor Date: Apr, 2016 KernelVersion: v4.7 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) Sub-system vendor id of the NVDIMM non-volatile memory subsystem controller. @@ -136,7 +136,7 @@ Description: What: /sys/bus/nd/devices/nmemX/nfit/subsystem_rev_id Date: Apr, 2016 KernelVersion: v4.7 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) Sub-system revision id of the NVDIMM non-volatile memory subsystem controller, assigned by the non-volatile memory subsystem @@ -146,7 +146,7 @@ Description: What: /sys/bus/nd/devices/nmemX/nfit/subsystem_device Date: Apr, 2016 KernelVersion: v4.7 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) Sub-system device id for the NVDIMM non-volatile memory subsystem controller, assigned by the non-volatile memory @@ -156,7 +156,7 @@ Description: What: /sys/bus/nd/devices/ndbusX/nfit/revision Date: Jun, 2015 KernelVersion: v4.2 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) ACPI NFIT table revision number. @@ -164,7 +164,7 @@ Description: What: /sys/bus/nd/devices/ndbusX/nfit/scrub Date: Sep, 2016 KernelVersion: v4.9 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RW) This shows the number of full Address Range Scrubs (ARS) that have been completed since driver load time. Userspace can @@ -177,7 +177,7 @@ Description: What: /sys/bus/nd/devices/ndbusX/nfit/hw_error_scrub Date: Sep, 2016 KernelVersion: v4.9 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RW) Provides a way to toggle the behavior between just adding the address (cache line) where the MCE happened to the poison @@ -196,7 +196,7 @@ Description: What: /sys/bus/nd/devices/ndbusX/nfit/dsm_mask Date: Jun, 2017 KernelVersion: v4.13 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) The bitmask indicates the supported bus specific control functions. See the section named 'NVDIMM Root Device _DSMs' in @@ -205,7 +205,7 @@ Description: What: /sys/bus/nd/devices/ndbusX/nfit/firmware_activate_noidle Date: Apr, 2020 KernelVersion: v5.8 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RW) The Intel platform implementation of firmware activate support exposes an option let the platform force idle devices in @@ -225,7 +225,7 @@ Description: What: /sys/bus/nd/devices/regionX/nfit/range_index Date: Jun, 2015 KernelVersion: v4.2 -Contact: linux-nvdimm@lists.01.org +Contact: nvdimm@lists.linux.dev Description: (RO) A unique number provided by the BIOS to identify an address range. Used by NVDIMM Region Mapping Structure to uniquely refer diff --git a/Documentation/ABI/testing/sysfs-bus-papr-pmem b/Documentation/ABI/testing/sysfs-bus-papr-pmem index 8316c33862a0..92e2db0e2d3d 100644 --- a/Documentation/ABI/testing/sysfs-bus-papr-pmem +++ b/Documentation/ABI/testing/sysfs-bus-papr-pmem @@ -1,7 +1,7 @@ What: /sys/bus/nd/devices/nmemX/papr/flags Date: Apr, 2020 KernelVersion: v5.8 -Contact: linuxppc-dev , linux-nvdimm@lists.01.org, +Contact: linuxppc-dev , nvdimm@lists.linux.dev, Description: (RO) Report flags indicating various states of a papr-pmem NVDIMM device. Each flag maps to a one or @@ -36,7 +36,7 @@ Description: What: /sys/bus/nd/devices/nmemX/papr/perf_stats Date: May, 2020 KernelVersion: v5.9 -Contact: linuxppc-dev , linux-nvdimm@lists.01.org, +Contact: linuxppc-dev , nvdimm@lists.linux.dev, Description: (RO) Report various performance stats related to papr-scm NVDIMM device. Each stat is reported on a new line with each line diff --git a/Documentation/driver-api/nvdimm/nvdimm.rst b/Documentation/driver-api/nvdimm/nvdimm.rst index ef6d59e0978e..1d8302b89bd4 100644 --- a/Documentation/driver-api/nvdimm/nvdimm.rst +++ b/Documentation/driver-api/nvdimm/nvdimm.rst @@ -4,7 +4,7 @@ LIBNVDIMM: Non-Volatile Devices libnvdimm - kernel / libndctl - userspace helper library -linux-nvdimm@lists.01.org +nvdimm@lists.linux.dev Version 13 diff --git a/MAINTAINERS b/MAINTAINERS index bd7aff0c120f..6b5d489022ea 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5237,7 +5237,7 @@ DEVICE DIRECT ACCESS (DAX) M: Dan Williams M: Vishal Verma M: Dave Jiang -L: linux-nvdimm@lists.01.org +L: nvdimm@lists.linux.dev S: Supported F: drivers/dax/ @@ -7006,7 +7006,7 @@ M: Dan Williams R: Matthew Wilcox R: Jan Kara L: linux-fsdevel@vger.kernel.org -L: linux-nvdimm@lists.01.org +L: nvdimm@lists.linux.dev S: Supported F: fs/dax.c F: include/linux/dax.h @@ -10378,7 +10378,7 @@ LIBNVDIMM BLK: MMIO-APERTURE DRIVER M: Dan Williams M: Vishal Verma M: Dave Jiang -L: linux-nvdimm@lists.01.org +L: nvdimm@lists.linux.dev S: Supported Q: https://patchwork.kernel.org/project/linux-nvdimm/list/ P: Documentation/nvdimm/maintainer-entry-profile.rst @@ -10389,7 +10389,7 @@ LIBNVDIMM BTT: BLOCK TRANSLATION TABLE M: Vishal Verma M: Dan Williams M: Dave Jiang -L: linux-nvdimm@lists.01.org +L: nvdimm@lists.linux.dev S: Supported Q: https://patchwork.kernel.org/project/linux-nvdimm/list/ P: Documentation/nvdimm/maintainer-entry-profile.rst @@ -10399,7 +10399,7 @@ LIBNVDIMM PMEM: PERSISTENT MEMORY DRIVER M: Dan Williams M: Vishal Verma M: Dave Jiang -L: linux-nvdimm@lists.01.org +L: nvdimm@lists.linux.dev S: Supported Q: https://patchwork.kernel.org/project/linux-nvdimm/list/ P: Documentation/nvdimm/maintainer-entry-profile.rst @@ -10407,7 +10407,7 @@ F: drivers/nvdimm/pmem* LIBNVDIMM: DEVICETREE BINDINGS M: Oliver O'Halloran -L: linux-nvdimm@lists.01.org +L: nvdimm@lists.linux.dev S: Supported Q: https://patchwork.kernel.org/project/linux-nvdimm/list/ F: Documentation/devicetree/bindings/pmem/pmem-region.txt @@ -10418,7 +10418,7 @@ M: Dan Williams M: Vishal Verma M: Dave Jiang M: Ira Weiny -L: linux-nvdimm@lists.01.org +L: nvdimm@lists.linux.dev S: Supported Q: https://patchwork.kernel.org/project/linux-nvdimm/list/ P: Documentation/nvdimm/maintainer-entry-profile.rst -- cgit v1.3.1 From 3e42d1de020805ff3f7d854e1cff742d14e158f5 Mon Sep 17 00:00:00 2001 From: Carlos Bilbao Date: Thu, 13 May 2021 09:31:10 -0400 Subject: docs: typo fixes in Documentation/ABI/ Fix the following typos in the Documentation/ABI/ directory: - In file obsolete/sysfs-cpuidle, change "obselete" for "obsolete". - In file removed/sysfs-kernel-uids, change "propotional" for "proportional". - In directory stable/, fix the following words: "associtated" for "associated", "hexidecimal" for "hexadecimal", "vlue" for "value", "csed" for "caused" and "wrtie" for "write". This updates a total of five files. - In directory testing/, fix the following words: "subystem" for "subsystem", "isochrnous" for "isochronous", "Desctiptors" for "Descriptors", "picutre" for "picture", "capture" for "capture", "occured" for "ocurred", "connnected" for "connected","agressively" for "aggressively","manufacturee" for "manufacturer" and "transaction" for "transaction", "malformatted" for "incorrectly formated" ,"internel" for "internal", "writtento" for "written to", "specificed" for "specified", "beyound" for "beyond", "Symetric" for "Symmetric". This updates a total of eleven files. Signed-off-by: Carlos Bilbao Reviewed-by: Randy Dunlap Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/5710038.lOV4Wx5bFT@iron-maiden Signed-off-by: Jonathan Corbet --- Documentation/ABI/obsolete/sysfs-cpuidle | 2 +- Documentation/ABI/removed/sysfs-kernel-uids | 2 +- Documentation/ABI/stable/sysfs-bus-vmbus | 2 +- Documentation/ABI/stable/sysfs-bus-xen-backend | 2 +- Documentation/ABI/stable/sysfs-driver-dma-idxd | 2 +- Documentation/ABI/stable/sysfs-driver-mlxreg-io | 4 ++-- Documentation/ABI/testing/configfs-iio | 2 +- Documentation/ABI/testing/configfs-most | 8 ++++---- Documentation/ABI/testing/configfs-usb-gadget | 2 +- Documentation/ABI/testing/configfs-usb-gadget-uvc | 4 ++-- Documentation/ABI/testing/debugfs-driver-genwqe | 2 +- Documentation/ABI/testing/debugfs-driver-habanalabs | 2 +- Documentation/ABI/testing/sysfs-bus-fsi | 2 +- Documentation/ABI/testing/sysfs-bus-pci | 4 ++-- Documentation/ABI/testing/sysfs-devices-system-cpu | 10 +++++----- Documentation/ABI/testing/sysfs-driver-ufs | 4 ++-- Documentation/ABI/testing/sysfs-fs-f2fs | 2 +- 17 files changed, 28 insertions(+), 28 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/obsolete/sysfs-cpuidle b/Documentation/ABI/obsolete/sysfs-cpuidle index e398fb5e542f..972cc11d3434 100644 --- a/Documentation/ABI/obsolete/sysfs-cpuidle +++ b/Documentation/ABI/obsolete/sysfs-cpuidle @@ -6,4 +6,4 @@ Description: with the update that cpuidle governor can be changed at runtime in default, both current_governor and current_governor_ro co-exist under /sys/devices/system/cpu/cpuidle/ file, it's duplicate so make - current_governor_ro obselete. + current_governor_ro obsolete. diff --git a/Documentation/ABI/removed/sysfs-kernel-uids b/Documentation/ABI/removed/sysfs-kernel-uids index dc4463f190a7..85a90b86ce1e 100644 --- a/Documentation/ABI/removed/sysfs-kernel-uids +++ b/Documentation/ABI/removed/sysfs-kernel-uids @@ -5,7 +5,7 @@ Contact: Dhaval Giani Description: The /sys/kernel/uids//cpu_shares tunable is used to set the cpu bandwidth a user is allowed. This is a - propotional value. What that means is that if there + proportional value. What that means is that if there are two users logged in, each with an equal number of shares, then they will get equal CPU bandwidth. Another example would be, if User A has shares = 1024 and user diff --git a/Documentation/ABI/stable/sysfs-bus-vmbus b/Documentation/ABI/stable/sysfs-bus-vmbus index 42599d9fa161..3066feae1d8d 100644 --- a/Documentation/ABI/stable/sysfs-bus-vmbus +++ b/Documentation/ABI/stable/sysfs-bus-vmbus @@ -61,7 +61,7 @@ Date: September. 2017 KernelVersion: 4.14 Contact: Stephen Hemminger Description: Directory for per-channel information - NN is the VMBUS relid associtated with the channel. + NN is the VMBUS relid associated with the channel. What: /sys/bus/vmbus/devices//channels//cpu Date: September. 2017 diff --git a/Documentation/ABI/stable/sysfs-bus-xen-backend b/Documentation/ABI/stable/sysfs-bus-xen-backend index e8b60bd766f7..480a89edfa05 100644 --- a/Documentation/ABI/stable/sysfs-bus-xen-backend +++ b/Documentation/ABI/stable/sysfs-bus-xen-backend @@ -19,7 +19,7 @@ Date: April 2011 KernelVersion: 3.0 Contact: Konrad Rzeszutek Wilk Description: - The major:minor number (in hexidecimal) of the + The major:minor number (in hexadecimal) of the physical device providing the storage for this backend block device. diff --git a/Documentation/ABI/stable/sysfs-driver-dma-idxd b/Documentation/ABI/stable/sysfs-driver-dma-idxd index 55285c136cf0..d431e2d00472 100644 --- a/Documentation/ABI/stable/sysfs-driver-dma-idxd +++ b/Documentation/ABI/stable/sysfs-driver-dma-idxd @@ -173,7 +173,7 @@ What: /sys/bus/dsa/devices/wq./priority Date: Oct 25, 2019 KernelVersion: 5.6.0 Contact: dmaengine@vger.kernel.org -Description: The priority value of this work queue, it is a vlue relative to +Description: The priority value of this work queue, it is a value relative to other work queue in the same group to control quality of service for dispatching work from multiple workqueues in the same group. diff --git a/Documentation/ABI/stable/sysfs-driver-mlxreg-io b/Documentation/ABI/stable/sysfs-driver-mlxreg-io index fd9a8045bb0c..b2553df2e786 100644 --- a/Documentation/ABI/stable/sysfs-driver-mlxreg-io +++ b/Documentation/ABI/stable/sysfs-driver-mlxreg-io @@ -137,7 +137,7 @@ Contact: Vadim Pasternak Description: These files show the system reset cause, as following: COMEX thermal shutdown; wathchdog power off or reset was derived by one of the next components: COMEX, switch board or by Small Form - Factor mezzanine, reset requested from ASIC, reset cuased by BIOS + Factor mezzanine, reset requested from ASIC, reset caused by BIOS reload. Value 1 in file means this is reset cause, 0 - otherwise. Only one of the above causes could be 1 at the same time, representing only last reset cause. @@ -183,7 +183,7 @@ What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/vpd_wp Date: January 2020 KernelVersion: 5.6 Contact: Vadim Pasternak -Description: This file allows to overwrite system VPD hardware wrtie +Description: This file allows to overwrite system VPD hardware write protection when attribute is set 1. The file is read/write. diff --git a/Documentation/ABI/testing/configfs-iio b/Documentation/ABI/testing/configfs-iio index aebda53ec0f7..1637fcb50f56 100644 --- a/Documentation/ABI/testing/configfs-iio +++ b/Documentation/ABI/testing/configfs-iio @@ -31,4 +31,4 @@ Date: April 2016 KernelVersion: 4.7 Description: Dummy IIO devices directory. Creating a directory here will result - in creating a dummy IIO device in the IIO subystem. + in creating a dummy IIO device in the IIO subsystem. diff --git a/Documentation/ABI/testing/configfs-most b/Documentation/ABI/testing/configfs-most index bc6b8bd18da4..0a4b8649aa5a 100644 --- a/Documentation/ABI/testing/configfs-most +++ b/Documentation/ABI/testing/configfs-most @@ -20,7 +20,7 @@ Description: subbuffer_size configure the sub-buffer size for this channel - (needed for synchronous and isochrnous data) + (needed for synchronous and isochronous data) num_buffers @@ -75,7 +75,7 @@ Description: subbuffer_size configure the sub-buffer size for this channel - (needed for synchronous and isochrnous data) + (needed for synchronous and isochronous data) num_buffers @@ -130,7 +130,7 @@ Description: subbuffer_size configure the sub-buffer size for this channel - (needed for synchronous and isochrnous data) + (needed for synchronous and isochronous data) num_buffers @@ -196,7 +196,7 @@ Description: subbuffer_size configure the sub-buffer size for this channel - (needed for synchronous and isochrnous data) + (needed for synchronous and isochronous data) num_buffers diff --git a/Documentation/ABI/testing/configfs-usb-gadget b/Documentation/ABI/testing/configfs-usb-gadget index dc351e9af80a..b7943aa7e997 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget +++ b/Documentation/ABI/testing/configfs-usb-gadget @@ -137,7 +137,7 @@ Description: This group contains "OS String" extension handling attributes. ============= =============================================== - use flag turning "OS Desctiptors" support on/off + use flag turning "OS Descriptors" support on/off b_vendor_code one-byte value used for custom per-device and per-interface requests qw_sign an identifier to be reported as "OS String" diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc index ac5e11af79a8..889ed45be4ca 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uvc +++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc @@ -170,7 +170,7 @@ Description: Default color matching descriptors bMatrixCoefficients matrix used to compute luma and chroma values from the color primaries bTransferCharacteristics optoelectronic transfer - characteristic of the source picutre, + characteristic of the source picture, also called the gamma function bColorPrimaries color primaries and the reference white @@ -311,7 +311,7 @@ Description: Specific streaming header descriptors a hardware trigger interrupt event bTriggerSupport flag specifying if hardware triggering is supported - bStillCaptureMethod method of still image caputre + bStillCaptureMethod method of still image capture supported bTerminalLink id of the output terminal to which the video endpoint of this interface diff --git a/Documentation/ABI/testing/debugfs-driver-genwqe b/Documentation/ABI/testing/debugfs-driver-genwqe index 1c2f25674e8c..b45b016545d8 100644 --- a/Documentation/ABI/testing/debugfs-driver-genwqe +++ b/Documentation/ABI/testing/debugfs-driver-genwqe @@ -31,7 +31,7 @@ What: /sys/kernel/debug/genwqe/genwqe_card/prev_regs Date: Oct 2013 Contact: haver@linux.vnet.ibm.com Description: Dump of the error registers before the last reset of - the card occured. + the card occurred. Only available for PF. What: /sys/kernel/debug/genwqe/genwqe_card/prev_dbg_uid0 diff --git a/Documentation/ABI/testing/debugfs-driver-habanalabs b/Documentation/ABI/testing/debugfs-driver-habanalabs index c78fc9282876..e89c6351503c 100644 --- a/Documentation/ABI/testing/debugfs-driver-habanalabs +++ b/Documentation/ABI/testing/debugfs-driver-habanalabs @@ -153,7 +153,7 @@ KernelVersion: 5.1 Contact: ogabbay@kernel.org Description: Triggers an I2C transaction that is generated by the device's CPU. Writing to this file generates a write transaction while - reading from the file generates a read transcation + reading from the file generates a read transaction What: /sys/kernel/debug/habanalabs/hl/i2c_reg Date: Jan 2019 diff --git a/Documentation/ABI/testing/sysfs-bus-fsi b/Documentation/ABI/testing/sysfs-bus-fsi index d148214181a1..76e0caa0c2b3 100644 --- a/Documentation/ABI/testing/sysfs-bus-fsi +++ b/Documentation/ABI/testing/sysfs-bus-fsi @@ -12,7 +12,7 @@ KernelVersion: 4.12 Contact: linux-fsi@lists.ozlabs.org Description: Sends an FSI BREAK command on a master's communication - link to any connnected slaves. A BREAK resets connected + link to any connected slaves. A BREAK resets connected device's logic and preps it to receive further commands from the master. diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index ef00fada2efb..793cbb76cd25 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -139,8 +139,8 @@ Description: binary file containing the Vital Product Data for the device. It should follow the VPD format defined in PCI Specification 2.1 or 2.2, but users should consider - that some devices may have malformatted data. If the - underlying VPD has a writable section then the + that some devices may have incorrectly formatted data. + If the underlying VPD has a writable section then the corresponding section of this file will be writable. What: /sys/bus/pci/devices/.../virtfnN diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index fe13baa53c59..160b10c029c0 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -50,7 +50,7 @@ Description: Dynamic addition and removal of CPU's. This is not hotplug architecture specific. release: writes to this file dynamically remove a CPU from - the system. Information writtento the file to remove CPU's + the system. Information written to the file to remove CPU's is architecture specific. What: /sys/devices/system/cpu/cpu#/node @@ -97,7 +97,7 @@ Description: CPU topology files that describe a logical CPU's relationship corresponds to a physical socket number, but the actual value is architecture and platform dependent. - thread_siblings: internel kernel map of cpu#'s hardware + thread_siblings: internal kernel map of cpu#'s hardware threads within the same core as cpu# thread_siblings_list: human-readable list of cpu#'s hardware @@ -280,7 +280,7 @@ Description: Disable L3 cache indices on a processor with this functionality will return the currently disabled index for that node. There is one L3 structure per node, or per internal node on MCM machines. Writing a valid - index to one of these files will cause the specificed cache + index to one of these files will cause the specified cache index to be disabled. All AMD processors with L3 caches provide this functionality. @@ -295,7 +295,7 @@ Description: Processor frequency boosting control This switch controls the boost setting for the whole system. Boosting allows the CPU and the firmware to run at a frequency - beyound it's nominal limit. + beyond it's nominal limit. More details can be found in Documentation/admin-guide/pm/cpufreq.rst @@ -532,7 +532,7 @@ What: /sys/devices/system/cpu/smt /sys/devices/system/cpu/smt/control Date: June 2018 Contact: Linux kernel mailing list -Description: Control Symetric Multi Threading (SMT) +Description: Control Symmetric Multi Threading (SMT) active: Tells whether SMT is active (enabled and siblings online) diff --git a/Documentation/ABI/testing/sysfs-driver-ufs b/Documentation/ABI/testing/sysfs-driver-ufs index d1bc23cb6a9d..eaac6898f0c0 100644 --- a/Documentation/ABI/testing/sysfs-driver-ufs +++ b/Documentation/ABI/testing/sysfs-driver-ufs @@ -168,7 +168,7 @@ Description: This file shows the manufacturing date in BCD format. What: /sys/bus/platform/drivers/ufshcd/*/device_descriptor/manufacturer_id Date: February 2018 Contact: Stanislav Nijnikov -Description: This file shows the manufacturee ID. This is one of the +Description: This file shows the manufacturer ID. This is one of the UFS device descriptor parameters. The full information about the descriptor could be found at UFS specifications 2.1. @@ -521,7 +521,7 @@ Description: This file shows maximum VCC, VCCQ and VCCQ2 value for What: /sys/bus/platform/drivers/ufshcd/*/string_descriptors/manufacturer_name Date: February 2018 Contact: Stanislav Nijnikov -Description: This file contains a device manufactureer name string. +Description: This file contains a device manufacturer name string. The full information about the descriptor could be found at UFS specifications 2.1. diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 4849b8e84e42..5d9ae27bd462 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -238,7 +238,7 @@ Description: Shows current reserved blocks in system, it may be temporarily What: /sys/fs/f2fs//gc_urgent Date: August 2017 Contact: "Jaegeuk Kim" -Description: Do background GC agressively when set. When gc_urgent = 1, +Description: Do background GC aggressively when set. When gc_urgent = 1, background thread starts to do GC by given gc_urgent_sleep_time interval. When gc_urgent = 2, F2FS will lower the bar of checking idle in order to process outstanding discard commands -- cgit v1.3.1 From 1e886090cefe26113122a7d59a36a9aec492fef5 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Tue, 20 Apr 2021 14:06:38 +0200 Subject: docs: admin-guide: update description for kernel.hotplug sysctl It's been a few releases since this defaulted to /sbin/hotplug. Update the text, and include pointers to the two CONFIG_UEVENT_HELPER{,_PATH} config knobs whose help text could provide more info, but also hint that the user probably doesn't need to care at all. Fixes: 7934779a69f1 ("Driver-Core: disable /sbin/hotplug by default") Signed-off-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20210420120638.1104016-1-linux@rasmusvillemoes.dk Signed-off-by: Jonathan Corbet --- Documentation/admin-guide/sysctl/kernel.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst index 1d56a6b73a4e..c24f57f2c782 100644 --- a/Documentation/admin-guide/sysctl/kernel.rst +++ b/Documentation/admin-guide/sysctl/kernel.rst @@ -333,7 +333,12 @@ hotplug ======= Path for the hotplug policy agent. -Default value is "``/sbin/hotplug``". +Default value is ``CONFIG_UEVENT_HELPER_PATH``, which in turn defaults +to the empty string. + +This file only exists when ``CONFIG_UEVENT_HELPER`` is enabled. Most +modern systems rely exclusively on the netlink-based uevent source and +don't need this. hung_task_all_cpu_backtrace -- cgit v1.3.1 From 2c5ff2caa4f8164e93a9bf035af9a2ad87cad9f2 Mon Sep 17 00:00:00 2001 From: Wei Ming Chen Date: Thu, 6 May 2021 20:20:20 +0800 Subject: docs: usb: function: Modify path name Original path does not exists, so changed to "Documentation/ABI/testing/configfs-usb-gadget" Signed-off-by: Wei Ming Chen Link: https://lore.kernel.org/r/20210506122020.7117-1-jj251510319013@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/usb/gadget_configfs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/usb/gadget_configfs.rst b/Documentation/usb/gadget_configfs.rst index 158e48dab586..e4566ffb223f 100644 --- a/Documentation/usb/gadget_configfs.rst +++ b/Documentation/usb/gadget_configfs.rst @@ -140,7 +140,7 @@ is an arbitrary string allowed in a filesystem, e.g.:: Each function provides its specific set of attributes, with either read-only or read-write access. Where applicable they need to be written to as appropriate. -Please refer to Documentation/ABI/*/configfs-usb-gadget* for more information. +Please refer to Documentation/ABI/testing/configfs-usb-gadget for more information. 4. Associating the functions with their configurations ------------------------------------------------------ -- cgit v1.3.1 From f4d3f25aced3b493e57fd4109e2bc86f0831b23e Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 14 May 2021 17:27:36 -0700 Subject: docs: admin-guide: update description for kernel.modprobe sysctl When I added CONFIG_MODPROBE_PATH, I neglected to update Documentation/. It's still true that this defaults to /sbin/modprobe, but now via a level of indirection. So document that the kernel might have been built with something other than /sbin/modprobe as the initial value. Link: https://lkml.kernel.org/r/20210420125324.1246826-1-linux@rasmusvillemoes.dk Fixes: 17652f4240f7a ("modules: add CONFIG_MODPROBE_PATH") Signed-off-by: Rasmus Villemoes Cc: Jonathan Corbet Cc: Greg Kroah-Hartman Cc: Jessica Yu Cc: Luis Chamberlain Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/admin-guide/sysctl/kernel.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst index 1d56a6b73a4e..7ca8df5451d4 100644 --- a/Documentation/admin-guide/sysctl/kernel.rst +++ b/Documentation/admin-guide/sysctl/kernel.rst @@ -483,10 +483,11 @@ modprobe ======== The full path to the usermode helper for autoloading kernel modules, -by default "/sbin/modprobe". This binary is executed when the kernel -requests a module. For example, if userspace passes an unknown -filesystem type to mount(), then the kernel will automatically request -the corresponding filesystem module by executing this usermode helper. +by default ``CONFIG_MODPROBE_PATH``, which in turn defaults to +"/sbin/modprobe". This binary is executed when the kernel requests a +module. For example, if userspace passes an unknown filesystem type +to mount(), then the kernel will automatically request the +corresponding filesystem module by executing this usermode helper. This usermode helper should insert the needed module into the kernel. This sysctl only affects module autoloading. It has no effect on the -- cgit v1.3.1 From 20bc8c1e972f29afcac85e524e430c11a6df5f58 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 11 May 2021 18:39:55 +0300 Subject: lib/vsprintf: Allow to override ISO 8601 date and time separator ISO 8601 defines 'T' as a separator between date and time. Though, some ABIs use time and date with ' ' (space) separator instead. Add a flavour to the %pt specifier to override default separator. Signed-off-by: Andy Shevchenko Reviewed-by: Petr Mladek Reviewed-by: Sergey Senozhatsky Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20210511153958.34527-1-andriy.shevchenko@linux.intel.com --- Documentation/core-api/printk-formats.rst | 7 ++++++- lib/test_printf.c | 5 +++++ lib/vsprintf.c | 22 +++++++++++++++++----- 3 files changed, 28 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst index 9be6de402cb9..7b6bfd8a78d3 100644 --- a/Documentation/core-api/printk-formats.rst +++ b/Documentation/core-api/printk-formats.rst @@ -514,9 +514,10 @@ Time and date :: %pt[RT] YYYY-mm-ddTHH:MM:SS + %pt[RT]s YYYY-mm-dd HH:MM:SS %pt[RT]d YYYY-mm-dd %pt[RT]t HH:MM:SS - %pt[RT][dt][r] + %pt[RT][dt][r][s] For printing date and time as represented by:: @@ -528,6 +529,10 @@ in human readable format. By default year will be incremented by 1900 and month by 1. Use %pt[RT]r (raw) to suppress this behaviour. +The %pt[RT]s (space) will override ISO 8601 separator by using ' ' (space) +instead of 'T' (Capital T) between date and time. It won't have any effect +when date or time is omitted. + Passed by reference. struct clk diff --git a/lib/test_printf.c b/lib/test_printf.c index 27b964ec723d..69b04b531492 100644 --- a/lib/test_printf.c +++ b/lib/test_printf.c @@ -528,6 +528,11 @@ time_and_date(void) test("0119-00-04T15:32:23", "%ptTr", &t); test("15:32:23|2019-01-04", "%ptTt|%ptTd", &t, &t); test("15:32:23|0119-00-04", "%ptTtr|%ptTdr", &t, &t); + + test("2019-01-04 15:32:23", "%ptTs", &t); + test("0119-00-04 15:32:23", "%ptTsr", &t); + test("15:32:23|2019-01-04", "%ptTts|%ptTds", &t, &t); + test("15:32:23|0119-00-04", "%ptTtrs|%ptTdrs", &t, &t); } static void __init diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 6c56c62fd9a5..8d5142ae742e 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -1798,7 +1798,8 @@ char *rtc_str(char *buf, char *end, const struct rtc_time *tm, struct printf_spec spec, const char *fmt) { bool have_t = true, have_d = true; - bool raw = false; + bool raw = false, iso8601_separator = true; + bool found = true; int count = 2; if (check_pointer(&buf, end, tm, spec)) @@ -1815,14 +1816,25 @@ char *rtc_str(char *buf, char *end, const struct rtc_time *tm, break; } - raw = fmt[count] == 'r'; + do { + switch (fmt[count++]) { + case 'r': + raw = true; + break; + case 's': + iso8601_separator = false; + break; + default: + found = false; + break; + } + } while (found); if (have_d) buf = date_str(buf, end, tm, raw); if (have_d && have_t) { - /* Respect ISO 8601 */ if (buf < end) - *buf = 'T'; + *buf = iso8601_separator ? 'T' : ' '; buf++; } if (have_t) @@ -2261,7 +2273,7 @@ early_param("no_hash_pointers", no_hash_pointers_enable); * - 'd[234]' For a dentry name (optionally 2-4 last components) * - 'D[234]' Same as 'd' but for a struct file * - 'g' For block_device name (gendisk + partition number) - * - 't[RT][dt][r]' For time and date as represented by: + * - 't[RT][dt][r][s]' For time and date as represented by: * R struct rtc_time * T time64_t * - 'C' For a clock, it prints the name (Common Clock Framework) or address -- cgit v1.3.1 From 867e6d38f367c5414c076f94c451da2f664b9c7e Mon Sep 17 00:00:00 2001 From: Wu XiangCheng Date: Mon, 17 May 2021 18:34:20 +0800 Subject: docs/zh_CN: Add translation zh_CN/maintainer/index.rst Add a new translation Documentation/translations/zh_CN/maintainer/index.rst and link it to zh_CN/index.rst Signed-off-by: Wu XiangCheng Reviewed-by: Yanteng Si Link: https://lore.kernel.org/r/224959c4cdcd4c6554035145d5cedcd244887552.1621243426.git.bobwxc@email.cn Signed-off-by: Jonathan Corbet --- Documentation/translations/zh_CN/index.rst | 2 +- Documentation/translations/zh_CN/maintainer/index.rst | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/maintainer/index.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/index.rst b/Documentation/translations/zh_CN/index.rst index d56d6b7092e6..95c3f313cea1 100644 --- a/Documentation/translations/zh_CN/index.rst +++ b/Documentation/translations/zh_CN/index.rst @@ -72,11 +72,11 @@ TODOlist: dev-tools/index doc-guide/index kernel-hacking/index + maintainer/index TODOList: * trace/index -* maintainer/index * fault-injection/index * livepatch/index * rust/index diff --git a/Documentation/translations/zh_CN/maintainer/index.rst b/Documentation/translations/zh_CN/maintainer/index.rst new file mode 100644 index 000000000000..4ce27c12f370 --- /dev/null +++ b/Documentation/translations/zh_CN/maintainer/index.rst @@ -0,0 +1,19 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/maintainer/index.rst + +============== +内核维护者手册 +============== + +本文档本是内核维护者手册的首页。 +本手册还需要大量完善!请自由提出(和编写)本手册的补充内容。 +*译注:指英文原版* + +TODOList: + +- configure-git +- rebasing-and-merging +- pull-requests +- maintainer-entry-profile +- modifying-patches -- cgit v1.3.1 From 6ba8a96f4dbab7118d4c019bb30a41d74b2bda13 Mon Sep 17 00:00:00 2001 From: Wu XiangCheng Date: Mon, 17 May 2021 18:34:32 +0800 Subject: docs/zh_CN: Add translation zh_CN/maintainer/configure-git.rst Add a new translation Documentation/translations/zh_CN/maintainer/configure-git.rst and link it to zh_CN/maintainer/index.rst Signed-off-by: Wu XiangCheng Reviewed-by: Yanteng Si Link: https://lore.kernel.org/r/dcf6addd89eba3777b9b59d8b506fa162fbcd828.1621243426.git.bobwxc@email.cn Signed-off-by: Jonathan Corbet --- .../zh_CN/maintainer/configure-git.rst | 62 ++++++++++++++++++++++ .../translations/zh_CN/maintainer/index.rst | 6 ++- 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/maintainer/configure-git.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/maintainer/configure-git.rst b/Documentation/translations/zh_CN/maintainer/configure-git.rst new file mode 100644 index 000000000000..a45ea736f73b --- /dev/null +++ b/Documentation/translations/zh_CN/maintainer/configure-git.rst @@ -0,0 +1,62 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/maintainer/configure-git.rst + +:译者: + + 吴想成 Wu XiangCheng + +.. _configuregit_zh: + +Git配置 +======= + +本章讲述了维护者级别的git配置。 + +Documentation/maintainer/pull-requests.rst 中使用的标记分支应使用开发人员的 +GPG公钥进行签名。可以通过将 ``-u`` 标志传递给 ``git tag`` 来创建签名标记。 +但是,由于 *通常* 对同一项目使用同一个密钥,因此可以设置:: + + git config user.signingkey "keyname" + +或者手动编辑你的 ``.git/config`` 或 ``~/.gitconfig`` 文件:: + + [user] + name = Jane Developer + email = jd@domain.org + signingkey = jd@domain.org + +你可能需要告诉 ``git`` 去使用 ``gpg2``:: + + [gpg] + program = /path/to/gpg2 + +你可能也需要告诉 ``gpg`` 去使用哪个 ``tty`` (添加到你的shell rc文件中):: + + export GPG_TTY=$(tty) + + +创建链接到lore.kernel.org的提交 +------------------------------- + +http://lore.kernel.org 网站是所有涉及或影响内核开发的邮件列表的总存档。在这里 +存储补丁存档是推荐的做法,当维护人员将补丁应用到子系统树时,最好提供一个指向 +lore存档链接的标签,以便浏览提交历史的人可以找到某个更改背后的相关讨论和基本 +原理。链接标签如下所示: + + Link: https://lore.kernel.org/r/ + +通过在git中添加以下钩子,可以将此配置为在发布 ``git am`` 时自动执行: + +.. code-block:: none + + $ git config am.messageid true + $ cat >.git/hooks/applypatch-msg <<'EOF' + #!/bin/sh + . git-sh-setup + perl -pi -e 's|^Message-Id:\s*]+)>?$|Link: https://lore.kernel.org/r/$1|g;' "$1" + test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} + : + EOF + $ chmod a+x .git/hooks/applypatch-msg diff --git a/Documentation/translations/zh_CN/maintainer/index.rst b/Documentation/translations/zh_CN/maintainer/index.rst index 4ce27c12f370..e263315f5e7a 100644 --- a/Documentation/translations/zh_CN/maintainer/index.rst +++ b/Documentation/translations/zh_CN/maintainer/index.rst @@ -10,9 +10,13 @@ 本手册还需要大量完善!请自由提出(和编写)本手册的补充内容。 *译注:指英文原版* +.. toctree:: + :maxdepth: 2 + + configure-git + TODOList: -- configure-git - rebasing-and-merging - pull-requests - maintainer-entry-profile -- cgit v1.3.1 From b7198943af1709790e7a125ff911c529c12ccc3f Mon Sep 17 00:00:00 2001 From: Wu XiangCheng Date: Mon, 17 May 2021 18:34:46 +0800 Subject: docs/zh_CN: Add translation zh_CN/maintainer/rebasing-and-merging.rst Add a new translation Documentation/translations/zh_CN/maintainer/rebasing-and-merging.rst and link it to zh_CN/maintainer/index.rst Signed-off-by: Wu XiangCheng Reviewed-by: Yanteng Si Link: https://lore.kernel.org/r/040f93d0f773a0c9c8d6637701ba269d816a6385.1621243426.git.bobwxc@email.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/maintainer/index.rst | 2 +- .../zh_CN/maintainer/rebasing-and-merging.rst | 165 +++++++++++++++++++++ 2 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/maintainer/rebasing-and-merging.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/maintainer/index.rst b/Documentation/translations/zh_CN/maintainer/index.rst index e263315f5e7a..21ab7cebf78b 100644 --- a/Documentation/translations/zh_CN/maintainer/index.rst +++ b/Documentation/translations/zh_CN/maintainer/index.rst @@ -14,10 +14,10 @@ :maxdepth: 2 configure-git + rebasing-and-merging TODOList: -- rebasing-and-merging - pull-requests - maintainer-entry-profile - modifying-patches diff --git a/Documentation/translations/zh_CN/maintainer/rebasing-and-merging.rst b/Documentation/translations/zh_CN/maintainer/rebasing-and-merging.rst new file mode 100644 index 000000000000..83b7dabfe88b --- /dev/null +++ b/Documentation/translations/zh_CN/maintainer/rebasing-and-merging.rst @@ -0,0 +1,165 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/maintainer/rebasing-and-merging.rst + +:译者: + + 吴想成 Wu XiangCheng + +========== +变基与合并 +========== + +一般来说,维护子系统需要熟悉Git源代码管理系统。Git是一个功能强大的工具,有 +很多功能;就像这类工具常出现的情况一样,使用这些功能的方法有对有错。本文档 +特别介绍了变基与合并的用法。维护者经常在错误使用这些工具时遇到麻烦,但避免 +问题实际上并不那么困难。 + +总的来说,需要注意的一点是:与许多其他项目不同,内核社区并不害怕在其开发历史 +中看到合并提交。事实上,考虑到该项目的规模,避免合并几乎是不可能的。维护者会 +在希望避免合并时遇到一些问题,而过于频繁的合并也会带来另一些问题。 + +变基 +==== + +“变基(Rebase)”是更改存储库中一系列提交的历史记录的过程。有两种不同型的操作 +都被称为变基,因为这两种操作都使用 ``git rebase`` 命令,但它们之间存在显著 +差异: + + - 更改一系列补丁的父提交(起始提交)。例如,变基操作可以将基于上一内核版本 + 的一个补丁集重建到当前版本上。在下面的讨论中,我们将此操作称为“变根”。 + + - 通过修复(或删除)损坏的提交、添加补丁、添加标记以更改一系列补丁的历史, + 来提交变更日志或更改已应用提交的顺序。在下文中,这种类型的操作称为“历史 + 修改” + +术语“变基”将用于指代上述两种操作。如果使用得当,变基可以产生更清晰、更整洁的 +开发历史;如果使用不当,它可能会模糊历史并引入错误。 + +以下一些经验法则可以帮助开发者避免最糟糕的变基风险: + + - 已经发布到你私人系统之外世界的历史通常不应更改。其他人可能会拉取你的树 + 的副本,然后基于它进行工作;修改你的树会给他们带来麻烦。如果工作需要变基, + 这通常是表明它还没有准备好提交到公共存储库的信号。 + + 但是,总有例外。有些树(linux-next是一个典型的例子)由于它们的需要经常 + 变基,开发人员知道不要基于它们来工作。开发人员有时会公开一个不稳定的分支, + 供其他人或自动测试服务进行测试。如果您确实以这种方式公开了一个可能不稳定 + 的分支,请确保潜在使用者知道不要基于它来工作。 + + - 不要在包含由他人创建的历史的分支上变基。如果你从别的开发者的仓库拉取了变更, + 那你现在就成了他们历史记录的保管人。你不应该改变它,除了少数例外情况。例如 + 树中有问题的提交必须显式恢复(即通过另一个补丁修复),而不是通过修改历史而 + 消失。 + + - 没有合理理由,不要对树变根。仅为了切换到更新的基或避免与上游储存库的合并 + 通常不是合理理由。 + + - 如果你必须对储存库进行变根,请不要随机选取一个提交作为新基。在发布节点之间 + 内核通常处于一个相对不稳定的状态;基于其中某点进行开发会增加遇到意外错误的 + 几率。当一系列补丁必须移动到新基时,请选择移动到一个稳定节点(例如-rc版本 + 节点)。 + + - 请知悉对补丁系列进行变根(或做明显的历史修改)会改变它们的开发环境,且很 + 可能使做过的大部分测试失效。一般来说,变基后的补丁系列应当像新代码一样对 + 待,并重新测试。 + +合并窗口麻烦的一个常见原因是,Linus收到了一个明显在拉取请求发送之前不久才变根 +(通常是变根到随机的提交上)的补丁系列。这样一个系列被充分测试的可能性相对较 +低,拉取请求被接受的几率也同样较低。 + +相反,如果变基仅限于私有树、提交基于一个通用的起点、且经过充分测试,则引起 +麻烦的可能性就很低。 + +合并 +==== + +内核开发过程中,合并是一个很常见的操作;5.1版本开发周期中有超过1126个合并 +——差不多占了整体的9%。内核开发工作积累在100多个不同的子系统树中,每个 +子系统树都可能包含多个主题分支;每个分支通常独立于其他分支进行开发。因此 +在任何给定分支进入上游储存库之前,至少需要一次合并。 + +许多项目要求拉取请求中的分支基于当前主干,这样历史记录中就不会出现合并提交。 +内核并不是这样;任何为了避免合并而重新对分支变基都很可能导致麻烦。 + +子系统维护人员发现他们必须进行两种类型的合并:从较低层级的子系统树和从其他 +子系统树(同级树或主线)进行合并。这两种情况下要遵循的最佳实践是不同的。 + +合并较低层级树 +-------------- + +较大的子系统往往有多个级别的维护人员,较低级别的维护人员向较高级别发送拉取 +请求。合并这样的请求执行几乎肯定会生成一个合并提交;这也是应该的。实际上, +子系统维护人员可能希望在极少数快进合并情况下使用 ``-–no-ff`` 标志来强制添加 +合并提交,以便记录合并的原因。 **任何** 类型的合并的变更日志必须说明 +*为什么* 合并。对于较低级别的树,“为什么”通常是对该取所带来的变化的总结。 + +各级维护人员都应在他们的拉取请求上使用经签名的标签,上游维护人员应在拉取分支 +时验证标签。不这样做会威胁整个开发过程的安全。 + +根据上面列出的规则,一旦您将其他人的历史记录合并到树中,您就不得对该分支进行 +变基,即使您能够这样做。 + +合并同级树或上游树 +------------------ + +虽然来自下游的合并是常见且不起眼的,但当需要将一个分支推向上游时,其中来自 +其他树的合并往往是一个危险信号。这种合并需要仔细考虑并加以充分证明,否则后续 +的拉取请求很可能会被拒绝。 + +想要将主分支合并到存储库中是很自然的;这种类型的合并通常被称为“反向合并” +。反向合并有助于确保与并行的开发没有冲突,并且通常会给人一种温暖、舒服的 +感觉,即处于最新。但这种诱惑几乎总是应该避免的。 + +为什么呢?反向合并将搅乱你自己分支的开发历史。它们会大大增加你遇到来自社区 +其他地方的错误的机会,且使你很难确保你所管理的工作稳定并准备好合入上游。 +频繁的合并还可以掩盖树中开发过程中的问题;它们会隐藏与其他树的交互,而这些 +交互不应该(经常)发生在管理良好的分支中。 + +也就是说,偶尔需要进行反向合并;当这种情况发生时,一定要在提交信息中记录 +*为什么* 。同样,在一个众所周知的稳定点进行合并,而不是随机提交。即使这样, +你也不应该反向合并一棵比你的直接上游树更高层级的树;如果确实需要更高级别的 +反向合并,应首先在上游树进行。 + +导致合并相关问题最常见的原因之一是:在发送拉取请求之前维护者合并上游以解决 +合并冲突。同样,这种诱惑很容易理解,但绝对应该避免。对于最终拉取请求来说 +尤其如此:Linus坚信他更愿意看到合并冲突,而不是不必要的反向合并。看到冲突 +可以让他了解潜在的问题所在。他做过很多合并(在5.1版本开发周期中是382次), +而且在解决冲突方面也很在行——通常比参与的开发人员要强。 + +那么,当他们的子系统分支和主线之间发生冲突时,维护人员应该怎么做呢?最重要 +的一步是在拉取请求中提示Linus会发生冲突;如果啥都没说则表明您的分支可以正常 +合入。对于特别困难的冲突,创建并推送一个 *独立* 分支来展示你将如何解决问题。 +在拉取请求中提到该分支,但是请求本身应该针对未合并的分支。 + +即使不存在已知冲突,在发送拉取请求之前进行合并测试也是个好主意。它可能会提醒 +您一些在linux-next树中没有发现的问题,并帮助您准确地理解您正在要求上游做什么。 + +合并上游树或另一个子系统树的另一个原因是解决依赖关系。这些依赖性问题有时确实 +会发生,而且有时与另一棵树交叉合并是解决这些问题的最佳方法;同样,在这种情况 +下,合并提交应该解释为什么要进行合并。花点时间把它做好;会有人阅读这些变更 +日志。 + +然而依赖性问题通常表明需要改变方法。合并另一个子系统树以解决依赖性风险会带来 +其他缺陷,几乎永远不应这样做。如果该子系统树无法被合到上游,那么它的任何问题 +也都会阻碍你的树合并。更可取的选择包括与维护人员达成一致意见,在其中一个树中 +同时进行两组更改;或者创建一个主题分支专门处理可以合并到两个树中的先决条件提交。 +如果依赖关系与主要的基础结构更改相关,正确的解决方案可能是将依赖提交保留一个 +开发周期,以便这些更改有时间在主线上稳定。 + +最后 +==== + +在开发周期的开头合并主线是比较常见的,可以获取树中其他地方的更改和修复。同样, +这样的合并应该选择一个众所周知的发布点,而不是一些随机点。如果在合并窗口期间 +上游分支已完全清空到主线中,则可以使用以下命令向前拉取它:: + + git merge v5.2-rc1^0 + +“^0”使Git执行快进合并(在这种情况下这应该可以),从而避免多余的虚假合并提交。 + +上面列出的就是指导方针了。总是会有一些情况需要不同的解决方案,这些指导原则 +不应阻止开发人员在需要时做正确的事情。但是,我们应该时刻考虑是否真的出现了 +这样的需求,并准备好解释为什么需要做一些不寻常的事情。 -- cgit v1.3.1 From 989cfaecbd2c06800d13f49206498602b1e769a8 Mon Sep 17 00:00:00 2001 From: Wu XiangCheng Date: Mon, 17 May 2021 18:35:05 +0800 Subject: docs/zh_CN: Add translation zh_CN/maintainer/pull-requests.rst Add a new translation Documentation/translations/zh_CN/maintainer/pull-requests.rst and link it to zh_CN/maintainer/index.rst Signed-off-by: Wu XiangCheng Reviewed-by: Yanteng Si Link: https://lore.kernel.org/r/4774d1b7976678ce97c4356bd71509df0cec1ffc.1621243426.git.bobwxc@email.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/maintainer/index.rst | 2 +- .../zh_CN/maintainer/pull-requests.rst | 148 +++++++++++++++++++++ 2 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/maintainer/pull-requests.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/maintainer/index.rst b/Documentation/translations/zh_CN/maintainer/index.rst index 21ab7cebf78b..1a1222b78715 100644 --- a/Documentation/translations/zh_CN/maintainer/index.rst +++ b/Documentation/translations/zh_CN/maintainer/index.rst @@ -15,9 +15,9 @@ configure-git rebasing-and-merging + pull-requests TODOList: -- pull-requests - maintainer-entry-profile - modifying-patches diff --git a/Documentation/translations/zh_CN/maintainer/pull-requests.rst b/Documentation/translations/zh_CN/maintainer/pull-requests.rst new file mode 100644 index 000000000000..f46d6f3f2498 --- /dev/null +++ b/Documentation/translations/zh_CN/maintainer/pull-requests.rst @@ -0,0 +1,148 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/maintainer/pull-requests.rst + +:译者: + + 吴想成 Wu XiangCheng + +.. _pullrequests_zh: + +如何创建拉取请求 +================ + +本章描述维护人员如何创建并向其他维护人员提交拉取请求。这对将更改从一个维护者 +树转移到另一个维护者树非常有用。 + +本文档由Tobin C. Harding(当时他尚不是一名经验丰富的维护人员)编写,内容主要 +来自Greg Kroah Hartman和Linus Torvalds在LKML上的评论。Jonathan Corbet和Mauro +Carvalho Chehab提出了一些建议和修改。错误不可避免,如有问题,请找Tobin C. +Harding 。 + +原始邮件线程:: + + http://lkml.kernel.org/r/20171114110500.GA21175@kroah.com + + +创建分支 +-------- + +首先,您需要将希望包含拉取请求里的所有更改都放在单独分支中。通常您将基于某开发 +人员树的一个分支,一般是打算向其发送拉取请求的开发人员。 + +为了创建拉取请求,您必须首先标记刚刚创建的分支。建议您选择一个有意义的标记名, +以即使过了一段时间您和他人仍能理解的方式。在名称中包含源子系统和目标内核版本 +的指示也是一个好的做法。 + +Greg提供了以下内容。对于一个含有drivers/char中混杂事项、将应用于4.15-rc1内核的 +拉取请求,可以命名为 ``char-misc-4.15-rc1`` 。如果要在 ``char-misc-next`` 分支 +上打上此标记,您可以使用以下命令:: + + git tag -s char-misc-4.15-rc1 char-misc-next + +这将在 ``char-misc-next`` 分支的最后一个提交上创建一个名为 ``char-misc-4.15-rc1`` +的标记,并用您的gpg密钥签名(参见 Documentation/maintainer/configure-git.rst )。 + +Linus只接受基于签名过的标记的拉取请求。其他维护者可能会有所不同。 + +当您运行上述命令时 ``git`` 会打开编辑器要求你描述一下这个标记。在本例中您需要 +描述拉取请求,所以请概述一下包含的内容,为什么要合并,是否完成任何测试。所有 +这些信息都将留在标记中,然后在维护者合并拉取请求时保留在合并提交中。所以把它 +写好,它将永远留在内核中。 + +正如Linus所说:: + + 不管怎么样,至少对我来说,重要的是 *信息* 。我需要知道我在拉取什么、 + 为什么我要拉取。我也希望将此消息用于合并消息,因此它不仅应该对我有 + 意义,也应该可以成为一个有意义的历史记录。 + + 注意,如果拉取请求有一些不寻常的地方,请详细说明。如果你修改了并非 + 由你维护的文件,请解释 **为什么** 。我总会在差异中看到的,如果你不 + 提的话,我只会觉得分外可疑。当你在合并窗口后给我发新东西的时候, + (甚至是比较重大的错误修复),不仅需要解释做了什么、为什么这么做, + 还请解释一下 **时间问题** 。为什么错过了合并窗口…… + + 我会看你写在拉取请求邮件和签名标记里面的内容,所以根据你的工作流, + 你可以在签名标记里面描述工作内容(也会自动放进拉取请求邮件),也 + 可以只在标记里面放个占位符,稍后在你实际发给我拉取请求时描述工作内容。 + + 是的,我会编辑这些消息。部分因为我需要做一些琐碎的格式调整(整体缩进、 + 括号等),也因为此消息可能对我有意义(描述了冲突或一些个人问题)而对 + 合并提交信息上下文没啥意义,因此我需要尽力让它有意义起来。我也会 + 修复一些拼写和语法错误,特别是非母语者(母语者也是;^)。但我也会删掉 + 或增加一些内容。 + + Linus + +Greg给出了一个拉取请求的例子:: + + Char/Misc patches for 4.15-rc1 + + Here is the big char/misc patch set for the 4.15-rc1 merge window. + Contained in here is the normal set of new functions added to all + of these crazy drivers, as well as the following brand new + subsystems: + - time_travel_controller: Finally a set of drivers for the + latest time travel bus architecture that provides i/o to + the CPU before it asked for it, allowing uninterrupted + processing + - relativity_shifters: due to the affect that the + time_travel_controllers have on the overall system, there + was a need for a new set of relativity shifter drivers to + accommodate the newly formed black holes that would + threaten to suck CPUs into them. This subsystem handles + this in a way to successfully neutralize the problems. + There is a Kconfig option to force these to be enabled + when needed, so problems should not occur. + + All of these patches have been successfully tested in the latest + linux-next releases, and the original problems that it found have + all been resolved (apologies to anyone living near Canberra for the + lack of the Kconfig options in the earlier versions of the + linux-next tree creations.) + + Signed-off-by: Your-name-here + + +此标记消息格式就像一个git提交。顶部有一行“总结标题”, 一定要在下面sign-off。 + +现在您已经有了一个本地签名标记,您需要将它推送到可以被拉取的位置:: + + git push origin char-misc-4.15-rc1 + + +创建拉取请求 +------------ + +最后要做的是创建拉取请求消息。可以使用 ``git request-pull`` 命令让 ``git`` +为你做这件事,但它需要确定你想拉取什么,以及拉取针对的基础(显示正确的拉取 +更改和变更状态)。以下命令将生成一个拉取请求:: + + git request-pull master git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git/ char-misc-4.15-rc1 + +引用Greg的话:: + + 此命令要求git比较从“char-misc-4.15-rc1”标记位置到“master”分支头(上述 + 例子中指向了我从Linus的树分叉的地方,通常是-rc发布)的差异,并去使用 + git:// 协议拉取。如果你希望使用 https:// 协议,也可以用在这里(但是请 + 注意,部分人由于防火墙问题没法用https协议拉取)。 + + 如果char-misc-4.15-rc1标记没有出现在我要求拉取的仓库中,git会提醒 + 它不在那里,所以记得推送到公开地方。 + + “git request-pull”会包含git树的地址和需要拉取的特定标记,以及标记 + 描述全文(详尽描述标记)。同时它也会创建此拉取请求的差异状态和单个 + 提交的缩短日志。 + +Linus回复说他倾向于 ``git://`` 协议。其他维护者可能有不同的偏好。另外,请注意 +如果你创建的拉取请求没有签名标记, ``https://`` 可能是更好的选择。完整的讨论 +请看原邮件。 + + +提交拉取请求 +------------ + +拉取请求的提交方式与普通补丁相同。向维护人员发送内联电子邮件并抄送LKML以及 +任何必要特定子系统的列表。对Linus的拉取请求通常有如下主题行:: + + [GIT PULL] changes for v4.15-rc1 -- cgit v1.3.1 From 91643aba949347ab46b870524dd9348781fa8b1d Mon Sep 17 00:00:00 2001 From: Wu XiangCheng Date: Mon, 17 May 2021 18:35:33 +0800 Subject: docs/zh_CN: Add translation zh_CN/maintainer/maintainer-entry-profile.rst Add a new translation Documentation/translations/zh_CN/maintainer/maintainer-entry-profile.rst and link it to zh_CN/maintainer/index.rst Signed-off-by: Wu XiangCheng Reviewed-by: Yanteng Si Link: https://lore.kernel.org/r/e5b0838317cbc2f8fb3a9480f4604b6f099db975.1621243426.git.bobwxc@email.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/maintainer/index.rst | 2 +- .../zh_CN/maintainer/maintainer-entry-profile.rst | 92 ++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/maintainer/maintainer-entry-profile.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/maintainer/index.rst b/Documentation/translations/zh_CN/maintainer/index.rst index 1a1222b78715..18a820741f52 100644 --- a/Documentation/translations/zh_CN/maintainer/index.rst +++ b/Documentation/translations/zh_CN/maintainer/index.rst @@ -16,8 +16,8 @@ configure-git rebasing-and-merging pull-requests + maintainer-entry-profile TODOList: -- maintainer-entry-profile - modifying-patches diff --git a/Documentation/translations/zh_CN/maintainer/maintainer-entry-profile.rst b/Documentation/translations/zh_CN/maintainer/maintainer-entry-profile.rst new file mode 100644 index 000000000000..a1ee99c4786e --- /dev/null +++ b/Documentation/translations/zh_CN/maintainer/maintainer-entry-profile.rst @@ -0,0 +1,92 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/maintainer/maintainer-entry-profile.rst + +:译者: + + 吴想成 Wu XiangCheng + +.. _maintainerentryprofile_zh: + +维护者条目概要 +============== + +维护人员条目概要补充了顶层过程文档(提交补丁,提交驱动程序……),增加了子系 +统/设备驱动程序本地习惯以及有关补丁提交生命周期的相关内容。贡献者使用此文档 +来调整他们的期望和避免常见错误;维护人员可以使用这些信息超越子系统层面查看 +是否有机会汇聚到通用实践中。 + + +总览 +---- + +提供了子系统如何操作的介绍。MAINTAINERS文件告诉了贡献者应发送某文件的补丁到哪, +但它没有传达其他子系统的本地基础设施和机制以协助开发。 + +请考虑以下问题: + +- 当补丁被本地树接纳或合并到上游时是否有通知? +- 子系统是否使用patchwork实例?Patchwork状态变更是否有通知? +- 是否有任何机器人或CI基础设施监视列表,或子系统是否使用自动测试反馈以便把 + 控接纳补丁? +- 被拉入-next的Git分支是哪个? +- 贡献者应针对哪个分支提交? +- 是否链接到其他维护者条目概要?例如一个设备驱动可能指向其父子系统的条目。 + 这使得贡献者意识到某维护者可能对提交链中其他维护者负有的义务。 + + +提交检查单补遗 +-------------- + +列出强制性和咨询性标准,超出通用标准“提交检查表,以便维护者检查一个补丁是否 +足够健康。例如:“通过checkpatch.pl,没有错误、没有警告。通过单元测试详见某处”。 + +提交检查单补遗还可以包括有关硬件规格状态的详细信息。例如,子系统接受补丁之前 +是否需要考虑在某个修订版上发布的规范。 + + +开发周期的关键日期 +------------------ + +提交者常常会误以为补丁可以在合并窗口关闭之前的任何时间发送,且下一个-rc1时仍 +可以。事实上,大多数补丁都需要在下一个合并窗口打开之前提前进入linux-next中。 +向提交者澄清关键日期(以-rc发布周为标志)以明确什么时候补丁会被考虑合并以及 +何时需要等待下一个-rc。 + +至少需要讲明: + +- 最后一个可以提交新功能的-rc: + 针对下一个合并窗口的新功能提交应该在此点之前首次发布以供考虑。在此时间点 + 之后提交的补丁应该明确他们的目标为下下个合并窗口,或者给出应加快进度被接受 + 的充足理由。通常新特性贡献者的提交应出现在-rc5之前。 + +- 最后合并-rc:合并决策的最后期限。 + 向贡献者指出尚未接受的补丁集需要等待下下个合并窗口。当然,维护者没有义务 + 接受所有给定的补丁集,但是如果审阅在此时间点尚未结束,那么希望贡献者应该 + 等待并在下一个合并窗口重新提交。 + +可选项: + +- 开发基线分支的首个-rc,列在概述部分,视为已为新提交做好准备。 + + +审阅节奏 +-------- + +贡献者最担心的问题之一是:补丁集已发布却未收到反馈,应在多久后发送提醒。除了 +指定在重新提交之前要等待多长时间,还可以指示更新的首选样式;例如,重新发送 +整个系列,或私下发送提醒邮件。本节也可以列出本区域的代码审阅方式,以及获取 +不能直接从维护者那里得到的反馈的方法。 + + +现有概要 +-------- + +这里列出了现有的维护人员条目概要;我们可能会想要在不久的将来做一些不同的事情。 + +.. toctree:: + :maxdepth: 1 + + ../doc-guide/maintainer-profile + ../../../nvdimm/maintainer-entry-profile + ../../../riscv/patch-acceptance -- cgit v1.3.1 From 55e0990231a980459393729e253c26759172744a Mon Sep 17 00:00:00 2001 From: Wu XiangCheng Date: Mon, 17 May 2021 18:35:47 +0800 Subject: docs/zh_CN: Add translation zh_CN/maintainer/modifying-patches.rst Add a new translation Documentation/translations/zh_CN/maintainer/modifying-patches.rst and link it to zh_CN/maintainer/index.rst Signed-off-by: Wu XiangCheng Reviewed-by: Yanteng Si Link: https://lore.kernel.org/r/35e6878cb634db61c573fc7fdc69ef4c5d8ae31c.1621243426.git.bobwxc@email.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/maintainer/index.rst | 4 +- .../zh_CN/maintainer/modifying-patches.rst | 51 ++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 Documentation/translations/zh_CN/maintainer/modifying-patches.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/maintainer/index.rst b/Documentation/translations/zh_CN/maintainer/index.rst index 18a820741f52..eb75ccea9a21 100644 --- a/Documentation/translations/zh_CN/maintainer/index.rst +++ b/Documentation/translations/zh_CN/maintainer/index.rst @@ -17,7 +17,5 @@ rebasing-and-merging pull-requests maintainer-entry-profile + modifying-patches -TODOList: - -- modifying-patches diff --git a/Documentation/translations/zh_CN/maintainer/modifying-patches.rst b/Documentation/translations/zh_CN/maintainer/modifying-patches.rst new file mode 100644 index 000000000000..7f6326137f6b --- /dev/null +++ b/Documentation/translations/zh_CN/maintainer/modifying-patches.rst @@ -0,0 +1,51 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/maintainer/modifying-patches.rst + +:译者: + + 吴想成 Wu XiangCheng + +.. _modifyingpatches_zh: + +修改补丁 +======== + +如果你是子系统或者分支的维护者,由于代码在你的和提交者的树中并不完全相同, +有时你需要稍微修改一下收到的补丁以合并它们。 + +如果你严格遵守开发者来源证书的规则(c),你应该要求提交者重做,但这完全是会 +适得其反的时间、精力浪费。规则(b)允许你调整代码,但这样修改提交者的代码并 +让他背书你的错误是非常不礼貌的。为解决此问题,建议在你之前最后一个 +Signed-off-by标签和你的之间添加一行,以指示更改的性质。这没有强制性要求,最 +好在描述前面加上你的邮件和/或姓名,用方括号括住整行,以明显指出你对最后一刻 +的更改负责。例如:: + + Signed-off-by: Random J Developer + [lucky@maintainer.example.org: struct foo moved from foo.c to foo.h] + Signed-off-by: Lucky K Maintainer + +如果您维护着一个稳定的分支,并希望同时明确贡献、跟踪更改、合并修复,并保护 +提交者免受责难,这种做法尤其有用。请注意,在任何情况下都不得更改作者的身份 +(From头),因为它会在变更日志中显示。 + +向后移植(back-port)人员特别要注意:为了便于跟踪,请在提交消息的顶部(即主题行 +之后)插入补丁的来源,这是一种常见而有用的做法。例如,我们可以在3.x稳定版本 +中看到以下内容:: + + Date: Tue Oct 7 07:26:38 2014 -0400 + + libata: Un-break ATA blacklist + + commit 1c40279960bcd7d52dbdf1d466b20d24b99176c8 upstream. + +下面是一个旧的内核在某补丁被向后移植后会出现的:: + + Date: Tue May 13 22:12:27 2008 +0200 + + wireless, airo: waitbusy() won't delay + + [backport of 2.6 commit b7acbdfbd1f277c1eb23f344f899cfa4cd0bf36a] + +不管什么格式,这些信息都为人们跟踪你的树,以及试图解决你树中的错误的人提供了 +有价值的帮助。 -- cgit v1.3.1 From 94c1fbd487b33a28ea7f0da076a2cba6d0f410cf Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Mon, 17 May 2021 16:46:13 +0800 Subject: docs/zh_CN: add core-api kernel-api.rst translation This patch translates Documentation/core-api/kernel-api.rst into Chinese. Signed-off-by: Yanteng Si Reviewed-by: Wu XiangCheng Reviewed-by: Alex Shi Link: https://lore.kernel.org/r/d79e2d1f37bae52ce6fce0efb2fa4a32a89165fb.1621239725.git.siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/core-api/index.rst | 5 +- .../translations/zh_CN/core-api/kernel-api.rst | 369 +++++++++++++++++++++ 2 files changed, 373 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/core-api/kernel-api.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/core-api/index.rst b/Documentation/translations/zh_CN/core-api/index.rst index f1fa71e45c77..60e1566d57eb 100644 --- a/Documentation/translations/zh_CN/core-api/index.rst +++ b/Documentation/translations/zh_CN/core-api/index.rst @@ -19,9 +19,12 @@ 来的大量 kerneldoc 信息;有朝一日,若有人有动力的话,应当把它们拆分 出来。 -Todolist: +.. toctree:: + :maxdepth: 1 kernel-api + +Todolist: workqueue printk-basics printk-formats diff --git a/Documentation/translations/zh_CN/core-api/kernel-api.rst b/Documentation/translations/zh_CN/core-api/kernel-api.rst new file mode 100644 index 000000000000..d6f815ec265b --- /dev/null +++ b/Documentation/translations/zh_CN/core-api/kernel-api.rst @@ -0,0 +1,369 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/core-api/kernel-api.rst +:Translator: Yanteng Si + +.. _cn_kernel-api.rst: + + +============ +Linux内核API +============ + + +列表管理函数 +============ + +该API在以下内核代码中: + +include/linux/list.h + +基本的C库函数 +============= + +在编写驱动程序时,一般不能使用C库中的例程。部分函数通常很有用,它们在 +下面被列出。这些函数的行为可能会与ANSI定义的略有不同,这些偏差会在文中 +注明。 + +字符串转换 +---------- + +该API在以下内核代码中: + +lib/vsprintf.c + +include/linux/kernel.h + +include/linux/kernel.h + +lib/kstrtox.c + +lib/string_helpers.c + +字符串处理 +---------- + +该API在以下内核代码中: + +lib/string.c + +include/linux/string.h + +mm/util.c + +基本的内核库函数 +================ + +Linux内核提供了很多实用的基本函数。 + +位运算 +------ + +该API在以下内核代码中: + +include/asm-generic/bitops/instrumented-atomic.h + +include/asm-generic/bitops/instrumented-non-atomic.h + +include/asm-generic/bitops/instrumented-lock.h + +位图运算 +-------- + +该API在以下内核代码中: + +lib/bitmap.c + +include/linux/bitmap.h + +include/linux/bitmap.h + +include/linux/bitmap.h + +lib/bitmap.c + +lib/bitmap.c + +include/linux/bitmap.h + +命令行解析 +---------- + +该API在以下内核代码中: + +lib/cmdline.c + +排序 +---- + +该API在以下内核代码中: + +lib/sort.c + +lib/list_sort.c + +文本检索 +-------- + +该API在以下内核代码中: + +lib/textsearch.c + +lib/textsearch.c + +include/linux/textsearch.h + +Linux中的CRC和数学函数 +====================== + + +CRC函数 +------- + +*译注:CRC,Cyclic Redundancy Check,循环冗余校验* + +该API在以下内核代码中: + +lib/crc4.c + +lib/crc7.c + +lib/crc8.c + +lib/crc16.c + +lib/crc32.c + +lib/crc-ccitt.c + +lib/crc-itu-t.c + +基数为2的对数和幂函数 +--------------------- + +该API在以下内核代码中: + +include/linux/log2.h + +整数幂函数 +---------- + +该API在以下内核代码中: + +lib/math/int_pow.c + +lib/math/int_sqrt.c + +除法函数 +-------- + +该API在以下内核代码中: + +include/asm-generic/div64.h + +include/linux/math64.h + +lib/math/div64.c + +lib/math/gcd.c + +UUID/GUID +--------- + +该API在以下内核代码中: + +lib/uuid.c + +内核IPC设备 +=========== + +IPC实用程序 +----------- + +该API在以下内核代码中: + +ipc/util.c + +FIFO 缓冲区 +=========== + +kfifo接口 +--------- + +该API在以下内核代码中: + +include/linux/kfifo.h + +转发接口支持 +============ + +转发接口支持旨在为工具和设备提供一种有效的机制,将大量数据从内核空间 +转发到用户空间。 + +转发接口 +-------- + +该API在以下内核代码中: + +kernel/relay.c + +kernel/relay.c + +模块支持 +======== + +模块加载 +-------- + +该API在以下内核代码中: + +kernel/kmod.c + +模块接口支持 +------------ + +更多信息请参考文件kernel/module.c。 + +硬件接口 +======== + + +该API在以下内核代码中: + +kernel/dma.c + +资源管理 +-------- + +该API在以下内核代码中: + +kernel/resource.c + +kernel/resource.c + +MTRR处理 +-------- + +该API在以下内核代码中: + +arch/x86/kernel/cpu/mtrr/mtrr.c + +安全框架 +======== + +该API在以下内核代码中: + +security/security.c + +security/inode.c + +审计接口 +======== + +该API在以下内核代码中: + +kernel/audit.c + +kernel/auditsc.c + +kernel/auditfilter.c + +核算框架 +======== + +该API在以下内核代码中: + +kernel/acct.c + +块设备 +====== + +该API在以下内核代码中: + +block/blk-core.c + +block/blk-core.c + +block/blk-map.c + +block/blk-sysfs.c + +block/blk-settings.c + +block/blk-exec.c + +block/blk-flush.c + +block/blk-lib.c + +block/blk-integrity.c + +kernel/trace/blktrace.c + +block/genhd.c + +block/genhd.c + +字符设备 +======== + +该API在以下内核代码中: + +fs/char_dev.c + +时钟框架 +======== + +时钟框架定义了编程接口,以支持系统时钟树的软件管理。该框架广泛用于系统级芯片(SOC)平 +台,以支持电源管理和各种可能需要自定义时钟速率的设备。请注意,这些 “时钟”与计时或实 +时时钟(RTC)无关,它们都有单独的框架。这些:c:type: `struct clk ` 实例可用于管理 +各种时钟信号,例如一个96理例如96MHz的时钟信号,该信号可被用于总线或外设的数据交换,或以 +其他方式触发系统硬件中的同步状态机转换。 + +通过明确的软件时钟门控来支持电源管理:未使用的时钟被禁用,因此系统不会因为改变不在使用 +中的晶体管的状态而浪费电源。在某些系统中,这可能是由硬件时钟门控支持的,其中时钟被门控 +而不在软件中被禁用。芯片的部分,在供电但没有时钟的情况下,可能会保留其最后的状态。这种 +低功耗状态通常被称为*保留模式*。这种模式仍然会产生漏电流,特别是在电路几何结构较细的情 +况下,但对于CMOS电路来说,电能主要是随着时钟翻转而被消耗的。 + +电源感知驱动程序只有在其管理的设备处于活动使用状态时才会启用时钟。此外,系统睡眠状态通 +常根据哪些时钟域处于活动状态而有所不同:“待机”状态可能允许从多个活动域中唤醒,而 +"mem"(暂停到RAM)状态可能需要更全面地关闭来自高速PLL和振荡器的时钟,从而限制了可能 +的唤醒事件源的数量。驱动器的暂停方法可能需要注意目标睡眠状态的系统特定时钟约束。 + +一些平台支持可编程时钟发生器。这些可以被各种外部芯片使用,如其他CPU、多媒体编解码器以 +及对接口时钟有严格要求的设备。 + +该API在以下内核代码中: + +include/linux/clk.h + +同步原语 +======== + +读-复制-更新(RCU) +------------------- + +该API在以下内核代码中: + +include/linux/rcupdate.h + +kernel/rcu/tree.c + +kernel/rcu/tree_exp.h + +kernel/rcu/update.c + +include/linux/srcu.h + +kernel/rcu/srcutree.c + +include/linux/rculist_bl.h + +include/linux/rculist.h + +include/linux/rculist_nulls.h + +include/linux/rcu_sync.h + +kernel/rcu/sync.c -- cgit v1.3.1 From 7c0066d132d237db6702804aa1fcb18fefcda00b Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Mon, 17 May 2021 16:46:14 +0800 Subject: docs/zh_CN: add core-api printk-basics.rst translation This patch translates Documentation/core-api/printk-basics.rst into Chinese. Signed-off-by: Yanteng Si Reviewed-by: Wu XiangCheng Reviewed-by: Alex Shi Reviewed-by: Jiaxun Yang Link: https://lore.kernel.org/r/1610df76720b69f3f81bff27403e70e86c0875c5.1621239725.git.siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/core-api/index.rst | 2 +- .../translations/zh_CN/core-api/printk-basics.rst | 110 +++++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/core-api/printk-basics.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/core-api/index.rst b/Documentation/translations/zh_CN/core-api/index.rst index 60e1566d57eb..5ecb23e3ba8c 100644 --- a/Documentation/translations/zh_CN/core-api/index.rst +++ b/Documentation/translations/zh_CN/core-api/index.rst @@ -23,10 +23,10 @@ :maxdepth: 1 kernel-api + printk-basics Todolist: workqueue - printk-basics printk-formats symbol-namespaces diff --git a/Documentation/translations/zh_CN/core-api/printk-basics.rst b/Documentation/translations/zh_CN/core-api/printk-basics.rst new file mode 100644 index 000000000000..2b20f6303a82 --- /dev/null +++ b/Documentation/translations/zh_CN/core-api/printk-basics.rst @@ -0,0 +1,110 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/core-api/printk-basics.rst +:Translator: Yanteng Si + +.. _cn_printk-basics.rst: + + +================== +使用printk记录消息 +================== + +printk()是Linux内核中最广为人知的函数之一。它是我们打印消息的标准工具,通常也是追踪和调试 +的最基本方法。如果你熟悉printf(3),你就能够知道printk()是基于它的,尽管它在功能上有一些不 +同之处: + + - printk() 消息可以指定日志级别。 + + - 格式字符串虽然与C99基本兼容,但并不遵循完全相同的规范。它有一些扩展和一些限制(没 + 有 ``%n`` 或浮点转换指定符)。参见:ref: `如何正确地获得printk格式指定符` 。 + +所有的printk()消息都会被打印到内核日志缓冲区,这是一个通过/dev/kmsg输出到用户空间的环 +形缓冲区。读取它的通常方法是使用 ``dmesg`` 。 + +printk()的用法通常是这样的:: + + printk(KERN_INFO "Message: %s\n", arg); + +其中 ``KERN_INFO`` 是日志级别(注意,它与格式字符串连在一起,日志级别不是一个单独的参数)。 +可用的日志级别是: + + ++----------------+--------+-----------------------------------------------+ +| 名称 | 字符串 | 别名函数 | ++================+========+===============================================+ +| KERN_EMERG | "0" | pr_emerg() | ++----------------+--------+-----------------------------------------------+ +| KERN_ALERT | "1" | pr_alert() | ++----------------+--------+-----------------------------------------------+ +| KERN_CRIT | "2" | pr_crit() | ++----------------+--------+-----------------------------------------------+ +| KERN_ERR | "3" | pr_err() | ++----------------+--------+-----------------------------------------------+ +| KERN_WARNING | "4" | pr_warn() | ++----------------+--------+-----------------------------------------------+ +| KERN_NOTICE | "5" | pr_notice() | ++----------------+--------+-----------------------------------------------+ +| KERN_INFO | "6" | pr_info() | ++----------------+--------+-----------------------------------------------+ +| KERN_DEBUG | "7" | pr_debug() and pr_devel() 若定义了DEBUG | ++----------------+--------+-----------------------------------------------+ +| KERN_DEFAULT | "" | | ++----------------+--------+-----------------------------------------------+ +| KERN_CONT | "c" | pr_cont() | ++----------------+--------+-----------------------------------------------+ + + +日志级别指定了一条消息的重要性。内核根据日志级别和当前 *console_loglevel* (一个内核变量)决 +定是否立即显示消息(将其打印到当前控制台)。如果消息的优先级比 *console_loglevel* 高(日志级 +别值较低),消息将被打印到控制台。 + +如果省略了日志级别,则以 ``KERN_DEFAULT`` 级别打印消息。 + +你可以用以下方法检查当前的 *console_loglevel* :: + + $ cat /proc/sys/kernel/printk + 4 4 1 7 + +结果显示了 *current*, *default*, *minimum* 和 *boot-time-default* 日志级别 + +要改变当前的 console_loglevel,只需在 ``/proc/sys/kernel/printk`` 中写入所需的 +级别。例如,要打印所有的消息到控制台上:: + + # echo 8 > /proc/sys/kernel/printk + +另一种方式,使用 ``dmesg``:: + + # dmesg -n 5 + +设置 console_loglevel 打印 KERN_WARNING (4) 或更严重的消息到控制台。更多消息参 +见 ``dmesg(1)`` 。 + +作为printk()的替代方案,你可以使用 ``pr_*()`` 别名来记录日志。这个系列的宏在宏名中 +嵌入了日志级别。例如:: + + pr_info("Info message no. %d\n", msg_num); + +打印 ``KERN_INFO`` 消息。 + +除了比等效的printk()调用更简洁之外,它们还可以通过pr_fmt()宏为格式字符串使用一个通用 +的定义。例如,在源文件的顶部(在任何 ``#include`` 指令之前)定义这样的内容。:: + + #define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__ + +会在该文件中的每一条 pr_*() 消息前加上发起该消息的模块和函数名称。 + +为了调试,还有两个有条件编译的宏: +pr_debug()和pr_devel(),除非定义了 ``DEBUG`` (或者在pr_debug()的情况下定义了 +``CONFIG_DYNAMIC_DEBUG`` ),否则它们会被编译。 + + +函数接口 +======== + +该API在以下内核代码中: + +kernel/printk/printk.c + +include/linux/printk.h -- cgit v1.3.1 From eb2e708b9727806893e379c091184270c5468a6c Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Mon, 17 May 2021 16:46:15 +0800 Subject: docs/zh_CN: add core-api printk-formats.rst translation This patch translates Documentation/core-api/printk-formats.rst into Chinese. Signed-off-by: Yanteng Si Reviewed-by: Wu XiangCheng Reviewed-by: Alex Shi Reviewed-by: Jiaxun Yang Link: https://lore.kernel.org/r/b9dea1426e43d8848f1a8b7319c002418aebd3df.1621239725.git.siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/core-api/index.rst | 2 +- .../translations/zh_CN/core-api/printk-formats.rst | 580 +++++++++++++++++++++ 2 files changed, 581 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/core-api/printk-formats.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/core-api/index.rst b/Documentation/translations/zh_CN/core-api/index.rst index 5ecb23e3ba8c..c2d4614d9e68 100644 --- a/Documentation/translations/zh_CN/core-api/index.rst +++ b/Documentation/translations/zh_CN/core-api/index.rst @@ -24,10 +24,10 @@ kernel-api printk-basics + printk-formats Todolist: workqueue - printk-formats symbol-namespaces 数据结构和低级实用程序 diff --git a/Documentation/translations/zh_CN/core-api/printk-formats.rst b/Documentation/translations/zh_CN/core-api/printk-formats.rst new file mode 100644 index 000000000000..624a090e6ee5 --- /dev/null +++ b/Documentation/translations/zh_CN/core-api/printk-formats.rst @@ -0,0 +1,580 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/core-api/printk-formats.rst +:Translator: Yanteng Si + +.. _cn_printk-formats.rst: + + +============================== +如何获得正确的printk格式占位符 +============================== + + + +:作者: Randy Dunlap +:作者: Andrew Murray + + +整数类型 +======== + +:: + + 若变量类型是Type,则使用printk格式占位符。 + ------------------------------------------- + char %d 或 %x + unsigned char %u 或 %x + short int %d 或 %x + unsigned short int %u 或 %x + int %d 或 %x + unsigned int %u 或 %x + long %ld 或 %lx + unsigned long %lu 或 %lx + long long %lld 或 %llx + unsigned long long %llu 或 %llx + size_t %zu 或 %zx + ssize_t %zd 或 %zx + s8 %d 或 %x + u8 %u 或 %x + s16 %d 或 %x + u16 %u 或 %x + s32 %d 或 %x + u32 %u 或 %x + s64 %lld 或 %llx + u64 %llu 或 %llx + + +如果 的大小依赖于配置选项 (例如 sector_t, blkcnt_t) 或其大小依赖于架构 +(例如 tcflag_t),则使用其可能的最大类型的格式占位符并显式强制转换为它。 + +例如 + +:: + + printk("test: sector number/total blocks: %llu/%llu\n", + (unsigned long long)sector, (unsigned long long)blockcount); + +提醒:sizeof()返回类型为size_t。 + +内核的printf不支持%n。显而易见,浮点格式(%e, %f, %g, %a)也不被识别。使用任何不 +支持的占位符或长度限定符都会导致一个WARN并且终止vsnprintf()执行。 + +指针类型 +======== + +一个原始指针值可以用%p打印,它将在打印前对地址进行哈希处理。内核也支持扩展占位符来打印 +不同类型的指针。 + +一些扩展占位符会打印给定地址上的数据,而不是打印地址本身。在这种情况下,以下错误消息可能 +会被打印出来,而不是无法访问的消息:: + + (null) data on plain NULL address + (efault) data on invalid address + (einval) invalid data on a valid address + +普通指针 +---------- + +:: + + %p abcdef12 or 00000000abcdef12 + +没有指定扩展名的指针(即没有修饰符的%p)被哈希(hash),以防止内核内存布局消息的泄露。这 +样还有一个额外的好处,就是提供一个唯一的标识符。在64位机器上,前32位被清零。当没有足够的 +熵进行散列处理时,内核将打印(ptrval)代替 + +如果可能的话,使用专门的修饰符,如%pS或%pB(如下所述),以避免打印一个必须事后解释的非哈 +希地址。如果不可能,而且打印地址的目的是为调试提供更多的消息,使用%p,并在调试过程中 +用 ``no_hash_pointers`` 参数启动内核,这将打印所有未修改的%p地址。如果你 *真的* 想知 +道未修改的地址,请看下面的%px。 + +如果(也只有在)你将地址作为虚拟文件的内容打印出来,例如在procfs或sysfs中(使用 +seq_printf(),而不是printk())由用户空间进程读取,使用下面描述的%pK修饰符,不 +要用%p或%px。 + + +错误指针 +-------- + +:: + + %pe -ENOSPC + +用于打印错误指针(即IS_ERR()为真的指针)的符号错误名。不知道符号名的错误值会以十进制打印, +而作为%pe参数传递的非ERR_PTR会被视为普通的%p。 + +符号/函数指针 +------------- + +:: + + %pS versatile_init+0x0/0x110 + %ps versatile_init + %pSR versatile_init+0x9/0x110 + (with __builtin_extract_return_addr() translation) + %pB prev_fn_of_versatile_init+0x88/0x88 + + +``S`` 和 ``s`` 占位符用于打印符号格式的指针。它们的结果是符号名称带有(S)或不带有(s)偏移 +量。如果禁用KALLSYMS,则打印符号地址。 + +``B`` 占位符的结果是带有偏移量的符号名,在打印堆栈回溯时应该使用。占位符将考虑编译器优化 +的影响,当使用尾部调用并使用noreturn GCC属性标记时,可能会发生这种优化。 + +来自BPF / tracing追踪的探查指针 +---------------------------------- + +:: + + %pks kernel string + %pus user string + +``k`` 和 ``u`` 指定符用于打印来自内核内存(k)或用户内存(u)的先前探测的内存。后面的 ``s`` 指 +定符的结果是打印一个字符串。对于直接在常规的vsnprintf()中使用时,(k)和(u)注释被忽略,但是,当 +在BPF的bpf_trace_printk()之外使用时,它会读取它所指向的内存,不会出现错误。 + +内核指针 +-------- + +:: + + %pK 01234567 or 0123456789abcdef + +用于打印应该对非特权用户隐藏的内核指针。%pK的行为取决于kptr_restrict sysctl——详见 +Documentation/admin-guide/sysctl/kernel.rst。 + +未经修改的地址 +-------------- + +:: + + %px 01234567 or 0123456789abcdef + +对于打印指针,当你 *真的* 想打印地址时。在用%px打印指针之前,请考虑你是否泄露了内核内 +存布局的敏感消息。%px在功能上等同于%lx(或%lu)。%px是首选,因为它在grep查找时更唯一。 +如果将来我们需要修改内核处理打印指针的方式,我们将能更好地找到调用点。 + +在使用%px之前,请考虑使用%p并在调试过程中启用' ' no_hash_pointer ' '内核参数是否足 +够(参见上面的%p描述)。%px的一个有效场景可能是在panic发生之前立即打印消息,这样无论如何 +都可以防止任何敏感消息被利用,使用%px就不需要用no_hash_pointer来重现panic。 + +指针差异 +-------- + +:: + + %td 2560 + %tx a00 + +为了打印指针的差异,使用ptrdiff_t的%t修饰符。 + +例如:: + + printk("test: difference between pointers: %td\n", ptr2 - ptr1); + +结构体资源(Resources) +----------------------- + +:: + + %pr [mem 0x60000000-0x6fffffff flags 0x2200] or + [mem 0x0000000060000000-0x000000006fffffff flags 0x2200] + %pR [mem 0x60000000-0x6fffffff pref] or + [mem 0x0000000060000000-0x000000006fffffff pref] + +用于打印结构体资源。 ``R`` 和 ``r`` 占位符的结果是打印出的资源带有(R)或不带有(r)解码标志 +成员。 + +通过引用传递。 + +物理地址类型 phys_addr_t +------------------------ + +:: + + %pa[p] 0x01234567 or 0x0123456789abcdef + +用于打印phys_addr_t类型(以及它的衍生物,如resource_size_t),该类型可以根据构建选项而 +变化,无论CPU数据真实物理地址宽度如何。 + +通过引用传递。 + +DMA地址类型dma_addr_t +--------------------- + +:: + + %pad 0x01234567 or 0x0123456789abcdef + +用于打印dma_addr_t类型,该类型可以根据构建选项而变化,而不考虑CPU数据路径的宽度。 + +通过引用传递。 + +原始缓冲区为转义字符串 +---------------------- + +:: + + %*pE[achnops] + +用于将原始缓冲区打印成转义字符串。对于以下缓冲区:: + + 1b 62 20 5c 43 07 22 90 0d 5d + +几个例子展示了如何进行转换(不包括两端的引号)。:: + + %*pE "\eb \C\a"\220\r]" + %*pEhp "\x1bb \C\x07"\x90\x0d]" + %*pEa "\e\142\040\\\103\a\042\220\r\135" + +转换规则是根据可选的标志组合来应用的(详见:c:func:`string_escape_mem` 内核文档): + + - a - ESCAPE_ANY + - c - ESCAPE_SPECIAL + - h - ESCAPE_HEX + - n - ESCAPE_NULL + - o - ESCAPE_OCTAL + - p - ESCAPE_NP + - s - ESCAPE_SPACE + +默认情况下,使用 ESCAPE_ANY_NP。 + +ESCAPE_ANY_NP是许多情况下的明智选择,特别是对于打印SSID。 + +如果字段宽度被省略,那么将只转义1个字节。 + +原始缓冲区为十六进制字符串 +-------------------------- + +:: + + %*ph 00 01 02 ... 3f + %*phC 00:01:02: ... :3f + %*phD 00-01-02- ... -3f + %*phN 000102 ... 3f + +对于打印小的缓冲区(最长64个字节),可以用一定的分隔符作为一个 +十六进制字符串。对于较大的缓冲区,可以考虑使用 +:c:func:`print_hex_dump` 。 + +MAC/FDDI地址 +------------ + +:: + + %pM 00:01:02:03:04:05 + %pMR 05:04:03:02:01:00 + %pMF 00-01-02-03-04-05 + %pm 000102030405 + %pmR 050403020100 + +用于打印以十六进制表示的6字节MAC/FDDI地址。 ``M`` 和 ``m`` 占位符导致打印的 +地址有(M)或没有(m)字节分隔符。默认的字节分隔符是冒号(:)。 + +对于FDDI地址,可以在 ``M`` 占位符之后使用 ``F`` 说明,以使用破折号(——)分隔符 +代替默认的分隔符。 + +对于蓝牙地址, ``R`` 占位符应使用在 ``M`` 占位符之后,以使用反转的字节顺序,适 +合于以小尾端顺序的蓝牙地址的肉眼可见的解析。 + +通过引用传递。 + +IPv4地址 +-------- + +:: + + %pI4 1.2.3.4 + %pi4 001.002.003.004 + %p[Ii]4[hnbl] + +用于打印IPv4点分隔的十进制地址。 ``I4`` 和 ``i4`` 占位符的结果是打印的地址 +有(i4)或没有(I4)前导零。 + +附加的 ``h`` 、 ``n`` 、 ``b`` 和 ``l`` 占位符分别用于指定主机、网络、大 +尾端或小尾端地址。如果没有提供占位符,则使用默认的网络/大尾端顺序。 + +通过引用传递。 + +IPv6 地址 +--------- + +:: + + %pI6 0001:0002:0003:0004:0005:0006:0007:0008 + %pi6 00010002000300040005000600070008 + %pI6c 1:2:3:4:5:6:7:8 + +用于打印IPv6网络顺序的16位十六进制地址。 ``I6`` 和 ``i6`` 占位符的结果是 +打印的地址有(I6)或没有(i6)分号。始终使用前导零。 + +额外的 ``c`` 占位符可与 ``I`` 占位符一起使用,以打印压缩的IPv6地址,如 +https://tools.ietf.org/html/rfc5952 所述 + +通过引用传递。 + +IPv4/IPv6地址(generic, with port, flowinfo, scope) +-------------------------------------------------- + +:: + + %pIS 1.2.3.4 or 0001:0002:0003:0004:0005:0006:0007:0008 + %piS 001.002.003.004 or 00010002000300040005000600070008 + %pISc 1.2.3.4 or 1:2:3:4:5:6:7:8 + %pISpc 1.2.3.4:12345 or [1:2:3:4:5:6:7:8]:12345 + %p[Ii]S[pfschnbl] + +用于打印一个IP地址,不需要区分它的类型是AF_INET还是AF_INET6。一个指向有效结构 +体sockaddr的指针,通过 ``IS`` 或 ``IS`` 指定,可以传递给这个格式占位符。 + +附加的 ``p`` 、 ``f`` 和 ``s`` 占位符用于指定port(IPv4, IPv6)、 +flowinfo (IPv6)和sope(IPv6)。port有一个 ``:`` 前缀,flowinfo是 ``/`` 和 +范围是 ``%`` ,每个后面都跟着实际的值。 + +对于IPv6地址,如果指定了额外的指定符 ``c`` ,则使用 +https://tools.ietf.org/html/rfc5952 描述的压缩IPv6地址。 +如https://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-07 +所建议的,IPv6地址由'[',']'包围,以防止出现额外的占位符 ``p`` , ``f`` 或 ``s`` 。 + +对于IPv4地址,也可以使用额外的 ``h`` , ``n`` , ``b`` 和 ``l`` 说 +明符,但对于IPv6地址则忽略。 + +通过引用传递。 + +更多例子:: + + %pISfc 1.2.3.4 or [1:2:3:4:5:6:7:8]/123456789 + %pISsc 1.2.3.4 or [1:2:3:4:5:6:7:8]%1234567890 + %pISpfc 1.2.3.4:12345 or [1:2:3:4:5:6:7:8]:12345/123456789 + +UUID/GUID地址 +------------- + +:: + + %pUb 00010203-0405-0607-0809-0a0b0c0d0e0f + %pUB 00010203-0405-0607-0809-0A0B0C0D0E0F + %pUl 03020100-0504-0706-0809-0a0b0c0e0e0f + %pUL 03020100-0504-0706-0809-0A0B0C0E0E0F + +用于打印16字节的UUID/GUIDs地址。附加的 ``l`` , ``L`` , ``b`` 和 ``B`` 占位符用 +于指定小写(l)或大写(L)十六进制表示法中的小尾端顺序,以及小写(b)或大写(B)十六进制表 +示法中的大尾端顺序。 + +如果没有使用额外的占位符,则将打印带有小写十六进制表示法的默认大端顺序。 + +通过引用传递。 + +目录项(dentry)的名称 +---------------------- + +:: + + %pd{,2,3,4} + %pD{,2,3,4} + +用于打印dentry名称;如果我们用 :c:func:`d_move` 和它比较,名称可能是新旧混合的,但 +不会oops。 %pd dentry比较安全,其相当于我们以前用的%s dentry->d_name.name,%pd打 +印 ``n`` 最后的组件。 %pD对结构文件做同样的事情。 + + +通过引用传递。 + +块设备(block_device)名称 +-------------------------- + +:: + + %pg sda, sda1 or loop0p1 + +用于打印block_device指针的名称。 + +va_format结构体 +--------------- + +:: + + %pV + +用于打印结构体va_format。这些结构包含一个格式字符串 +和va_list如下 + +:: + + struct va_format { + const char *fmt; + va_list *va; + }; + +实现 "递归vsnprintf"。 + +如果没有一些机制来验证格式字符串和va_list参数的正确性,请不要使用这个功能。 + +通过引用传递。 + +设备树节点 +---------- + +:: + + %pOF[fnpPcCF] + + +用于打印设备树节点结构。默认行为相当于%pOFf。 + + - f - 设备节点全称 + - n - 设备节点名 + - p - 设备节点句柄 + - P - 设备节点路径规范(名称+@单位) + - F - 设备节点标志 + - c - 主要兼容字符串 + - C - 全兼容字符串 + +当使用多个参数时,分隔符是':'。 + +例如 + +:: + + %pOF /foo/bar@0 - Node full name + %pOFf /foo/bar@0 - Same as above + %pOFfp /foo/bar@0:10 - Node full name + phandle + %pOFfcF /foo/bar@0:foo,device:--P- - Node full name + + major compatible string + + node flags + D - dynamic + d - detached + P - Populated + B - Populated bus + +通过引用传递。 + +Fwnode handles +-------------- + +:: + + %pfw[fP] + +用于打印fwnode_handles的消息。默认情况下是打印完整的节点名称,包括路径。 +这些修饰符在功能上等同于上面的%pOF。 + + - f - 节点的全名,包括路径。 + - P - 节点名称,包括地址(如果有的话)。 + +例如 (ACPI) + +:: + + %pfwf \_SB.PCI0.CIO2.port@1.endpoint@0 - Full node name + %pfwP endpoint@0 - Node name + +例如 (OF) + +:: + + %pfwf /ocp@68000000/i2c@48072000/camera@10/port/endpoint - Full name + %pfwP endpoint - Node name + +时间和日期 +---------- + +:: + + %pt[RT] YYYY-mm-ddTHH:MM:SS + %pt[RT]d YYYY-mm-dd + %pt[RT]t HH:MM:SS + %pt[RT][dt][r] + +用于打印日期和时间:: + + R struct rtc_time structure + T time64_t type + +以我们(人类)可读的格式。 + +默认情况下,年将以1900为单位递增,月将以1为单位递增。 使用%pt[RT]r (raw) +来抑制这种行为。 + +通过引用传递。 + +clk结构体 +--------- + +:: + + %pC pll1 + %pCn pll1 + +用于打印clk结构。%pC 和 %pCn 打印时钟的名称(通用时钟框架)或唯一的32位 +ID(传统时钟框架)。 + +通过引用传递。 + +位图及其衍生物,如cpumask和nodemask +----------------------------------- + +:: + + %*pb 0779 + %*pbl 0,3-6,8-10 + +对于打印位图(bitmap)及其派生的cpumask和nodemask,%*pb输出以字段宽度为位数的位图, +%*pbl输出以字段宽度为位数的范围列表。 + +字段宽度用值传递,位图用引用传递。可以使用辅助宏cpumask_pr_args()和 +nodemask_pr_args()来方便打印cpumask和nodemask。 + +标志位字段,如页标志、gfp_flags +------------------------------- + +:: + + %pGp referenced|uptodate|lru|active|private|node=0|zone=2|lastcpupid=0x1fffff + %pGg GFP_USER|GFP_DMA32|GFP_NOWARN + %pGv read|exec|mayread|maywrite|mayexec|denywrite + +将flags位字段打印为构造值的符号常量集合。标志的类型由第三个字符给出。目前支持的 +是[p]age flags, [v]ma_flags(都期望 ``unsigned long *`` )和 +[g]fp_flags(期望 ``gfp_t *`` )。标志名称和打印顺序取决于特定的类型。 + +注意,这种格式不应该直接用于跟踪点的:c:func:`TP_printk()` 部分。相反,应使 +用 中的show_*_flags()函数。 + +通过引用传递。 + +网络设备特性 +------------ + +:: + + %pNF 0x000000000000c000 + +用于打印netdev_features_t。 + +通过引用传递。 + +V4L2和DRM FourCC代码(像素格式) +------------------------------ + +:: + + %p4cc + +打印V4L2或DRM使用的FourCC代码,包括格式端序及其十六进制的数值。 + +通过引用传递。 + +例如:: + + %p4cc BG12 little-endian (0x32314742) + %p4cc Y10 little-endian (0x20303159) + %p4cc NV12 big-endian (0xb231564e) + +谢谢 +==== + +如果您添加了其他%p扩展,请在可行的情况下,用一个或多个测试用例扩展。 + +谢谢你的合作和关注。 -- cgit v1.3.1 From b345b9ab1d0c7811f96d87cfb87a6cda01624b16 Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Mon, 17 May 2021 21:29:27 +0800 Subject: docs/zh_CN: add core-api workqueue.rst translation This patch translates Documentation/core-api/workqueue.rst into Chinese. Signed-off-by: Yanteng Si Reviewed-by: Alex Shi Link: https://lore.kernel.org/r/20210517132927.3461185-1-siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/core-api/index.rst | 2 +- .../translations/zh_CN/core-api/workqueue.rst | 337 +++++++++++++++++++++ 2 files changed, 338 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/core-api/workqueue.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/core-api/index.rst b/Documentation/translations/zh_CN/core-api/index.rst index c2d4614d9e68..34be9b25cfa1 100644 --- a/Documentation/translations/zh_CN/core-api/index.rst +++ b/Documentation/translations/zh_CN/core-api/index.rst @@ -25,9 +25,9 @@ kernel-api printk-basics printk-formats + workqueue Todolist: - workqueue symbol-namespaces 数据结构和低级实用程序 diff --git a/Documentation/translations/zh_CN/core-api/workqueue.rst b/Documentation/translations/zh_CN/core-api/workqueue.rst new file mode 100644 index 000000000000..0b8f730db6c0 --- /dev/null +++ b/Documentation/translations/zh_CN/core-api/workqueue.rst @@ -0,0 +1,337 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/core-api/workqueue.rst +:Translator: Yanteng Si + +.. _cn_workqueue.rst: + + +========================= +并发管理的工作队列 (cmwq) +========================= + +:日期: September, 2010 +:作者: Tejun Heo +:作者: Florian Mickler + + +简介 +==== + +在很多情况下,需要一个异步进程的执行环境,工作队列(wq)API是这种情况下 +最常用的机制。 + +当需要这样一个异步执行上下文时,一个描述将要执行的函数的工作项(work, +即一个待执行的任务)被放在队列中。一个独立的线程作为异步执行环境。该队 +列被称为workqueue,线程被称为工作者(worker,即执行这一队列的线程)。 + +当工作队列上有工作项时,工作者会一个接一个地执行与工作项相关的函数。当 +工作队列中没有任何工作项时,工作者就会变得空闲。当一个新的工作项被排入 +队列时,工作者又开始执行。 + + +为什么要cmwq? +============= + +在最初的wq实现中,多线程(MT)wq在每个CPU上有一个工作者线程,而单线程 +(ST)wq在全系统有一个工作者线程。一个MT wq需要保持与CPU数量相同的工 +作者数量。这些年来,内核增加了很多MT wq的用户,随着CPU核心数量的不断 +增加,一些系统刚启动就达到了默认的32k PID的饱和空间。 + +尽管MT wq浪费了大量的资源,但所提供的并发性水平却不能令人满意。这个限 +制在ST和MT wq中都有,只是在MT中没有那么严重。每个wq都保持着自己独立的 +工作者池。一个MT wq只能为每个CPU提供一个执行环境,而一个ST wq则为整个 +系统提供一个。工作项必须竞争这些非常有限的执行上下文,从而导致各种问题, +包括在单一执行上下文周围容易发生死锁。 + +(MT wq)所提供的并发性水平和资源使用之间的矛盾也迫使其用户做出不必要的权衡,比 +如libata选择使用ST wq来轮询PIO,并接受一个不必要的限制,即没有两个轮 +询PIO可以同时进行。由于MT wq并没有提供更好的并发性,需要更高层次的并 +发性的用户,如async或fscache,不得不实现他们自己的线程池。 + +并发管理工作队列(cmwq)是对wq的重新实现,重点是以下目标。 + +* 保持与原始工作队列API的兼容性。 + +* 使用由所有wq共享的每CPU统一的工作者池,在不浪费大量资源的情况下按 +* 需提供灵活的并发水平。 + +* 自动调节工作者池和并发水平,使API用户不需要担心这些细节。 + + +设计 +==== + +为了简化函数的异步执行,引入了一个新的抽象概念,即工作项。 + +一个工作项是一个简单的结构,它持有一个指向将被异步执行的函数的指针。 +每当一个驱动程序或子系统希望一个函数被异步执行时,它必须建立一个指 +向该函数的工作项,并在工作队列中排队等待该工作项。(就是挂到workqueue +队列里面去) + +特定目的线程,称为工作线程(工作者),一个接一个地执行队列中的功能。 +如果没有工作项排队,工作者线程就会闲置。这些工作者线程被管理在所谓 +的工作者池中。 + +cmwq设计区分了面向用户的工作队列,子系统和驱动程序在上面排队工作, +以及管理工作者池和处理排队工作项的后端机制。 + +每个可能的CPU都有两个工作者池,一个用于正常的工作项,另一个用于高 +优先级的工作项,还有一些额外的工作者池,用于服务未绑定工作队列的工 +作项目——这些后备池的数量是动态的。 + +当他们认为合适的时候,子系统和驱动程序可以通过特殊的 +``workqueue API`` 函数创建和排队工作项。他们可以通过在工作队列上 +设置标志来影响工作项执行方式的某些方面,他们把工作项放在那里。这些 +标志包括诸如CPU定位、并发限制、优先级等等。要获得详细的概述,请参 +考下面的 ``alloc_workqueue()`` 的 API 描述。 + +当一个工作项被排入一个工作队列时,目标工作池将根据队列参数和工作队 +列属性确定,并被附加到工作池的共享工作列表上。例如,除非特别重写, +否则一个绑定的工作队列的工作项将被排在与发起线程运行的CPU相关的普 +通或高级工作工作者池的工作项列表中。 + +对于任何工作者池的实施,管理并发水平(有多少执行上下文处于活动状 +态)是一个重要问题。最低水平是为了节省资源,而饱和水平是指系统被 +充分使用。 + +每个与实际CPU绑定的worker-pool通过钩住调度器来实现并发管理。每当 +一个活动的工作者被唤醒或睡眠时,工作者池就会得到通知,并跟踪当前可 +运行的工作者的数量。一般来说,工作项不会占用CPU并消耗很多周期。这 +意味着保持足够的并发性以防止工作处理停滞应该是最优的。只要CPU上有 +一个或多个可运行的工作者,工作者池就不会开始执行新的工作,但是,当 +最后一个运行的工作者进入睡眠状态时,它会立即安排一个新的工作者,这 +样CPU就不会在有待处理的工作项目时闲置。这允许在不损失执行带宽的情 +况下使用最少的工作者。 + +除了kthreads的内存空间外,保留空闲的工作者并没有其他成本,所以cmwq +在杀死它们之前会保留一段时间的空闲。 + +对于非绑定的工作队列,后备池的数量是动态的。可以使用 +``apply_workqueue_attrs()`` 为非绑定工作队列分配自定义属性, +workqueue将自动创建与属性相匹配的后备工作者池。调节并发水平的责任在 +用户身上。也有一个标志可以将绑定的wq标记为忽略并发管理。 +详情请参考API部分。 + +前进进度的保证依赖于当需要更多的执行上下文时可以创建工作者,这也是 +通过使用救援工作者来保证的。所有可能在处理内存回收的代码路径上使用 +的工作项都需要在wq上排队,wq上保留了一个救援工作者,以便在内存有压 +力的情况下下执行。否则,工作者池就有可能出现死锁,等待执行上下文释 +放出来。 + + +应用程序编程接口 (API) +====================== + +``alloc_workqueue()`` 分配了一个wq。原来的 ``create_*workqueue()`` +函数已被废弃,并计划删除。 ``alloc_workqueue()`` 需要三个 +参数 - ``@name`` , ``@flags`` 和 ``@max_active`` 。 +``@name`` 是wq的名称,如果有的话,也用作救援线程的名称。 + +一个wq不再管理执行资源,而是作为前进进度保证、刷新(flush)和 +工作项属性的域。 ``@flags`` 和 ``@max_active`` 控制着工作 +项如何被分配执行资源、安排和执行。 + + +``flags`` +--------- + +``WQ_UNBOUND`` + 排队到非绑定wq的工作项由特殊的工作者池提供服务,这些工作者不 + 绑定在任何特定的CPU上。这使得wq表现得像一个简单的执行环境提 + 供者,没有并发管理。非绑定工作者池试图尽快开始执行工作项。非 + 绑定的wq牺牲了局部性,但在以下情况下是有用的。 + + * 预计并发水平要求会有很大的波动,使用绑定的wq最终可能会在不 + 同的CPU上产生大量大部分未使用的工作者,因为发起线程在不同 + 的CPU上跳转。 + + * 长期运行的CPU密集型工作负载,可以由系统调度器更好地管理。 + +``WQ_FREEZABLE`` + 一个可冻结的wq参与了系统暂停操作的冻结阶段。wq上的工作项被 + 排空,在解冻之前没有新的工作项开始执行。 + +``WQ_MEM_RECLAIM`` + 所有可能在内存回收路径中使用的wq都必须设置这个标志。无论内 + 存压力如何,wq都能保证至少有一个执行上下文。 + +``WQ_HIGHPRI`` + 高优先级wq的工作项目被排到目标cpu的高优先级工作者池中。高 + 优先级的工作者池由具有较高级别的工作者线程提供服务。 + + 请注意,普通工作者池和高优先级工作者池之间并不相互影响。他 + 们各自维护其独立的工作者池,并在其工作者之间实现并发管理。 + +``WQ_CPU_INTENSIVE`` + CPU密集型wq的工作项对并发水平没有贡献。换句话说,可运行的 + CPU密集型工作项不会阻止同一工作者池中的其他工作项开始执行。 + 这对于那些预计会占用CPU周期的绑定工作项很有用,这样它们的 + 执行就会受到系统调度器的监管。 + + 尽管CPU密集型工作项不会对并发水平做出贡献,但它们的执行开 + 始仍然受到并发管理的管制,可运行的非CPU密集型工作项会延迟 + CPU密集型工作项的执行。 + + 这个标志对于未绑定的wq来说是没有意义的。 + +请注意,标志 ``WQ_NON_REENTRANT`` 不再存在,因为现在所有的工作 +队列都是不可逆的——任何工作项都保证在任何时间内最多被整个系统的一 +个工作者执行。 + + +``max_active`` +-------------- + +``@max_active`` 决定了每个CPU可以分配给wq的工作项的最大执行上 +下文数量。例如,如果 ``@max_active为16`` ,每个CPU最多可以同 +时执行16个wq的工作项。 + +目前,对于一个绑定的wq, ``@max_active`` 的最大限制是512,当指 +定为0时使用的默认值是256。对于非绑定的wq,其限制是512和 +4 * ``num_possible_cpus()`` 中的较高值。这些值被选得足够高,所 +以它们不是限制性因素,同时会在失控情况下提供保护。 + +一个wq的活动工作项的数量通常由wq的用户来调节,更具体地说,是由用 +户在同一时间可以排列多少个工作项来调节。除非有特定的需求来控制活动 +工作项的数量,否则建议指定 为"0"。 + +一些用户依赖于ST wq的严格执行顺序。 ``@max_active`` 为1和 ``WQ_UNBOUND`` +的组合用来实现这种行为。这种wq上的工作项目总是被排到未绑定的工作池 +中,并且在任何时候都只有一个工作项目处于活动状态,从而实现与ST wq相 +同的排序属性。 + +在目前的实现中,上述配置只保证了特定NUMA节点内的ST行为。相反, +``alloc_ordered_queue()`` 应该被用来实现全系统的ST行为。 + + +执行场景示例 +============ + +下面的示例执行场景试图说明cmwq在不同配置下的行为。 + + 工作项w0、w1、w2被排到同一个CPU上的一个绑定的wq q0上。w0 + 消耗CPU 5ms,然后睡眠10ms,然后在完成之前再次消耗CPU 5ms。 + +忽略所有其他的任务、工作和处理开销,并假设简单的FIFO调度, +下面是一个高度简化的原始wq的可能事件序列的版本。:: + + TIME IN MSECS EVENT + 0 w0 starts and burns CPU + 5 w0 sleeps + 15 w0 wakes up and burns CPU + 20 w0 finishes + 20 w1 starts and burns CPU + 25 w1 sleeps + 35 w1 wakes up and finishes + 35 w2 starts and burns CPU + 40 w2 sleeps + 50 w2 wakes up and finishes + +And with cmwq with ``@max_active`` >= 3, :: + + TIME IN MSECS EVENT + 0 w0 starts and burns CPU + 5 w0 sleeps + 5 w1 starts and burns CPU + 10 w1 sleeps + 10 w2 starts and burns CPU + 15 w2 sleeps + 15 w0 wakes up and burns CPU + 20 w0 finishes + 20 w1 wakes up and finishes + 25 w2 wakes up and finishes + +如果 ``@max_active`` == 2, :: + + TIME IN MSECS EVENT + 0 w0 starts and burns CPU + 5 w0 sleeps + 5 w1 starts and burns CPU + 10 w1 sleeps + 15 w0 wakes up and burns CPU + 20 w0 finishes + 20 w1 wakes up and finishes + 20 w2 starts and burns CPU + 25 w2 sleeps + 35 w2 wakes up and finishes + +现在,我们假设w1和w2被排到了不同的wq q1上,这个wq q1 +有 ``WQ_CPU_INTENSIVE`` 设置:: + + TIME IN MSECS EVENT + 0 w0 starts and burns CPU + 5 w0 sleeps + 5 w1 and w2 start and burn CPU + 10 w1 sleeps + 15 w2 sleeps + 15 w0 wakes up and burns CPU + 20 w0 finishes + 20 w1 wakes up and finishes + 25 w2 wakes up and finishes + + +指南 +==== + +* 如果一个wq可能处理在内存回收期间使用的工作项目,请不 + 要忘记使用 ``WQ_MEM_RECLAIM`` 。每个设置了 + ``WQ_MEM_RECLAIM`` 的wq都有一个为其保留的执行环境。 + 如果在内存回收过程中使用的多个工作项之间存在依赖关系, + 它们应该被排在不同的wq中,每个wq都有 ``WQ_MEM_RECLAIM`` 。 + +* 除非需要严格排序,否则没有必要使用ST wq。 + +* 除非有特殊需要,建议使用0作为@max_active。在大多数使用情 + 况下,并发水平通常保持在默认限制之下。 + +* 一个wq作为前进进度保证(WQ_MEM_RECLAIM,冲洗(flush)和工 + 作项属性的域。不涉及内存回收的工作项,不需要作为工作项组的一 + 部分被刷新,也不需要任何特殊属性,可以使用系统中的一个wq。使 + 用专用wq和系统wq在执行特性上没有区别。 + +* 除非工作项预计会消耗大量的CPU周期,否则使用绑定的wq通常是有 + 益的,因为wq操作和工作项执行中的定位水平提高了。 + + +调试 +==== + +因为工作函数是由通用的工作者线程执行的,所以需要一些手段来揭示一些行为不端的工作队列用户。 + +工作者线程在进程列表中显示为: :: + + root 5671 0.0 0.0 0 0 ? S 12:07 0:00 [kworker/0:1] + root 5672 0.0 0.0 0 0 ? S 12:07 0:00 [kworker/1:2] + root 5673 0.0 0.0 0 0 ? S 12:12 0:00 [kworker/0:0] + root 5674 0.0 0.0 0 0 ? S 12:13 0:00 [kworker/1:0] + +如果kworkers失控了(使用了太多的cpu),有两类可能的问题: + + 1. 正在迅速调度的事情 + 2. 一个消耗大量cpu周期的工作项。 + +第一个可以用追踪的方式进行跟踪: :: + + $ echo workqueue:workqueue_queue_work > /sys/kernel/debug/tracing/set_event + $ cat /sys/kernel/debug/tracing/trace_pipe > out.txt + (wait a few secs) + +如果有什么东西在工作队列上忙着做循环,它就会主导输出,可以用工作项函数确定违规者。 + +对于第二类问题,应该可以只检查违规工作者线程的堆栈跟踪。 :: + + $ cat /proc/THE_OFFENDING_KWORKER/stack + +工作项函数在堆栈追踪中应该是微不足道的。 + + +内核内联文档参考 +================ + +该API在以下内核代码中: + +include/linux/workqueue.h + +kernel/workqueue.c -- cgit v1.3.1 From 6586f2d8cec186ef0af7cf6a0738293fea048ed8 Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Mon, 17 May 2021 21:37:48 +0800 Subject: docs/zh_CN: add core api kobject translation This patch translates Documentation/core-api/kobject.rst into Chinese. Signed-off-by: Yanteng Si Reviewed-by: Alex Shi Reviewed-by: Wu XiangCheng Link: https://lore.kernel.org/r/20210517133748.3461357-1-siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/core-api/index.rst | 6 +- .../translations/zh_CN/core-api/kobject.rst | 378 +++++++++++++++++++++ 2 files changed, 383 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/core-api/kobject.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/core-api/index.rst b/Documentation/translations/zh_CN/core-api/index.rst index 34be9b25cfa1..a1dd792e46f7 100644 --- a/Documentation/translations/zh_CN/core-api/index.rst +++ b/Documentation/translations/zh_CN/core-api/index.rst @@ -35,9 +35,13 @@ Todolist: 在整个内核中使用的函数库。 -Todolist: +.. toctree:: + :maxdepth: 1 kobject + +Todolist: + kref assoc_array xarray diff --git a/Documentation/translations/zh_CN/core-api/kobject.rst b/Documentation/translations/zh_CN/core-api/kobject.rst new file mode 100644 index 000000000000..f0e6a4aeb372 --- /dev/null +++ b/Documentation/translations/zh_CN/core-api/kobject.rst @@ -0,0 +1,378 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/core-api/kobject.rst +:Translator: Yanteng Si + +.. _cn_core_api_kobject.rst: + +======================================================= +关于kobjects、ksets和ktypes的一切你没想过需要了解的东西 +======================================================= + +:作者: Greg Kroah-Hartman +:最后一次更新: December 19, 2007 + +根据Jon Corbet于2003年10月1日为lwn.net撰写的原创文章改编,网址是: +https://lwn.net/Articles/51437/ + +理解驱动模型和建立在其上的kobject抽象的部分的困难在于,没有明显的切入点。 +处理kobjects需要理解一些不同的类型,所有这些类型都会相互引用。为了使事情 +变得更简单,我们将多路并进,从模糊的术语开始,并逐渐增加细节。那么,先来 +了解一些我们将要使用的术语的简明定义吧。 + + - 一个kobject是一个kobject结构体类型的对象。Kobjects有一个名字和一个 + 引用计数。一个kobject也有一个父指针(允许对象被排列成层次结构),一个 + 特定的类型,并且,通常在sysfs虚拟文件系统中表示。 + + Kobjects本身通常并不引人关注;相反它们常常被嵌入到其他包含真正引人注目 + 的代码的结构体中。 + + 任何结构体都 **不应该** 有一个以上的kobject嵌入其中。如果有的话,对象的引用计 + 数肯定会被打乱,而且不正确,你的代码就会出现错误。所以不要这样做。 + + - ktype是嵌入一个kobject的对象的类型。每个嵌入kobject的结构体都需要一个 + 相应的ktype。ktype控制着kobject在被创建和销毁时的行为。 + + - 一个kset是一组kobjects。这些kobjects可以是相同的ktype或者属于不同的 + ktype。kset是kobjects集合的基本容器类型。Ksets包含它们自己的kobjects, + 但你可以安全地忽略这个实现细节,因为kset的核心代码会自动处理这个kobject。 + + 当你看到一个下面全是其他目录的sysfs目录时,通常这些目录中的每一个都对应 + 于同一个kset中的一个kobject。 + + 我们将研究如何创建和操作所有这些类型。将采取一种自下而上的方法,所以我们 + 将回到kobjects。 + + +嵌入kobjects +============= + +内核代码很少创建孤立的kobject,只有一个主要的例外,下面会解释。相反, +kobjects被用来控制对一个更大的、特定领域的对象的访问。为此,kobjects会被 +嵌入到其他结构中。如果你习惯于用面向对象的术语来思考问题,那么kobjects可 +以被看作是一个顶级的抽象类,其他的类都是从它派生出来的。一个kobject实现了 +一系列的功能,这些功能本身并不特别有用,但在其他对象中却很好用。C语言不允 +许直接表达继承,所以必须使用其他技术——比如结构体嵌入。 + +(对于那些熟悉内核链表实现的人来说,这类似于“list_head”结构本身很少有用, +但总是被嵌入到感兴趣的更大的对象中)。 + +例如, ``drivers/uio/uio.c`` 中的IO代码有一个结构体,定义了与uio设备相 +关的内存区域:: + + struct uio_map { + struct kobject kobj; + struct uio_mem *mem; + }; + +如果你有一个uio_map结构体,找到其嵌入的kobject只是一个使用kobj成员的问题。 +然而,与kobjects一起工作的代码往往会遇到相反的问题:给定一个结构体kobject +的指针,指向包含结构体的指针是什么?你必须避免使用一些技巧(比如假设 +kobject在结构的开头),相反,你得使用container_of()宏,其可以在 ```` +中找到:: + + container_of(ptr, type, member) + +其中: + + * ``ptr`` 是一个指向嵌入kobject的指针, + * ``type`` 是包含结构体的类型, + * ``member`` 是 ``指针`` 所指向的结构体域的名称。 + +container_of()的返回值是一个指向相应容器类型的指针。因此,例如,一个嵌入到 +uio_map结构 **中** 的kobject结构体的指针kp可以被转换为一个指向 **包含** uio_map +结构体的指针,方法是:: + + struct uio_map *u_map = container_of(kp, struct uio_map, kobj); + +为了方便起见,程序员经常定义一个简单的宏,用于将kobject指针 **反推** 到包含 +类型。在早期的 ``drivers/uio/uio.c`` 中正是如此,你可以在这里看到:: + + struct uio_map { + struct kobject kobj; + struct uio_mem *mem; + }; + + #define to_map(map) container_of(map, struct uio_map, kobj) + +其中宏的参数“map”是一个指向有关的kobject结构体的指针。该宏随后被调用:: + + struct uio_map *map = to_map(kobj); + + +kobjects的初始化 +================ + +当然,创建kobject的代码必须初始化该对象。一些内部字段是通过(强制)调用kobject_init() +来设置的:: + + void kobject_init(struct kobject *kobj, struct kobj_type *ktype); + +ktype是正确创建kobject的必要条件,因为每个kobject都必须有一个相关的kobj_type。 +在调用kobject_init()后,为了向sysfs注册kobject,必须调用函数kobject_add():: + + int kobject_add(struct kobject *kobj, struct kobject *parent, + const char *fmt, ...); + +这将正确设置kobject的父级和kobject的名称。如果该kobject要与一个特定的kset相关 +联,在调用kobject_add()之前必须分配kobj->kset。如果kset与kobject相关联,则 +kobject的父级可以在调用kobject_add()时被设置为NULL,则kobject的父级将是kset +本身。 + +由于kobject的名字是在它被添加到内核时设置的,所以kobject的名字不应该被直接操作。 +如果你必须改变kobject的名字,请调用kobject_rename():: + + int kobject_rename(struct kobject *kobj, const char *new_name); + +kobject_rename()函数不会执行任何锁定操作,也不会对name进行可靠性检查,所以调用 +者自己检查和串行化操作是明智的选择 + +有一个叫kobject_set_name()的函数,但那是历史遗产,正在被删除。如果你的代码需 +要调用这个函数,那么它是不正确的,需要被修复。 + +要正确访问kobject的名称,请使用函数kobject_name():: + + const char *kobject_name(const struct kobject * kobj); + +有一个辅助函数可以同时初始化和添加kobject到内核中,令人惊讶的是,该函数被称为 +kobject_init_and_add():: + + int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, + struct kobject *parent, const char *fmt, ...); + +参数与上面描述的单个kobject_init()和kobject_add()函数相同。 + + +Uevents +======= + +当一个kobject被注册到kobject核心后,你需要向全世界宣布它已经被创建了。这可以通 +过调用kobject_uevent()来实现:: + + int kobject_uevent(struct kobject *kobj, enum kobject_action action); + +当kobject第一次被添加到内核时,使用 *KOBJ_ADD* 动作。这应该在该kobject的任 +何属性或子对象被正确初始化后进行,因为当这个调用发生时,用户空间会立即开始寻 +找它们。 + +当kobject从内核中移除时(关于如何做的细节在下面), **KOBJ_REMOVE** 的uevent +将由kobject核心自动创建,所以调用者不必担心手动操作。 + + +引用计数 +======== + +kobject的关键功能之一是作为它所嵌入的对象的一个引用计数器。只要对该对象的引用 +存在,该对象(以及支持它的代码)就必须继续存在。用于操作kobject的引用计数的低 +级函数是:: + + struct kobject *kobject_get(struct kobject *kobj); + void kobject_put(struct kobject *kobj); + +对kobject_get()的成功调用将增加kobject的引用计数器值并返回kobject的指针。 + +当引用被释放时,对kobject_put()的调用将递减引用计数值,并可能释放该对象。请注 +意,kobject_init()将引用计数设置为1,所以设置kobject的代码最终需要kobject_put() +来释放该引用。 + +因为kobjects是动态的,所以它们不能以静态方式或在堆栈中声明,而总是以动态方式分 +配。未来版本的内核将包含对静态创建的kobjects的运行时检查,并将警告开发者这种不 +当的使用。 + +如果你使用struct kobject只是为了给你的结构体提供一个引用计数器,请使用struct kref +来代替;kobject是多余的。关于如何使用kref结构体的更多信息,请参见Linux内核源代 +码树中的文件Documentation/core-api/kref.rst + + +创建“简单的”kobjects +==================== + +有时,开发者想要的只是在sysfs层次结构中创建一个简单的目录,而不必去搞那些复杂 +的ksets、显示和存储函数,以及其他细节。这是一个应该创建单个kobject的例外。要 +创建这样一个条目(即简单的目录),请使用函数:: + + struct kobject *kobject_create_and_add(const char *name, struct kobject *parent); + +这个函数将创建一个kobject,并将其放在sysfs中指定的父kobject下面的位置。要创 +建与此kobject相关的简单属性,请使用:: + + int sysfs_create_file(struct kobject *kobj, const struct attribute *attr); + +或者:: + + int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp); + +这里使用的两种类型的属性,与已经用kobject_create_and_add()创建的kobject, +都可以是kobj_attribute类型,所以不需要创建特殊的自定义属性。 + +参见示例模块, ``samples/kobject/kobject-example.c`` ,以了解一个简单的 +kobject和属性的实现。 + + + +ktypes和释放方法 +================ + +以上讨论中还缺少一件重要的事情,那就是当一个kobject的引用次数达到零的时候 +会发生什么。创建kobject的代码通常不知道何时会发生这种情况;首先,如果它知 +道,那么使用kobject就没有什么意义。当sysfs被引入时,即使是可预测的对象生命 +周期也会变得更加复杂,因为内核的其他部分可以获得在系统中注册的任何kobject +的引用。 + +最终的结果是,一个由kobject保护的结构体在其引用计数归零之前不能被释放。引 +用计数不受创建kobject的代码的直接控制。因此,每当它的一个kobjects的最后一 +个引用消失时,必须异步通知该代码。 + +一旦你通过kobject_add()注册了你的kobject,你绝对不能使用kfree()来直接释 +放它。唯一安全的方法是使用kobject_put()。在kobject_init()之后总是使用 +kobject_put()以避免错误的发生是一个很好的做法。 + +这个通知是通过kobject的release()方法完成的。通常这样的方法有如下形式:: + + void my_object_release(struct kobject *kobj) + { + struct my_object *mine = container_of(kobj, struct my_object, kobj); + + /* Perform any additional cleanup on this object, then... */ + kfree(mine); + } + +有一点很重要:每个kobject都必须有一个release()方法,而且这个kobject必 +须持续存在(处于一致的状态),直到这个方法被调用。如果这些约束条件没有 +得到满足,那么代码就是有缺陷的。注意,如果你忘记提供release()方法,内 +核会警告你。不要试图通过提供一个“空”的释放函数来摆脱这个警告。 + +如果你的清理函数只需要调用kfree(),那么你必须创建一个包装函数,该函数 +使用container_of()来向上造型到正确的类型(如上面的例子所示),然后在整个 +结构体上调用kfree()。 + +注意,kobject的名字在release函数中是可用的,但它不能在这个回调中被改 +变。否则,在kobject核心中会出现内存泄漏,这让人很不爽。 + +有趣的是,release()方法并不存储在kobject本身;相反,它与ktype相关。 +因此,让我们引入结构体kobj_type:: + + struct kobj_type { + void (*release)(struct kobject *kobj); + const struct sysfs_ops *sysfs_ops; + struct attribute **default_attrs; + const struct attribute_group **default_groups; + const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj); + const void *(*namespace)(struct kobject *kobj); + void (*get_ownership)(struct kobject *kobj, kuid_t *uid, kgid_t *gid); + }; + +这个结构提用来描述一个特定类型的kobject(或者更正确地说,包含对象的 +类型)。每个kobject都需要有一个相关的kobj_type结构;当你调用 +kobject_init()或kobject_init_and_add()时必须指定一个指向该结构的 +指针。 + +当然,kobj_type结构中的release字段是指向这种类型的kobject的release() +方法的一个指针。另外两个字段(sysfs_ops 和 default_attrs)控制这种 +类型的对象如何在 sysfs 中被表示;它们超出了本文的范围。 + +default_attrs 指针是一个默认属性的列表,它将为任何用这个 ktype 注册 +的 kobject 自动创建。 + + +ksets +===== + +一个kset仅仅是一个希望相互关联的kobjects的集合。没有限制它们必须是相 +同的ktype,但是如果它们不是相同的,就要非常小心。 + +一个kset有以下功能: + + - 它像是一个包含一组对象的袋子。一个kset可以被内核用来追踪“所有块 + 设备”或“所有PCI设备驱动”。 + + - kset也是sysfs中的一个子目录,与kset相关的kobjects可以在这里显示 + 出来。每个kset都包含一个kobject,它可以被设置为其他kobject的父对象; + sysfs层次结构的顶级目录就是以这种方式构建的。 + + - Ksets可以支持kobjects的 "热插拔",并影响uevent事件如何被报告给 + 用户空间。 + + 在面向对象的术语中,“kset”是顶级的容器类;ksets包含它们自己的kobject, + 但是这个kobject是由kset代码管理的,不应该被任何其他用户所操纵。 + + kset在一个标准的内核链表中保存它的子对象。Kobjects通过其kset字段指向其 + 包含的kset。在几乎所有的情况下,属于一个kset的kobjects在它们的父 + 对象中都有那个kset(或者,严格地说,它的嵌入kobject)。 + + 由于kset中包含一个kobject,它应该总是被动态地创建,而不是静态地 + 或在堆栈中声明。要创建一个新的kset,请使用:: + + struct kset *kset_create_and_add(const char *name, + const struct kset_uevent_ops *uevent_ops, + struct kobject *parent_kobj); + +当你完成对kset的处理后,调用:: + + void kset_unregister(struct kset *k); + +来销毁它。这将从sysfs中删除该kset并递减其引用计数值。当引用计数 +为零时,该kset将被释放。因为对该kset的其他引用可能仍然存在, +释放可能发生在kset_unregister()返回之后。 + +一个使用kset的例子可以在内核树中的 ``samples/kobject/kset-example.c`` +文件中看到。 + +如果一个kset希望控制与它相关的kobjects的uevent操作,它可以使用 +结构体kset_uevent_ops来处理它:: + + struct kset_uevent_ops { + int (* const filter)(struct kset *kset, struct kobject *kobj); + const char *(* const name)(struct kset *kset, struct kobject *kobj); + int (* const uevent)(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env); + }; + + +过滤器函数允许kset阻止一个特定kobject的uevent被发送到用户空间。 +如果该函数返回0,该uevent将不会被发射出去。 + +name函数将被调用以覆盖uevent发送到用户空间的kset的默认名称。默 +认情况下,该名称将与kset本身相同,但这个函数,如果存在,可以覆盖 +该名称。 + +当uevent即将被发送至用户空间时,uevent函数将被调用,以允许更多 +的环境变量被添加到uevent中。 + +有人可能会问,鉴于没有提出执行该功能的函数,究竟如何将一个kobject +添加到一个kset中。答案是这个任务是由kobject_add()处理的。当一个 +kobject被传递给kobject_add()时,它的kset成员应该指向这个kobject +所属的kset。 kobject_add()将处理剩下的部分。 + +如果属于一个kset的kobject没有父kobject集,它将被添加到kset的目 +录中。并非所有的kset成员都必须住在kset目录中。如果在添加kobject +之前分配了一个明确的父kobject,那么该kobject将被注册到kset中, +但是被添加到父kobject下面。 + + +移除Kobject +=========== + +当一个kobject在kobject核心注册成功后,在代码使用完它时,必须将其 +清理掉。要做到这一点,请调用kobject_put()。通过这样做,kobject核 +心会自动清理这个kobject分配的所有内存。如果为这个对象发送了 ``KOBJ_ADD`` +uevent,那么相应的 ``KOBJ_REMOVE`` uevent也将被发送,任何其他的 +sysfs内务将被正确处理。 + +如果你需要分两次对kobject进行删除(比如说在你要销毁对象时无权睡眠), +那么调用kobject_del()将从sysfs中取消kobject的注册。这使得kobject +“不可见”,但它并没有被清理掉,而且该对象的引用计数仍然是一样的。在稍 +后的时间调用kobject_put()来完成与该kobject相关的内存的清理。 + +kobject_del()可以用来放弃对父对象的引用,如果循环引用被构建的话。 +在某些情况下,一个父对象引用一个子对象是有效的。循环引用必须通过明 +确调用kobject_del()来打断,这样一个释放函数就会被调用,前一个循环 +中的对象会相互释放。 + + +示例代码出处 +============ + +关于正确使用ksets和kobjects的更完整的例子,请参见示例程序 +``samples/kobject/{kobject-example.c,kset-example.c}`` ,如果 +您选择 ``CONFIG_SAMPLE_KOBJECT`` ,它们将被构建为可加载模块。 -- cgit v1.3.1 From 35f1fceaa288ee0954ced2d740b95211aef4cc80 Mon Sep 17 00:00:00 2001 From: Chun-Hung Tseng Date: Sun, 16 May 2021 18:59:55 +0800 Subject: Documentation: scheduler: fixed 2 typos in sched-nice-design.rst This patch fixed 2 spelling errors in the documentation. Signed-off-by: Chun-Hung Tseng Link: https://lore.kernel.org/r/20210516105955.120651-1-henrybear327@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/scheduler/sched-nice-design.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/scheduler/sched-nice-design.rst b/Documentation/scheduler/sched-nice-design.rst index 0571f1b47e64..889bf2b737dc 100644 --- a/Documentation/scheduler/sched-nice-design.rst +++ b/Documentation/scheduler/sched-nice-design.rst @@ -60,7 +60,7 @@ within the constraints of HZ and jiffies and their nasty design level coupling to timeslices and granularity it was not really viable. The second (less frequent but still periodically occurring) complaint -about Linux's nice level support was its assymetry around the origo +about Linux's nice level support was its asymmetry around the origin (which you can see demonstrated in the picture above), or more accurately: the fact that nice level behavior depended on the _absolute_ nice level as well, while the nice API itself is fundamentally -- cgit v1.3.1 From 4710ccc52e8e504a5617a889843a18cd06f1ab72 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 10 May 2021 15:35:14 -0500 Subject: dt-bindings: media: renesas,drif: Use graph schema Convert the renesas,drif binding schema to use the graph schema. The binding referred to video-interfaces.txt, but it doesn't actually use any properties from it as 'sync-active' is a custom property. As 'sync-active' is custom, it needs a type definition. Cc: Mauro Carvalho Chehab Cc: Ramesh Shanmugasundaram Cc: linux-media@vger.kernel.org Cc: linux-renesas-soc@vger.kernel.org Signed-off-by: Rob Herring Reviewed-by: Fabrizio Castro Link: https://lore.kernel.org/r/20210510203514.603471-1-robh@kernel.org --- .../devicetree/bindings/media/renesas,drif.yaml | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/renesas,drif.yaml b/Documentation/devicetree/bindings/media/renesas,drif.yaml index f1bdaeab4053..ce505a7c006a 100644 --- a/Documentation/devicetree/bindings/media/renesas,drif.yaml +++ b/Documentation/devicetree/bindings/media/renesas,drif.yaml @@ -99,32 +99,26 @@ properties: Indicates that the channel acts as primary among the bonded channels. port: - type: object + $ref: /schemas/graph.yaml#/properties/port + unevaluatedProperties: false description: - Child port node corresponding to the data input, in accordance with the - video interface bindings defined in - Documentation/devicetree/bindings/media/video-interfaces.txt. - The port node must contain at least one endpoint. + Child port node corresponding to the data input. The port node must + contain at least one endpoint. properties: endpoint: - type: object + $ref: /schemas/graph.yaml#/$defs/endpoint-base + unevaluatedProperties: false properties: - remote-endpoint: - description: - A phandle to the remote tuner endpoint subnode in remote node - port. - sync-active: + $ref: /schemas/types.yaml#/definitions/uint32 enum: [0, 1] description: Indicates sync signal polarity, 0/1 for low/high respectively. This property maps to SYNCAC bit in the hardware manual. The default is 1 (active high). - additionalProperties: false - required: - compatible - reg -- cgit v1.3.1 From c17611592d9635c443bedc9be901f4463f45c6d5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 10 May 2021 15:45:24 -0500 Subject: dt-bindings: More removals of type references on common properties Users of common properties shouldn't have a type definition as the common schemas already have one. A few new ones slipped in and *-names was missed in the last clean-up pass. Drop all the unnecessary type references in the tree. A meta-schema update to catch these is pending. Cc: Stephen Boyd Cc: Olivier Moysan Cc: Arnaud Pouliquen Cc: Lars-Peter Clausen Cc: Dmitry Torokhov Cc: Bjorn Andersson Cc: "David S. Miller" Cc: Jakub Kicinski Cc: Orson Zhai Cc: Baolin Wang Cc: Chunyan Zhang Cc: Liam Girdwood Cc: Fabrice Gasnier Cc: Odelu Kukatla Cc: Alex Elder Cc: Shengjiu Wang Cc: linux-clk@vger.kernel.org Cc: alsa-devel@alsa-project.org Cc: linux-iio@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-input@vger.kernel.org Cc: linux-pm@vger.kernel.org Cc: netdev@vger.kernel.org Signed-off-by: Rob Herring Acked-by: Mark Brown Acked-by: Georgi Djakov Reviewed-by: Luca Ceresoli Acked-by: Jonathan Cameron Acked-by: Sebastian Reichel Link: https://lore.kernel.org/r/20210510204524.617390-1-robh@kernel.org --- Documentation/devicetree/bindings/clock/idt,versaclock5.yaml | 2 -- Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml | 1 - Documentation/devicetree/bindings/input/input.yaml | 1 - Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml | 1 - Documentation/devicetree/bindings/net/qcom,ipa.yaml | 1 - Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml | 2 +- Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml | 2 +- 7 files changed, 2 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/idt,versaclock5.yaml b/Documentation/devicetree/bindings/clock/idt,versaclock5.yaml index c268debe5b8d..28675b0b80f1 100644 --- a/Documentation/devicetree/bindings/clock/idt,versaclock5.yaml +++ b/Documentation/devicetree/bindings/clock/idt,versaclock5.yaml @@ -60,7 +60,6 @@ properties: maxItems: 2 idt,xtal-load-femtofarads: - $ref: /schemas/types.yaml#/definitions/uint32 minimum: 9000 maximum: 22760 description: Optional load capacitor for XTAL1 and XTAL2 @@ -84,7 +83,6 @@ patternProperties: enum: [ 1800000, 2500000, 3300000 ] idt,slew-percent: description: The Slew rate control for CMOS single-ended. - $ref: /schemas/types.yaml#/definitions/uint32 enum: [ 80, 85, 90, 100 ] required: diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml index 6f2398cdc82d..1e7894e524f9 100644 --- a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml @@ -102,7 +102,6 @@ patternProperties: st,adc-channel-names: description: List of single-ended channel names. - $ref: /schemas/types.yaml#/definitions/string-array st,filter-order: description: | diff --git a/Documentation/devicetree/bindings/input/input.yaml b/Documentation/devicetree/bindings/input/input.yaml index 74244d21d2b3..d41d8743aad4 100644 --- a/Documentation/devicetree/bindings/input/input.yaml +++ b/Documentation/devicetree/bindings/input/input.yaml @@ -38,6 +38,5 @@ properties: Duration in seconds which the key should be kept pressed for device to reset automatically. Device with key pressed reset feature can specify this property. - $ref: /schemas/types.yaml#/definitions/uint32 additionalProperties: true diff --git a/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml index cb6498108b78..36c955965d90 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml @@ -92,7 +92,6 @@ properties: this interconnect to send RPMh commands. qcom,bcm-voter-names: - $ref: /schemas/types.yaml#/definitions/string-array description: | Names for each of the qcom,bcm-voters specified. diff --git a/Documentation/devicetree/bindings/net/qcom,ipa.yaml b/Documentation/devicetree/bindings/net/qcom,ipa.yaml index 7443490d4cc6..5fe6d3dceb08 100644 --- a/Documentation/devicetree/bindings/net/qcom,ipa.yaml +++ b/Documentation/devicetree/bindings/net/qcom,ipa.yaml @@ -105,7 +105,6 @@ properties: - description: Whether the IPA clock is enabled (if valid) qcom,smem-state-names: - $ref: /schemas/types.yaml#/definitions/string-array description: The names of the state bits used for SMP2P output items: - const: ipa-clock-enabled-valid diff --git a/Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml b/Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml index db1aa238cda5..b62c2431f94e 100644 --- a/Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml +++ b/Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml @@ -20,7 +20,7 @@ properties: maxItems: 1 phys: - $ref: /schemas/types.yaml#/definitions/phandle + maxItems: 1 description: phandle to the USB phy monitored-battery: diff --git a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml index b4c190bddd84..61802a11baf4 100644 --- a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml @@ -49,7 +49,7 @@ properties: maxItems: 1 memory-region: - $ref: /schemas/types.yaml#/definitions/phandle + maxItems: 1 description: phandle to a node describing reserved memory (System RAM memory) The M core can't access all the DDR memory space on some platform, -- cgit v1.3.1 From fcb501704554eebfd27e3220b0540997fd2b24a8 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 12 May 2021 12:40:35 +0100 Subject: delayacct: Document task_delayacct sysctl Update sysctl/kernel.rst. Signed-off-by: Mel Gorman Signed-off-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r/20210512114035.GH3672@suse.de --- Documentation/admin-guide/sysctl/kernel.rst | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'Documentation') diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst index 1d56a6b73a4e..ebd2f993d608 100644 --- a/Documentation/admin-guide/sysctl/kernel.rst +++ b/Documentation/admin-guide/sysctl/kernel.rst @@ -1087,6 +1087,13 @@ Model available). If your platform happens to meet the requirements for EAS but you do not want to use it, change this value to 0. +task_delayacct +=============== + +Enables/disables task delay accounting (see +:doc:`accounting/delay-accounting.rst`). Enabling this feature incurs +a small amount of overhead in the scheduler but is useful for debugging +and performance tuning. It is required by some tools such as iotop. sched_schedstats ================ -- cgit v1.3.1 From 0b07154f066ab2c087c342b372be5771145bdc60 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Mon, 17 May 2021 17:39:46 +0200 Subject: dt-bindings: spi: spi-mux: rename flash node The recent conversion of the common MTD properties to YAML now mandates a particular node name for SPI flash devices. Reported-by: Rob Herring Signed-off-by: Michael Walle Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210517153946.9502-1-michael@walle.cc Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-mux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-mux.yaml b/Documentation/devicetree/bindings/spi/spi-mux.yaml index 6c21a132b51f..c2c007260582 100644 --- a/Documentation/devicetree/bindings/spi/spi-mux.yaml +++ b/Documentation/devicetree/bindings/spi/spi-mux.yaml @@ -72,7 +72,7 @@ examples: mux-controls = <&mux>; - spi-flash@0 { + flash@0 { compatible = "jedec,spi-nor"; reg = <0>; #address-cells = <1>; -- cgit v1.3.1 From f96e6c0ef63b981d295547ef624f4da7c820e097 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 May 2021 17:03:50 +0300 Subject: spi: pxa2xx: Update documentation to point out that it's outdated Update documentation by pointing out that it's applicable mostly for a legacy platform. While at it, add couple of points with regard to ACPI, Device Tree, and automatic DMA enablement. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210517140351.901-9-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- Documentation/spi/pxa2xx.rst | 58 ++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 26 deletions(-) (limited to 'Documentation') diff --git a/Documentation/spi/pxa2xx.rst b/Documentation/spi/pxa2xx.rst index 882d3cc72cc2..6312968acfe9 100644 --- a/Documentation/spi/pxa2xx.rst +++ b/Documentation/spi/pxa2xx.rst @@ -2,43 +2,47 @@ PXA2xx SPI on SSP driver HOWTO ============================== -This a mini howto on the pxa2xx_spi driver. The driver turns a PXA2xx -synchronous serial port into a SPI master controller +This a mini HOWTO on the pxa2xx_spi driver. The driver turns a PXA2xx +synchronous serial port into an SPI master controller (see Documentation/spi/spi-summary.rst). The driver has the following features -- Support for any PXA2xx SSP +- Support for any PXA2xx and compatible SSP. - SSP PIO and SSP DMA data transfers. - External and Internal (SSPFRM) chip selects. - Per slave device (chip) configuration. - Full suspend, freeze, resume support. -The driver is built around a "spi_message" fifo serviced by workqueue and a -tasklet. The workqueue, "pump_messages", drives message fifo and the tasklet -(pump_transfer) is responsible for queuing SPI transactions and setting up and -launching the dma/interrupt driven transfers. +The driver is built around a &struct spi_message FIFO serviced by kernel +thread. The kernel thread, spi_pump_messages(), drives message FIFO and +is responsible for queuing SPI transactions and setting up and launching +the DMA or interrupt driven transfers. Declaring PXA2xx Master Controllers ----------------------------------- -Typically a SPI master is defined in the arch/.../mach-*/board-*.c as a -"platform device". The master configuration is passed to the driver via a table -found in include/linux/spi/pxa2xx_spi.h:: +Typically, for a legacy platform, an SPI master is defined in the +arch/.../mach-*/board-*.c as a "platform device". The master configuration +is passed to the driver via a table found in include/linux/spi/pxa2xx_spi.h:: struct pxa2xx_spi_controller { u16 num_chipselect; u8 enable_dma; + ... }; The "pxa2xx_spi_controller.num_chipselect" field is used to determine the number of slave device (chips) attached to this SPI master. The "pxa2xx_spi_controller.enable_dma" field informs the driver that SSP DMA should -be used. This caused the driver to acquire two DMA channels: rx_channel and -tx_channel. The rx_channel has a higher DMA service priority the tx_channel. +be used. This caused the driver to acquire two DMA channels: Rx channel and +Tx channel. The Rx channel has a higher DMA service priority than the Tx channel. See the "PXA2xx Developer Manual" section "DMA Controller". +For the new platforms the description of the controller and peripheral devices +comes from Device Tree or ACPI. + NSSP MASTER SAMPLE ------------------ -Below is a sample configuration using the PXA255 NSSP:: +Below is a sample configuration using the PXA255 NSSP for a legacy platform:: static struct resource pxa_spi_nssp_resources[] = { [0] = { @@ -79,9 +83,10 @@ Below is a sample configuration using the PXA255 NSSP:: Declaring Slave Devices ----------------------- -Typically each SPI slave (chip) is defined in the arch/.../mach-*/board-*.c -using the "spi_board_info" structure found in "linux/spi/spi.h". See -"Documentation/spi/spi-summary.rst" for additional information. +Typically, for a legacy platform, each SPI slave (chip) is defined in the +arch/.../mach-*/board-*.c using the "spi_board_info" structure found in +"linux/spi/spi.h". See "Documentation/spi/spi-summary.rst" for additional +information. Each slave device attached to the PXA must provide slave specific configuration information via the structure "pxa2xx_spi_chip" found in @@ -101,9 +106,9 @@ device. All fields are optional. }; The "pxa2xx_spi_chip.tx_threshold" and "pxa2xx_spi_chip.rx_threshold" fields are -used to configure the SSP hardware fifo. These fields are critical to the +used to configure the SSP hardware FIFO. These fields are critical to the performance of pxa2xx_spi driver and misconfiguration will result in rx -fifo overruns (especially in PIO mode transfers). Good default values are:: +FIFO overruns (especially in PIO mode transfers). Good default values are:: .tx_threshold = 8, .rx_threshold = 8, @@ -118,7 +123,7 @@ use a value of 8. The driver will determine a reasonable default if dma_burst_size == 0. The "pxa2xx_spi_chip.timeout" fields is used to efficiently handle -trailing bytes in the SSP receiver fifo. The correct value for this field is +trailing bytes in the SSP receiver FIFO. The correct value for this field is dependent on the SPI bus speed ("spi_board_info.max_speed_hz") and the specific slave device. Please note that the PXA2xx SSP 1 does not support trailing byte timeouts and must busy-wait any trailing bytes. @@ -131,19 +136,19 @@ testing. The "pxa2xx_spi_chip.cs_control" field is used to point to a board specific function for asserting/deasserting a slave device chip select. If the field is NULL, the pxa2xx_spi master controller driver assumes that the SSP port is -configured to use SSPFRM instead. +configured to use GPIO or SSPFRM instead. NOTE: the SPI driver cannot control the chip select if SSPFRM is used, so the chipselect is dropped after each spi_transfer. Most devices need chip select -asserted around the complete message. Use SSPFRM as a GPIO (through cs_control) +asserted around the complete message. Use SSPFRM as a GPIO (through a descriptor) to accommodate these chips. NSSP SLAVE SAMPLE ----------------- -The pxa2xx_spi_chip structure is passed to the pxa2xx_spi driver in the -"spi_board_info.controller_data" field. Below is a sample configuration using -the PXA255 NSSP. +For a legacy platform or in some other cases, the pxa2xx_spi_chip structure +is passed to the pxa2xx_spi driver in the "spi_board_info.controller_data" +field. Below is a sample configuration using the PXA255 NSSP. :: @@ -212,7 +217,9 @@ DMA and PIO I/O Support ----------------------- The pxa2xx_spi driver supports both DMA and interrupt driven PIO message transfers. The driver defaults to PIO mode and DMA transfers must be enabled -by setting the "enable_dma" flag in the "pxa2xx_spi_controller" structure. The DMA +by setting the "enable_dma" flag in the "pxa2xx_spi_controller" structure. +For the newer platforms, that are known to support DMA, the driver will enable +it automatically and try it first with a possible fallback to PIO. The DMA mode supports both coherent and stream based DMA mappings. The following logic is used to determine the type of I/O to be used on @@ -236,5 +243,4 @@ a per "spi_transfer" basis:: THANKS TO --------- - David Brownell and others for mentoring the development of this driver. -- cgit v1.3.1 From 1897907cca5aa22cdfcdb7fb8f0644a6add0877d Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Mon, 19 Apr 2021 21:49:55 +0000 Subject: Documentation/x86: Add buslock.rst Add buslock.rst to explain bus lock problem and how to detect and handle it. [ tglx: Included it into index.rst and added the missing include ... ] Signed-off-by: Fenghua Yu Signed-off-by: Thomas Gleixner Reviewed-by: Tony Luck Link: https://lore.kernel.org/r/20210419214958.4035512-2-fenghua.yu@intel.com --- Documentation/x86/buslock.rst | 104 ++++++++++++++++++++++++++++++++++++++++++ Documentation/x86/index.rst | 1 + 2 files changed, 105 insertions(+) create mode 100644 Documentation/x86/buslock.rst (limited to 'Documentation') diff --git a/Documentation/x86/buslock.rst b/Documentation/x86/buslock.rst new file mode 100644 index 000000000000..159ff6ba830e --- /dev/null +++ b/Documentation/x86/buslock.rst @@ -0,0 +1,104 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: + +=============================== +Bus lock detection and handling +=============================== + +:Copyright: |copy| 2021 Intel Corporation +:Authors: - Fenghua Yu + - Tony Luck + +Problem +======= + +A split lock is any atomic operation whose operand crosses two cache lines. +Since the operand spans two cache lines and the operation must be atomic, +the system locks the bus while the CPU accesses the two cache lines. + +A bus lock is acquired through either split locked access to writeback (WB) +memory or any locked access to non-WB memory. This is typically thousands of +cycles slower than an atomic operation within a cache line. It also disrupts +performance on other cores and brings the whole system to its knees. + +Detection +========= + +Intel processors may support either or both of the following hardware +mechanisms to detect split locks and bus locks. + +#AC exception for split lock detection +-------------------------------------- + +Beginning with the Tremont Atom CPU split lock operations may raise an +Alignment Check (#AC) exception when a split lock operation is attemped. + +#DB exception for bus lock detection +------------------------------------ + +Some CPUs have the ability to notify the kernel by an #DB trap after a user +instruction acquires a bus lock and is executed. This allows the kernel to +terminate the application or to enforce throttling. + +Software handling +================= + +The kernel #AC and #DB handlers handle bus lock based on the kernel +parameter "split_lock_detect". Here is a summary of different options: + ++------------------+----------------------------+-----------------------+ +|split_lock_detect=|#AC for split lock |#DB for bus lock | ++------------------+----------------------------+-----------------------+ +|off |Do nothing |Do nothing | ++------------------+----------------------------+-----------------------+ +|warn |Kernel OOPs |Warn once per task and | +|(default) |Warn once per task and |and continues to run. | +| |disable future checking | | +| |When both features are | | +| |supported, warn in #AC | | ++------------------+----------------------------+-----------------------+ +|fatal |Kernel OOPs |Send SIGBUS to user. | +| |Send SIGBUS to user | | +| |When both features are | | +| |supported, fatal in #AC | | ++------------------+----------------------------+-----------------------+ + +Usages +====== + +Detecting and handling bus lock may find usages in various areas: + +It is critical for real time system designers who build consolidated real +time systems. These systems run hard real time code on some cores and run +"untrusted" user processes on other cores. The hard real time cannot afford +to have any bus lock from the untrusted processes to hurt real time +performance. To date the designers have been unable to deploy these +solutions as they have no way to prevent the "untrusted" user code from +generating split lock and bus lock to block the hard real time code to +access memory during bus locking. + +It's also useful for general computing to prevent guests or user +applications from slowing down the overall system by executing instructions +with bus lock. + + +Guidance +======== +off +--- + +Disable checking for split lock and bus lock. This option can be useful if +there are legacy applications that trigger these events at a low rate so +that mitigation is not needed. + +warn +---- + +A warning is emitted when a bus lock is detected which allows to identify +the offending application. This is the default behavior. + +fatal +----- + +In this case, the bus lock is not tolerated and the process is killed. diff --git a/Documentation/x86/index.rst b/Documentation/x86/index.rst index 4693e192b447..0004f5d2283e 100644 --- a/Documentation/x86/index.rst +++ b/Documentation/x86/index.rst @@ -29,6 +29,7 @@ x86-specific Documentation microcode resctrl tsx_async_abort + buslock usb-legacy-support i386/index x86_64/index -- cgit v1.3.1 From 9d839c280b64817345c2fa462c0027a9bd742361 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Mon, 19 Apr 2021 21:49:57 +0000 Subject: Documentation/admin-guide: Add bus lock ratelimit Since bus lock rate limit changes the split_lock_detect parameter, update the documentation for the change. Signed-off-by: Fenghua Yu Signed-off-by: Thomas Gleixner Reviewed-by: Tony Luck Link: https://lore.kernel.org/r/20210419214958.4035512-4-fenghua.yu@intel.com --- Documentation/admin-guide/kernel-parameters.txt | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'Documentation') diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index cb89dbdedc46..ca94624438b9 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -5283,6 +5283,14 @@ exception. Default behavior is by #AC if both features are enabled in hardware. + ratelimit:N - + Set system wide rate limit to N bus locks + per second for bus lock detection. + 0 < N <= 1000. + + N/A for split lock detection. + + If an #AC exception is hit in the kernel or in firmware (i.e. not while executing in user mode) the kernel will oops in either "warn" or "fatal" -- cgit v1.3.1 From d28397eaf4c27947a1ffc720d42e8b3a33ae1e2a Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Mon, 19 Apr 2021 21:49:58 +0000 Subject: Documentation/x86: Add ratelimit in buslock.rst ratelimit is a new command line option for bus lock handling. Add proper documentation. [ tglx: Massaged documentation ] Signed-off-by: Fenghua Yu Signed-off-by: Thomas Gleixner Reviewed-by: Tony Luck Link: https://lore.kernel.org/r/20210419214958.4035512-5-fenghua.yu@intel.com --- Documentation/x86/buslock.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'Documentation') diff --git a/Documentation/x86/buslock.rst b/Documentation/x86/buslock.rst index 159ff6ba830e..7c051e714943 100644 --- a/Documentation/x86/buslock.rst +++ b/Documentation/x86/buslock.rst @@ -63,6 +63,11 @@ parameter "split_lock_detect". Here is a summary of different options: | |When both features are | | | |supported, fatal in #AC | | +------------------+----------------------------+-----------------------+ +|ratelimit:N |Do nothing |Limit bus lock rate to | +|(0 < N <= 1000) | |N bus locks per second | +| | |system wide and warn on| +| | |bus locks. | ++------------------+----------------------------+-----------------------+ Usages ====== @@ -102,3 +107,20 @@ fatal ----- In this case, the bus lock is not tolerated and the process is killed. + +ratelimit +--------- + +A system wide bus lock rate limit N is specified where 0 < N <= 1000. This +allows a bus lock rate up to N bus locks per second. When the bus lock rate +is exceeded then any task which is caught via the buslock #DB exception is +throttled by enforced sleeps until the rate goes under the limit again. + +This is an effective mitigation in cases where a minimal impact can be +tolerated, but an eventual Denial of Service attack has to be prevented. It +allows to identify the offending processes and analyze whether they are +malicious or just badly written. + +Selecting a rate limit of 1000 allows the bus to be locked for up to about +seven million cycles each second (assuming 7000 cycles for each bus +lock). On a 2 GHz processor that would be about 0.35% system slowdown. -- cgit v1.3.1 From 67a7e53d5b21f3a84efc03a4e62db7caf97841ef Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 27 Apr 2021 09:15:54 +0200 Subject: media: hevc: Fix dependent slice segment flags Dependent slice segment flag for PPS control is misnamed. It should have "enabled" at the end. It only tells if this flag is present in slice header or not and not the actual value. Fix this by renaming the PPS flag and introduce another flag for slice control which tells actual value. Signed-off-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 5 ++++- drivers/staging/media/sunxi/cedrus/cedrus_h265.c | 4 ++-- include/media/hevc-ctrls.h | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index b0de4e6e7ebd..514b334470ea 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -3053,7 +3053,7 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - :stub-columns: 0 :widths: 1 1 2 - * - ``V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT`` + * - ``V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED`` - 0x00000001 - * - ``V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT`` @@ -3277,6 +3277,9 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED`` - 0x00000100 - + * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT`` + - 0x00000200 + - .. raw:: latex diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c index ce497d0197df..10744fab7cea 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c @@ -477,8 +477,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, slice_params->flags); reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_DEPENDENT_SLICE_SEGMENT, - V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT, - pps->flags); + V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT, + slice_params->flags); /* FIXME: For multi-slice support. */ reg |= VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_FIRST_SLICE_SEGMENT_IN_PIC; diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h index b4cb2ef02f17..226fcfa0e026 100644 --- a/include/media/hevc-ctrls.h +++ b/include/media/hevc-ctrls.h @@ -81,7 +81,7 @@ struct v4l2_ctrl_hevc_sps { __u64 flags; }; -#define V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT (1ULL << 0) +#define V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED (1ULL << 0) #define V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT (1ULL << 1) #define V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED (1ULL << 2) #define V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT (1ULL << 3) @@ -160,6 +160,7 @@ struct v4l2_hevc_pred_weight_table { #define V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV (1ULL << 6) #define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED (1ULL << 7) #define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED (1ULL << 8) +#define V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT (1ULL << 9) struct v4l2_ctrl_hevc_slice_params { __u32 bit_size; -- cgit v1.3.1 From 0d705395afa4b4fa7d0fae86b9c04cfe50a03ace Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Thu, 1 Apr 2021 16:43:34 +0200 Subject: media: dt-bindings: Document SAMA5D4 VDEC bindings Add devicetree binding documentation for the Hantro G1/G2 VDEC on the Microchip SAMAS5D4 SoC. Acked-by: Nicolas Ferre Signed-off-by: Emil Velikov Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/microchip,sama5d4-vdec.yaml | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/microchip,sama5d4-vdec.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/microchip,sama5d4-vdec.yaml b/Documentation/devicetree/bindings/media/microchip,sama5d4-vdec.yaml new file mode 100644 index 000000000000..4b77103ca913 --- /dev/null +++ b/Documentation/devicetree/bindings/media/microchip,sama5d4-vdec.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) + +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/media/microchip,sama5d4-vdec.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Hantro G1 VPU codec implemented on Microchip SAMA5D4 SoCs + +maintainers: + - Emil Velikov + +description: + Hantro G1 video decode accelerator present on Microchip SAMA5D4 SoCs. + +properties: + compatible: + const: microchip,sama5d4-vdec + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + #include + #include + + vdec0: vdec@300000 { + compatible = "microchip,sama5d4-vdec"; + reg = <0x00300000 0x100000>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH 4>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 19>; + }; -- cgit v1.3.1 From d5b3bd6ab5418e34d85f64fba7c6ca02c3cbfb63 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 19 May 2021 15:02:53 +0200 Subject: dt-bindings: net: renesas,ether: Update Sergei's email address Update Sergei's email address, as per commit 534a8bf0ccdd7b3f ("MAINTAINERS: switch to my private email for Renesas Ethernet drivers"). Signed-off-by: Geert Uytterhoeven Acked-by: Sergei Shtylyov Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/renesas,ether.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/renesas,ether.yaml b/Documentation/devicetree/bindings/net/renesas,ether.yaml index 8ce5ed8a58dd..c101a1ec846e 100644 --- a/Documentation/devicetree/bindings/net/renesas,ether.yaml +++ b/Documentation/devicetree/bindings/net/renesas,ether.yaml @@ -10,7 +10,7 @@ allOf: - $ref: ethernet-controller.yaml# maintainers: - - Sergei Shtylyov + - Sergei Shtylyov properties: compatible: -- cgit v1.3.1 From 5665bc35c1ed917ac8fd06cb651317bb47a65b10 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 20 May 2021 21:19:30 +1000 Subject: powerpc/64s/syscall: Use pt_regs.trap to distinguish syscall ABI difference between sc and scv syscalls The sc and scv 0 system calls have different ABI conventions, and ptracers need to know which system call type is being used if they want to look at the syscall registers. Document that pt_regs.trap can be used for this, and fix one in-tree user to work with scv 0 syscalls. Fixes: 7fa95f9adaee ("powerpc/64s: system call support for scv/rfscv instructions") Cc: stable@vger.kernel.org # v5.9+ Reported-by: "Dmitry V. Levin" Suggested-by: "Dmitry V. Levin" Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20210520111931.2597127-1-npiggin@gmail.com --- Documentation/powerpc/syscall64-abi.rst | 10 ++++++++++ tools/testing/selftests/seccomp/seccomp_bpf.c | 27 ++++++++++++++++++--------- 2 files changed, 28 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/powerpc/syscall64-abi.rst b/Documentation/powerpc/syscall64-abi.rst index dabee3729e5a..56490c4c0c07 100644 --- a/Documentation/powerpc/syscall64-abi.rst +++ b/Documentation/powerpc/syscall64-abi.rst @@ -109,6 +109,16 @@ auxiliary vector. scv 0 syscalls will always behave as PPC_FEATURE2_HTM_NOSC. +ptrace +------ +When ptracing system calls (PTRACE_SYSCALL), the pt_regs.trap value contains +the system call type that can be used to distinguish between sc and scv 0 +system calls, and the different register conventions can be accounted for. + +If the value of (pt_regs.trap & 0xfff0) is 0xc00 then the system call was +performed with the sc instruction, if it is 0x3000 then the system call was +performed with the scv 0 instruction. + vsyscall ======== diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 98c3b647f54d..e3d5c77a8612 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -1753,16 +1753,25 @@ TEST_F(TRACE_poke, getpid_runs_normally) # define SYSCALL_RET_SET(_regs, _val) \ do { \ typeof(_val) _result = (_val); \ - /* \ - * A syscall error is signaled by CR0 SO bit \ - * and the code is stored as a positive value. \ - */ \ - if (_result < 0) { \ - SYSCALL_RET(_regs) = -_result; \ - (_regs).ccr |= 0x10000000; \ - } else { \ + if ((_regs.trap & 0xfff0) == 0x3000) { \ + /* \ + * scv 0 system call uses -ve result \ + * for error, so no need to adjust. \ + */ \ SYSCALL_RET(_regs) = _result; \ - (_regs).ccr &= ~0x10000000; \ + } else { \ + /* \ + * A syscall error is signaled by the \ + * CR0 SO bit and the code is stored as \ + * a positive value. \ + */ \ + if (_result < 0) { \ + SYSCALL_RET(_regs) = -_result; \ + (_regs).ccr |= 0x10000000; \ + } else { \ + SYSCALL_RET(_regs) = _result; \ + (_regs).ccr &= ~0x10000000; \ + } \ } \ } while (0) # define SYSCALL_RET_SET_ON_PTRACE_EXIT -- cgit v1.3.1 From e437c1a3e7137c0da035a2804bf6b4cc007d4f5e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 May 2021 10:51:39 +0200 Subject: docs: vcpu-requests.rst: fix reference for atomic ops Changeset f0400a77ebdc ("atomic: Delete obsolete documentation") got rid of atomic_ops.rst, pointing that this was superseded by Documentation/atomic_*.txt. Update its reference accordingly. Fixes: f0400a77ebdc ("atomic: Delete obsolete documentation") Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/703af756ac26a06c2185c05dfe6d902253f11161.1621413933.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/virt/kvm/vcpu-requests.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/vcpu-requests.rst b/Documentation/virt/kvm/vcpu-requests.rst index 5feb3706a7ae..5f8798e7fdf8 100644 --- a/Documentation/virt/kvm/vcpu-requests.rst +++ b/Documentation/virt/kvm/vcpu-requests.rst @@ -302,6 +302,6 @@ VCPU returns from the call. References ========== -.. [atomic-ops] Documentation/core-api/atomic_ops.rst +.. [atomic-ops] Documentation/atomic_bitops.txt and Documentation/atomic_t.txt .. [memory-barriers] Documentation/memory-barriers.txt .. [lwn-mb] https://lwn.net/Articles/573436/ -- cgit v1.3.1 From 50bd52fef16dc806be11ba86f406364366f3f23b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 May 2021 10:51:40 +0200 Subject: docs: translations/zh_CN: fix a typo at 8.Conclusion.rst transaltions -> translations Signed-off-by: Mauro Carvalho Chehab Acked-by: Wu XiangCheng Link: https://lore.kernel.org/r/40b3d5c983fb06d8a58d1f613c175a98e0631677.1621413933.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/translations/zh_CN/process/8.Conclusion.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/process/8.Conclusion.rst b/Documentation/translations/zh_CN/process/8.Conclusion.rst index 71c3e30efc6f..4707f0101964 100644 --- a/Documentation/translations/zh_CN/process/8.Conclusion.rst +++ b/Documentation/translations/zh_CN/process/8.Conclusion.rst @@ -19,7 +19,7 @@ :ref:`Documentation/translations/zh_CN/process/howto.rst ` 文件是一个重要的起点; :ref:`Documentation/translations/zh_CN/process/submitting-patches.rst ` -和 :ref:`Documentation/transaltions/zh_CN/process/submitting-drivers.rst ` +和 :ref:`Documentation/translations/zh_CN/process/submitting-drivers.rst ` 也是所有内核开发人员都应该阅读的内容。许多内部内核API都是使用kerneldoc机制 记录的;“make htmldocs”或“make pdfdocs”可用于以HTML或PDF格式生成这些文档 (尽管某些发行版提供的tex版本会遇到内部限制,无法正确处理文档)。 -- cgit v1.3.1 From 716c9d9403d061d02c419a6f63a4f3fd01278cae Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 May 2021 10:51:41 +0200 Subject: docs: sched-bwc.rst: fix a typo on a doc name cgroupv2.rst -> cgroup-v2.rst Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/1dc0203bd7df375ef45832f0c88566e22c4138ff.1621413933.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/scheduler/sched-bwc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/scheduler/sched-bwc.rst b/Documentation/scheduler/sched-bwc.rst index 845eee659199..1fc73555f5c4 100644 --- a/Documentation/scheduler/sched-bwc.rst +++ b/Documentation/scheduler/sched-bwc.rst @@ -29,7 +29,7 @@ Quota and period are managed within the cpu subsystem via cgroupfs. .. note:: The cgroupfs files described in this section are only applicable to cgroup v1. For cgroup v2, see - :ref:`Documentation/admin-guide/cgroupv2.rst `. + :ref:`Documentation/admin-guide/cgroup-v2.rst `. - cpu.cfs_quota_us: the total available run-time within a period (in microseconds) -- cgit v1.3.1 From 0a5fab9f085880dbd7f9b0055c74936ca8b64fc1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 May 2021 10:51:43 +0200 Subject: docs: virt: api.rst: fix a pointer to SGX documentation The document which describes the SGX kernel architecture was added at commit 3fa97bf00126 ("Documentation/x86: Document SGX kernel architecture") but the reference at virt/kvm/api.rst is pointing to some non-existing document. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/138c24633c6e4edf862a2b4d77033c603fc10406.1621413933.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/virt/kvm/api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 22d077562149..e86fe3481574 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6360,7 +6360,7 @@ system fingerprint. To prevent userspace from circumventing such restrictions by running an enclave in a VM, KVM prevents access to privileged attributes by default. -See Documentation/x86/sgx/2.Kernel-internals.rst for more details. +See Documentation/x86/sgx.rst for more details. 8. Other capabilities. ====================== -- cgit v1.3.1 From 5286bd25e2095d71d248fbfd2a55ca4333dfd77e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 May 2021 10:51:44 +0200 Subject: docs: ABI: iommu: remove duplicated definition for sysfs-kernel-iommu_groups ./scripts/get_abi.pl is reporting a duplicated definition for /sys/kernel/iommu_groups/reserved_regions, both at the same file: Warning: /sys/kernel/iommu_groups/reserved_regions is defined 2 times: Documentation/ABI/testing/sysfs-kernel-iommu_groups:15 Documentation/ABI/testing/sysfs-kernel-iommu_groups:27 Fix it by merging those into an unified entry. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/ec33e8e9b8f120232ffb3b9fcc99c97b87f242e3.1621413933.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/ABI/testing/sysfs-kernel-iommu_groups | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-kernel-iommu_groups b/Documentation/ABI/testing/sysfs-kernel-iommu_groups index 0fedbb0f94e4..eae2f1c1e11e 100644 --- a/Documentation/ABI/testing/sysfs-kernel-iommu_groups +++ b/Documentation/ABI/testing/sysfs-kernel-iommu_groups @@ -25,14 +25,10 @@ Description: /sys/kernel/iommu_groups/reserved_regions list IOVA the base IOVA, the second is the end IOVA and the third field describes the type of the region. -What: /sys/kernel/iommu_groups/reserved_regions -Date: June 2019 -KernelVersion: v5.3 -Contact: Eric Auger -Description: In case an RMRR is used only by graphics or USB devices - it is now exposed as "direct-relaxable" instead of "direct". - In device assignment use case, for instance, those RMRR - are considered to be relaxable and safe. + Since kernel 5.3, in case an RMRR is used only by graphics or + USB devices it is now exposed as "direct-relaxable" instead + of "direct". In device assignment use case, for instance, + those RMRR are considered to be relaxable and safe. What: /sys/kernel/iommu_groups//type Date: November 2020 -- cgit v1.3.1 From 13d6f96750c89f7fc282788bd058559381ccec29 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 May 2021 10:51:45 +0200 Subject: docs: ABI: sysfs-class-backlight: unify ambient light zone nodes ./scripts/get_abi.pl is warning about duplicated symbol definition: Warning: /sys/class/backlight//l1_daylight_max is defined 2 times: ./Documentation/ABI/testing/sysfs-class-backlight-driver-adp8870:4 ./Documentation/ABI/testing/sysfs-class-backlight-adp8860:12 What happens is that 3 drivers use the same pattern to report max and dim setting for different ambient light zones. It should be noticed that the adp8870 doc was missing an entry for l1_daylight_dim, which was fixed on this patch. While the ambient light zone is device-specific, the sysfs definition is actually common. So, unify them at: Documentation/ABI/testing/sysfs-class-backlight and use as the contact point, the e-mail reported by get_maintainers.pl for the subsystem. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/c13c6ebd03cd04a0d15d89018f8d529918fc0a73.1621413933.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/ABI/testing/sysfs-class-backlight | 100 +++++++++++++++++++++ .../ABI/testing/sysfs-class-backlight-adp5520 | 31 ------- .../ABI/testing/sysfs-class-backlight-adp8860 | 37 -------- .../testing/sysfs-class-backlight-driver-adp8870 | 32 ------- 4 files changed, 100 insertions(+), 100 deletions(-) delete mode 100644 Documentation/ABI/testing/sysfs-class-backlight-adp5520 delete mode 100644 Documentation/ABI/testing/sysfs-class-backlight-adp8860 delete mode 100644 Documentation/ABI/testing/sysfs-class-backlight-driver-adp8870 (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-class-backlight b/Documentation/ABI/testing/sysfs-class-backlight index 1fc86401bf95..c453646b06e2 100644 --- a/Documentation/ABI/testing/sysfs-class-backlight +++ b/Documentation/ABI/testing/sysfs-class-backlight @@ -84,3 +84,103 @@ Description: It can be enabled by writing the value stored in /sys/class/backlight//max_brightness to /sys/class/backlight//brightness. + +What: /sys/class/backlight//_max +Date: Sep, 2009 +KernelVersion: v2.6.32 +Contact: device-drivers-devel@blackfin.uclinux.org +Description: + Control the maximum brightness for + on this . Values are between 0 and 127. This file + will also show the brightness level stored for this + . + + The is device-driver specific: + + For ADP5520 and ADP5501, can be: + + =========== ================================================ + Ambient sysfs entry + light zone + =========== ================================================ + daylight /sys/class/backlight//daylight_max + office /sys/class/backlight//office_max + dark /sys/class/backlight//dark_max + =========== ================================================ + + For ADP8860, can be: + + =========== ================================================ + Ambient sysfs entry + light zone + =========== ================================================ + l1_daylight /sys/class/backlight//l1_daylight_max + l2_office /sys/class/backlight//l2_office_max + l3_dark /sys/class/backlight//l3_dark_max + =========== ================================================ + + For ADP8870, can be: + + =========== ================================================ + Ambient sysfs entry + light zone + =========== ================================================ + l1_daylight /sys/class/backlight//l1_daylight_max + l2_bright /sys/class/backlight//l2_bright_max + l3_office /sys/class/backlight//l3_office_max + l4_indoor /sys/class/backlight//l4_indoor_max + l5_dark /sys/class/backlight//l5_dark_max + =========== ================================================ + + See also: /sys/class/backlight//ambient_light_zone. + +What: /sys/class/backlight//_dim +Date: Sep, 2009 +KernelVersion: v2.6.32 +Contact: device-drivers-devel@blackfin.uclinux.org +Description: + Control the dim brightness for + on this . Values are between 0 and 127, typically + set to 0. Full off when the backlight is disabled. + This file will also show the dim brightness level stored for + this . + + The is device-driver specific: + + For ADP5520 and ADP5501, can be: + + =========== ================================================ + Ambient sysfs entry + light zone + =========== ================================================ + daylight /sys/class/backlight//daylight_dim + office /sys/class/backlight//office_dim + dark /sys/class/backlight//dark_dim + =========== ================================================ + + For ADP8860, can be: + + =========== ================================================ + Ambient sysfs entry + light zone + =========== ================================================ + l1_daylight /sys/class/backlight//l1_daylight_dim + l2_office /sys/class/backlight//l2_office_dim + l3_dark /sys/class/backlight//l3_dark_dim + =========== ================================================ + + For ADP8870, can be: + + =========== ================================================ + Ambient sysfs entry + light zone + =========== ================================================ + l1_daylight /sys/class/backlight//l1_daylight_dim + l2_bright /sys/class/backlight//l2_bright_dim + l3_office /sys/class/backlight//l3_office_dim + l4_indoor /sys/class/backlight//l4_indoor_dim + l5_dark /sys/class/backlight//l5_dark_dim + =========== ================================================ + + See also: /sys/class/backlight//ambient_light_zone. + diff --git a/Documentation/ABI/testing/sysfs-class-backlight-adp5520 b/Documentation/ABI/testing/sysfs-class-backlight-adp5520 deleted file mode 100644 index 34b6ebafa210..000000000000 --- a/Documentation/ABI/testing/sysfs-class-backlight-adp5520 +++ /dev/null @@ -1,31 +0,0 @@ -sysfs interface for analog devices adp5520(01) backlight driver ---------------------------------------------------------------- - -The backlight brightness control operates at three different levels for the -adp5520 and adp5501 devices: daylight (level 1), office (level 2) and dark -(level 3). By default the brightness operates at the daylight brightness level. - -What: /sys/class/backlight//daylight_max -What: /sys/class/backlight//office_max -What: /sys/class/backlight//dark_max -Date: Sep, 2009 -KernelVersion: v2.6.32 -Contact: Michael Hennerich -Description: - (RW) Maximum current setting for the backlight when brightness - is at one of the three levels (daylight, office or dark). This - is an input code between 0 and 127, which is transformed to a - value between 0 mA and 30 mA using linear or non-linear - algorithms. - -What: /sys/class/backlight//daylight_dim -What: /sys/class/backlight//office_dim -What: /sys/class/backlight//dark_dim -Date: Sep, 2009 -KernelVersion: v2.6.32 -Contact: Michael Hennerich -Description: - (RW) Dim current setting for the backlight when brightness is at - one of the three levels (daylight, office or dark). This is an - input code between 0 and 127, which is transformed to a value - between 0 mA and 30 mA using linear or non-linear algorithms. diff --git a/Documentation/ABI/testing/sysfs-class-backlight-adp8860 b/Documentation/ABI/testing/sysfs-class-backlight-adp8860 deleted file mode 100644 index 6610ac73f9ba..000000000000 --- a/Documentation/ABI/testing/sysfs-class-backlight-adp8860 +++ /dev/null @@ -1,37 +0,0 @@ -sysfs interface for analog devices adp8860 backlight driver ------------------------------------------------------------ - -The backlight brightness control operates at three different levels for the -adp8860, adp8861 and adp8863 devices: daylight (level 1), office (level 2) and -dark (level 3). By default the brightness operates at the daylight brightness -level. - -See also /sys/class/backlight//ambient_light_level and -/sys/class/backlight//ambient_light_zone. - - -What: /sys/class/backlight//l1_daylight_max -What: /sys/class/backlight//l2_office_max -What: /sys/class/backlight//l3_dark_max -Date: Apr, 2010 -KernelVersion: v2.6.35 -Contact: Michael Hennerich -Description: - (RW) Maximum current setting for the backlight when brightness - is at one of the three levels (daylight, office or dark). This - is an input code between 0 and 127, which is transformed to a - value between 0 mA and 30 mA using linear or non-linear - algorithms. - - -What: /sys/class/backlight//l1_daylight_dim -What: /sys/class/backlight//l2_office_dim -What: /sys/class/backlight//l3_dark_dim -Date: Apr, 2010 -KernelVersion: v2.6.35 -Contact: Michael Hennerich -Description: - (RW) Dim current setting for the backlight when brightness is at - one of the three levels (daylight, office or dark). This is an - input code between 0 and 127, which is transformed to a value - between 0 mA and 30 mA using linear or non-linear algorithms. diff --git a/Documentation/ABI/testing/sysfs-class-backlight-driver-adp8870 b/Documentation/ABI/testing/sysfs-class-backlight-driver-adp8870 deleted file mode 100644 index b08ca912cad4..000000000000 --- a/Documentation/ABI/testing/sysfs-class-backlight-driver-adp8870 +++ /dev/null @@ -1,32 +0,0 @@ -See also /sys/class/backlight//ambient_light_level and -/sys/class/backlight//ambient_light_zone. - -What: /sys/class/backlight//_max -What: /sys/class/backlight//l1_daylight_max -What: /sys/class/backlight//l2_bright_max -What: /sys/class/backlight//l3_office_max -What: /sys/class/backlight//l4_indoor_max -What: /sys/class/backlight//l5_dark_max -Date: May 2011 -KernelVersion: 3.0 -Contact: device-drivers-devel@blackfin.uclinux.org -Description: - Control the maximum brightness for - on this . Values are between 0 and 127. This file - will also show the brightness level stored for this - . - -What: /sys/class/backlight//_dim -What: /sys/class/backlight//l2_bright_dim -What: /sys/class/backlight//l3_office_dim -What: /sys/class/backlight//l4_indoor_dim -What: /sys/class/backlight//l5_dark_dim -Date: May 2011 -KernelVersion: 3.0 -Contact: device-drivers-devel@blackfin.uclinux.org -Description: - Control the dim brightness for - on this . Values are between 0 and 127, typically - set to 0. Full off when the backlight is disabled. - This file will also show the dim brightness level stored for - this . -- cgit v1.3.1 From 1ca5d41c371e6abe788439e6eaecfa76baaf6979 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 May 2021 10:51:46 +0200 Subject: docs: ABI: sysfs-class-led-trigger-pattern: remove repeat duplication As reported by scripts/get_abi.pl: Warning: /sys/class/leds//repeat is defined 2 times: Documentation/ABI/testing/sysfs-class-led-driver-el15203000:0 Documentation/ABI/testing/sysfs-class-led-trigger-pattern:28 The definition for the EL15203000 is just a special case of the sysfs led class. So, drop it and mentions the possible exception at the class definition. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/394580bd2e007ffb640f97212973a772ed8f0409.1621413933.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/ABI/testing/sysfs-class-led-driver-el15203000 | 9 --------- Documentation/ABI/testing/sysfs-class-led-trigger-pattern | 3 +++ 2 files changed, 3 insertions(+), 9 deletions(-) delete mode 100644 Documentation/ABI/testing/sysfs-class-led-driver-el15203000 (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-class-led-driver-el15203000 b/Documentation/ABI/testing/sysfs-class-led-driver-el15203000 deleted file mode 100644 index 04f3ffdc5936..000000000000 --- a/Documentation/ABI/testing/sysfs-class-led-driver-el15203000 +++ /dev/null @@ -1,9 +0,0 @@ -What: /sys/class/leds//repeat -Date: September 2019 -KernelVersion: 5.5 -Description: - EL15203000 supports only indefinitely patterns, - so this file should always store -1. - - For more info, please see: - Documentation/ABI/testing/sysfs-class-led-trigger-pattern diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-pattern b/Documentation/ABI/testing/sysfs-class-led-trigger-pattern index d91a07767adf..8c57d2780554 100644 --- a/Documentation/ABI/testing/sysfs-class-led-trigger-pattern +++ b/Documentation/ABI/testing/sysfs-class-led-trigger-pattern @@ -35,3 +35,6 @@ Description: This file will always return the originally written repeat number. + + It should be noticed that some leds, like EL15203000 may + only support indefinitely patterns, so they always store -1. -- cgit v1.3.1 From cc3496bf8685a5bd0bdd79b23ef06e85184f8863 Mon Sep 17 00:00:00 2001 From: Wei Ming Chen Date: Sat, 15 May 2021 23:51:42 +0800 Subject: docs: Use fallthrough pseudo-keyword Replace /* fall through */ comment with fallthrough, make it align with original process/coding-style.rst Signed-off-by: Wei Ming Chen Link: https://lore.kernel.org/r/20210515155142.2490-1-jj251510319013@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/translations/it_IT/process/coding-style.rst | 2 +- Documentation/translations/zh_CN/process/coding-style.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/translations/it_IT/process/coding-style.rst b/Documentation/translations/it_IT/process/coding-style.rst index 95f2e7c985e2..ecc74ba50d3e 100644 --- a/Documentation/translations/it_IT/process/coding-style.rst +++ b/Documentation/translations/it_IT/process/coding-style.rst @@ -62,7 +62,7 @@ i ``case``. Un esempio.: case 'K': case 'k': mem <<= 10; - /* fall through */ + fallthrough; default: break; } diff --git a/Documentation/translations/zh_CN/process/coding-style.rst b/Documentation/translations/zh_CN/process/coding-style.rst index 406d43a02c02..b8c484a84d10 100644 --- a/Documentation/translations/zh_CN/process/coding-style.rst +++ b/Documentation/translations/zh_CN/process/coding-style.rst @@ -61,7 +61,7 @@ Linux 内核代码风格 case 'K': case 'k': mem <<= 10; - /* fall through */ + fallthrough; default: break; } -- cgit v1.3.1 From 76001b8bbf48517e1cb64f5cddcbc4d1369aab0b Mon Sep 17 00:00:00 2001 From: Dwaipayan Ray Date: Sat, 15 May 2021 18:53:48 +0530 Subject: docs: Add more message type documentations for checkpatch - Document a couple of more checkpatch message types. - Add a blank line before all `See:` lines to improve the rst output. - Create a new subsection `Permissions` and move a few types to it. Signed-off-by: Dwaipayan Ray Acked-by: Lukas Bulwahn Link: https://lore.kernel.org/r/20210515132348.19082-1-dwaipayanray1@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/dev-tools/checkpatch.rst | 170 +++++++++++++++++++++++++++++++-- 1 file changed, 163 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/dev-tools/checkpatch.rst b/Documentation/dev-tools/checkpatch.rst index 51fed1bd72ec..e409f27f48b6 100644 --- a/Documentation/dev-tools/checkpatch.rst +++ b/Documentation/dev-tools/checkpatch.rst @@ -246,6 +246,7 @@ Allocation style The first argument for kcalloc or kmalloc_array should be the number of elements. sizeof() as the first argument is generally wrong. + See: https://www.kernel.org/doc/html/latest/core-api/memory-allocation.html **ALLOC_SIZEOF_STRUCT** @@ -264,6 +265,7 @@ Allocation style **ALLOC_WITH_MULTIPLY** Prefer kmalloc_array/kcalloc over kmalloc/kzalloc with a sizeof multiply. + See: https://www.kernel.org/doc/html/latest/core-api/memory-allocation.html @@ -284,6 +286,7 @@ API usage BUG() or BUG_ON() should be avoided totally. Use WARN() and WARN_ON() instead, and handle the "impossible" error condition as gracefully as possible. + See: https://www.kernel.org/doc/html/latest/process/deprecated.html#bug-and-bug-on **CONSIDER_KSTRTO** @@ -292,12 +295,23 @@ API usage may lead to unexpected results in callers. The respective kstrtol(), kstrtoll(), kstrtoul(), and kstrtoull() functions tend to be the correct replacements. + See: https://www.kernel.org/doc/html/latest/process/deprecated.html#simple-strtol-simple-strtoll-simple-strtoul-simple-strtoull + **IN_ATOMIC** + in_atomic() is not for driver use so any such use is reported as an ERROR. + Also in_atomic() is often used to determine if we may sleep, but it is not + reliable in this use model therefore its use is strongly discouraged. + + However, in_atomic() is ok for core kernel use. + + See: https://lore.kernel.org/lkml/20080320201723.b87b3732.akpm@linux-foundation.org/ + **LOCKDEP** The lockdep_no_validate class was added as a temporary measure to prevent warnings on conversion of device->sem to device->mutex. It should not be used for any other purpose. + See: https://lore.kernel.org/lkml/1268959062.9440.467.camel@laptop/ **MALFORMED_INCLUDE** @@ -308,11 +322,18 @@ API usage **USE_LOCKDEP** lockdep_assert_held() annotations should be preferred over assertions based on spin_is_locked() + See: https://www.kernel.org/doc/html/latest/locking/lockdep-design.html#annotations **UAPI_INCLUDE** No #include statements in include/uapi should use a uapi/ path. + **USLEEP_RANGE** + usleep_range() should be preferred over udelay(). The proper way of + using usleep_range() is mentioned in the kernel docs. + + See: https://www.kernel.org/doc/html/latest/timers/timers-howto.html#delays-information-on-the-various-kernel-delay-sleep-mechanisms + Comment style ------------- @@ -338,6 +359,7 @@ Comment style **C99_COMMENTS** C99 style single line comments (//) should not be used. Prefer the block comment style instead. + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#commenting @@ -347,6 +369,7 @@ Commit message **BAD_SIGN_OFF** The signed-off-by line does not fall in line with the standards specified by the community. + See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#developer-s-certificate-of-origin-1-1 **BAD_STABLE_ADDRESS_STYLE** @@ -368,12 +391,26 @@ Commit message **COMMIT_MESSAGE** The patch is missing a commit description. A brief description of the changes made by the patch should be added. + See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#describe-your-changes + **FROM_SIGN_OFF_MISMATCH** + The author's email does not match with that in the Signed-off-by: + line(s). This can be sometimes caused due to an improperly configured + email client. + + This message is emitted due to any of the following reasons:: + + - The email names do not match. + - The email addresses do not match. + - The email subaddresses do not match. + - The email comments do not match. + **MISSING_SIGN_OFF** The patch is missing a Signed-off-by line. A signed-off-by line should be added according to Developer's certificate of Origin. + See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin **NO_AUTHOR_SIGN_OFF** @@ -382,6 +419,7 @@ Commit message end of explanation of the patch to denote that the author has written it or otherwise has the rights to pass it on as an open source patch. + See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin **DIFF_IN_COMMIT_MSG** @@ -389,6 +427,7 @@ Commit message This causes problems when one tries to apply a file containing both the changelog and the diff because patch(1) tries to apply the diff which it found in the changelog. + See: https://lore.kernel.org/lkml/20150611134006.9df79a893e3636019ad2759e@linux-foundation.org/ **GERRIT_CHANGE_ID** @@ -431,6 +470,7 @@ Comparison style **BOOL_COMPARISON** Comparisons of A to true and false are better written as A and !A. + See: https://lore.kernel.org/lkml/1365563834.27174.12.camel@joe-AO722/ **COMPARISON_TO_NULL** @@ -492,6 +532,7 @@ Macros, Attributes and Symbols The kernel does *not* use the ``__DATE__`` and ``__TIME__`` macros, and enables warnings if they are used as they can lead to non-deterministic builds. + See: https://www.kernel.org/doc/html/latest/kbuild/reproducible-builds.html#timestamps **DEFINE_ARCH_HAS** @@ -502,6 +543,7 @@ Macros, Attributes and Symbols want architectures able to override them with optimized ones, we should either use weak functions (appropriate for some cases), or the symbol that protects them should be the same symbol we use. + See: https://lore.kernel.org/lkml/CA+55aFycQ9XJvEOsiM3txHL5bjUc8CeKWJNR_H+MiicaddB42Q@mail.gmail.com/ **INIT_ATTRIBUTE** @@ -528,6 +570,20 @@ Macros, Attributes and Symbols ... } + **MISPLACED_INIT** + It is possible to use section markers on variables in a way + which gcc doesn't understand (or at least not the way the + developer intended):: + + static struct __initdata samsung_pll_clock exynos4_plls[nr_plls] = { + + does not put exynos4_plls in the .initdata section. The __initdata + marker can be virtually anywhere on the line, except right after + "struct". The preferred location is before the "=" sign if there is + one, or before the trailing ";" otherwise. + + See: https://lore.kernel.org/lkml/1377655732.3619.19.camel@joe-AO722/ + **MULTISTATEMENT_MACRO_USE_DO_WHILE** Macros with multiple statements should be enclosed in a do - while block. Same should also be the case for macros @@ -541,6 +597,10 @@ Macros, Attributes and Symbols See: https://www.kernel.org/doc/html/latest/process/coding-style.html#macros-enums-and-rtl + **PREFER_FALLTHROUGH** + Use the `fallthrough;` pseudo keyword instead of + `/* fallthrough */` like comments. + **WEAK_DECLARATION** Using weak declarations like __attribute__((weak)) or __weak can have unintended link defects. Avoid using them. @@ -551,6 +611,7 @@ Functions and Variables **CAMELCASE** Avoid CamelCase Identifiers. + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#naming **FUNCTION_WITHOUT_ARGS** @@ -583,6 +644,27 @@ Functions and Variables return bar; +Permissions +----------- + + **EXECUTE_PERMISSIONS** + There is no reason for source files to be executable. The executable + bit can be removed safely. + + **EXPORTED_WORLD_WRITABLE** + Exporting world writable sysfs/debugfs files is usually a bad thing. + When done arbitrarily they can introduce serious security bugs. + In the past, some of the debugfs vulnerabilities would seemingly allow + any local user to write arbitrary values into device registers - a + situation from which little good can be expected to emerge. + + See: https://lore.kernel.org/linux-arm-kernel/cover.1296818921.git.segoon@openwall.com/ + + **NON_OCTAL_PERMISSIONS** + Permission bits should use 4 digit octal permissions (like 0700 or 0444). + Avoid using any other base like decimal. + + Spacing and Brackets -------------------- @@ -616,7 +698,7 @@ Spacing and Brackets 1. With a type on the left:: - ;int [] a; + int [] a; 2. At the beginning of a line for slice initialisers:: @@ -630,6 +712,7 @@ Spacing and Brackets Code indent should use tabs instead of spaces. Outside of comments, documentation and Kconfig, spaces are never used for indentation. + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#indentation **CONCATENATED_STRING** @@ -644,17 +727,20 @@ Spacing and Brackets **ELSE_AFTER_BRACE** `else {` should follow the closing block `}` on the same line. + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#placing-braces-and-spaces **LINE_SPACING** Vertical space is wasted given the limited number of lines an editor window can display when multiple blank lines are used. + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces **OPEN_BRACE** The opening brace should be following the function definitions on the next line. For any non-functional block it should be on the same line as the last construct. + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#placing-braces-and-spaces **POINTER_LOCATION** @@ -671,6 +757,7 @@ Spacing and Brackets **SPACING** Whitespace style used in the kernel sources is described in kernel docs. + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces **SWITCH_CASE_INDENT_LEVEL** @@ -700,8 +787,40 @@ Spacing and Brackets Trailing whitespace should always be removed. Some editors highlight the trailing whitespace and cause visual distractions when editing files. + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces + **UNNECESSARY_PARENTHESES** + Parentheses are not required in the following cases:: + + 1. Function pointer uses:: + + (foo->bar)(); + + could be:: + + foo->bar(); + + 2. Comparisons in if:: + + if ((foo->bar) && (foo->baz)) + if ((foo == bar)) + + could be:: + + if (foo->bar && foo->baz) + if (foo == bar) + + 3. addressof/dereference single Lvalues:: + + &(foo->bar) + *(foo->bar) + + could be:: + + &foo->bar + *foo->bar + **WHILE_AFTER_BRACE** while should follow the closing bracket on the same line:: @@ -727,13 +846,40 @@ Others For DOS-formatted patches, there are extra ^M symbols at the end of the line. These should be removed. - **EXECUTE_PERMISSIONS** - There is no reason for source files to be executable. The executable - bit can be removed safely. + **FSF_MAILING_ADDRESS** + Kernel maintainers reject new instances of the GPL boilerplate paragraph + directing people to write to the FSF for a copy of the GPL, since the + FSF has moved in the past and may do so again. + So do not write paragraphs about writing to the Free Software Foundation's + mailing address. - **NON_OCTAL_PERMISSIONS** - Permission bits should use 4 digit octal permissions (like 0700 or 0444). - Avoid using any other base like decimal. + See: https://lore.kernel.org/lkml/20131006222342.GT19510@leaf/ + + **LONG_LINE** + The line has exceeded the specified maximum length. Consider refactoring + it. + To use a different maximum line length, the --max-line-length=n option + may be added while invoking checkpatch. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings + + **LONG_LINE_STRING** + A string starts before but extends beyond the maximum line length. + To use a different maximum line length, the --max-line-length=n option + may be added while invoking checkpatch. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings + + **LONG_LINE_COMMENT** + A comment starts before but extends beyond the maximum line length. + To use a different maximum line length, the --max-line-length=n option + may be added while invoking checkpatch. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings + + **MEMSET** + The memset use appears to be incorrect. This may be caused due to + badly ordered parameters. Please recheck the usage. **NOT_UNIFIED_DIFF** The patch file does not appear to be in unified-diff format. Please @@ -742,6 +888,13 @@ Others **PRINTF_0XDECIMAL** Prefixing 0x with decimal output is defective and should be corrected. + **SPDX_LICENSE_TAG** + The source file is missing or has an improper SPDX identifier tag. + The Linux kernel requires the precise SPDX identifier in all source files, + and it is thoroughly documented in the kernel docs. + + See: https://www.kernel.org/doc/html/latest/process/license-rules.html + **TRAILING_STATEMENTS** Trailing statements (for example after any conditional) should be on the next line. @@ -753,3 +906,6 @@ Others if (x == y) break; + + **TYPO_SPELLING** + Some words may have been misspelled. Consider reviewing them. -- cgit v1.3.1 From fa5b8fef20b12bc7135e69a1b3689b1d677534de Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Wed, 12 May 2021 16:20:57 +0800 Subject: docs/zh_CN: add parisc index translation This patch translates Documentation/parisc/index.rst into Chinese. Signed-off-by: Yanteng Si Reviewed-by: Wu XiangCheng Link: https://lore.kernel.org/r/c13ce34b11a65e1f18c4e37566509ead82f2c15f.1620805100.git.siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- Documentation/translations/zh_CN/index.rst | 2 +- Documentation/translations/zh_CN/parisc/index.rst | 24 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/parisc/index.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/index.rst b/Documentation/translations/zh_CN/index.rst index 95c3f313cea1..a736057da41f 100644 --- a/Documentation/translations/zh_CN/index.rst +++ b/Documentation/translations/zh_CN/index.rst @@ -153,6 +153,7 @@ TODOList: arm64/index riscv/index openrisc/index + parisc/index TODOList: @@ -160,7 +161,6 @@ TODOList: * ia64/index * m68k/index * nios2/index -* parisc/index * powerpc/index * s390/index * sh/index diff --git a/Documentation/translations/zh_CN/parisc/index.rst b/Documentation/translations/zh_CN/parisc/index.rst new file mode 100644 index 000000000000..ef232d46b1ba --- /dev/null +++ b/Documentation/translations/zh_CN/parisc/index.rst @@ -0,0 +1,24 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/parisc/index.rst +:Translator: Yanteng Si + +.. _cn_parisc_index: + +==================== +PA-RISC体系架构 +==================== + +Todolist: + + debugging + registers + features + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` -- cgit v1.3.1 From b24247ded3e3616d225769bdeaf8782c244c80ee Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Wed, 12 May 2021 16:20:58 +0800 Subject: docs/zh_CN: add parisc debugging.rst translation This patch translates Documentation/parisc/debugging.rst into Chinese. Signed-off-by: Yanteng Si Link: https://lore.kernel.org/r/32661b39374f012442b760444ef149afcc0d22af.1620805100.git.siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/parisc/debugging.rst | 42 ++++++++++++++++++++++ Documentation/translations/zh_CN/parisc/index.rst | 6 +++- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/parisc/debugging.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/parisc/debugging.rst b/Documentation/translations/zh_CN/parisc/debugging.rst new file mode 100644 index 000000000000..c21beb986e15 --- /dev/null +++ b/Documentation/translations/zh_CN/parisc/debugging.rst @@ -0,0 +1,42 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/parisc/debugging.rst +:Translator: Yanteng Si + +.. _cn_parisc_debugging: + +================= +调试PA-RISC +================= + +好吧,这里有一些关于调试linux/parisc的较底层部分的信息。 + + +1. 绝对地址 +===================== + +很多汇编代码目前运行在实模式下,这意味着会使用绝对地址,而不是像内核其他 +部分那样使用虚拟地址。要将绝对地址转换为虚拟地址,你可以在System.map中查 +找,添加__PAGE_OFFSET(目前是0x10000000)。 + + +2. HPMCs +======== + +当实模式的代码试图访问不存在的内存时,会出现HPMC(high priority machine +check)而不是内核oops。若要调试HPMC,请尝试找到系统响应程序/请求程序地址。 +系统请求程序地址应该与(某)处理器的HPA(I/O范围内的高地址)相匹配;系统响应程 +序地址是实模式代码试图访问的地址。 + +系统响应程序地址的典型值是大于__PAGE_OFFSET (0x10000000)的地址,这意味着 +在实模式试图访问它之前,虚拟地址没有被翻译成物理地址。 + + +3. 有趣的Q位 +============ + +某些非常关键的代码必须清除PSW中的Q位。当Q位被清除时,CPU不会更新中断处理 +程序所读取的寄存器,以找出机器被中断的位置——所以如果你在清除Q位的指令和再 +次设置Q位的RFI之间遇到中断,你不知道它到底发生在哪里。如果你幸运的话,IAOQ +会指向清除Q位的指令,如果你不幸运的话,它会指向任何地方。通常Q位的问题会 +表现为无法解释的系统挂起或物理内存越界。 diff --git a/Documentation/translations/zh_CN/parisc/index.rst b/Documentation/translations/zh_CN/parisc/index.rst index ef232d46b1ba..b913d664e735 100644 --- a/Documentation/translations/zh_CN/parisc/index.rst +++ b/Documentation/translations/zh_CN/parisc/index.rst @@ -10,9 +10,13 @@ PA-RISC体系架构 ==================== -Todolist: +.. toctree:: + :maxdepth: 2 debugging + +Todolist: + registers features -- cgit v1.3.1 From 5fb82175a2aeb44d174ec60d264e54cb6e1e55f4 Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Wed, 12 May 2021 16:20:59 +0800 Subject: docs/zh_CN: add parisc registers.rst translation This patch translates Documentation/parisc/registers.rst into Chinese. Signed-off-by: Yanteng Si Reviewed-by: Wu XiangCheng Link: https://lore.kernel.org/r/b8375b5cd2c5163691691fe4757511ce984f3b83.1620805100.git.siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- Documentation/translations/zh_CN/parisc/index.rst | 2 +- .../translations/zh_CN/parisc/registers.rst | 153 +++++++++++++++++++++ 2 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/parisc/registers.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/parisc/index.rst b/Documentation/translations/zh_CN/parisc/index.rst index b913d664e735..a47454ebe32e 100644 --- a/Documentation/translations/zh_CN/parisc/index.rst +++ b/Documentation/translations/zh_CN/parisc/index.rst @@ -14,10 +14,10 @@ PA-RISC体系架构 :maxdepth: 2 debugging + registers Todolist: - registers features .. only:: subproject and html diff --git a/Documentation/translations/zh_CN/parisc/registers.rst b/Documentation/translations/zh_CN/parisc/registers.rst new file mode 100644 index 000000000000..71e2404cd103 --- /dev/null +++ b/Documentation/translations/zh_CN/parisc/registers.rst @@ -0,0 +1,153 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/parisc/registers.rst +:Translator: Yanteng Si + +.. _cn_parisc_registers: + +========================= +Linux/PA-RISC的寄存器用法 +========================= + +[ 用星号表示目前尚未实现的计划用途。 ] + +ABI约定的通用寄存器 +=================== + +控制寄存器 +---------- + +============================ ================================= +CR 0 (恢复计数器) 用于ptrace +CR 1-CR 7(无定义) 未使用 +CR 8 (Protection ID) 每进程值* +CR 9, 12, 13 (PIDS) 未使用 +CR10 (CCR) FPU延迟保存* +CR11 按照ABI的规定(SAR) +CR14 (中断向量) 初始化为 fault_vector +CR15 (EIEM) 所有位初始化为1* +CR16 (间隔计时器) 读取周期数/写入开始时间间隔计时器 +CR17-CR22 中断参数 +CR19 中断指令寄存器 +CR20 中断空间寄存器 +CR21 中断偏移量寄存器 +CR22 中断 PSW +CR23 (EIRR) 读取未决中断/写入清除位 +CR24 (TR 0) 内核空间页目录指针 +CR25 (TR 1) 用户空间页目录指针 +CR26 (TR 2) 不使用 +CR27 (TR 3) 线程描述符指针 +CR28 (TR 4) 不使用 +CR29 (TR 5) 不使用 +CR30 (TR 6) 当前 / 0 +CR31 (TR 7) 临时寄存器,在不同地方使用 +============================ ================================= + +空间寄存器(内核模式) +---------------------- + +======== ============================== +SR0 临时空间寄存器 +SR4-SR7 设置为0 +SR1 临时空间寄存器 +SR2 内核不应该破坏它 +SR3 用于用户空间访问(当前进程) +======== ============================== + +空间寄存器(用户模式) +---------------------- + +======== ============================ +SR0 临时空间寄存器 +SR1 临时空间寄存器 +SR2 保存Linux gateway page的空间 +SR3 在内核中保存用户地址空间的值 +SR4-SR7 定义了用户/内核的短地址空间 +======== ============================ + + +处理器状态字 +------------ + +====================== ================================================ +W (64位地址) 0 +E (小尾端) 0 +S (安全间隔计时器) 0 +T (产生分支陷阱) 0 +H (高特权级陷阱) 0 +L (低特权级陷阱) 0 +N (撤销下一条指令) 被C代码使用 +X (数据存储中断禁用) 0 +B (产生分支) 被C代码使用 +C (代码地址转译) 1, 在执行实模式代码时为0 +V (除法步长校正) 被C代码使用 +M (HPMC 掩码) 0, 在执行HPMC操作*时为1 +C/B (进/借 位) 被C代码使用 +O (有序引用) 1* +F (性能监视器) 0 +R (回收计数器陷阱) 0 +Q (收集中断状态) 1 (在rfi之前的代码中为0) +P (保护标识符) 1* +D (数据地址转译) 1, 在执行实模式代码时为0 +I (外部中断掩码) 由cli()/sti()宏使用。 +====================== ================================================ + +“隐形”寄存器(影子寄存器) +--------------------------- + +============= =================== +PSW W 默认值 0 +PSW E 默认值 0 +影子寄存器 被中断处理代码使用 +TOC启用位 1 +============= =================== + +---------------------------------------------------------- + +PA-RISC架构定义了7个寄存器作为“影子寄存器”。这些寄存器在 +RETURN FROM INTERRUPTION AND RESTORE指令中使用,通过消 +除中断处理程序中对一般寄存器(GR)的保存和恢复的需要来减 +少状态保存和恢复时间。影子寄存器是GRs 1, 8, 9, 16, 17, +24和25。 + +------------------------------------------------------------------------- + +寄存器使用说明,最初由John Marvin提供,并由Randolph Chung提供一些补充说明。 + +对于通用寄存器: + +r1,r2,r19-r26,r28,r29 & r31可以在不保存它们的情况下被使用。当然,如果你 +关心它们,在调用另一个程序之前,你也需要保存它们。上面的一些寄存器确实 +有特殊的含义,你应该注意一下: + + r1: + addil指令是硬性规定将其结果放在r1中,所以如果你使用这条指令要 + 注意这点。 + + r2: + 这就是返回指针。一般来说,你不想使用它,因为你需要这个指针来返 + 回给你的调用者。然而,它与这组寄存器组合在一起,因为调用者不能 + 依赖你返回时的值是相同的,也就是说,你可以将r2复制到另一个寄存 + 器,并在作废r2后通过该寄存器返回,这应该不会给调用程序带来问题。 + + r19-r22: + 这些通常被认为是临时寄存器。 + 请注意,在64位中它们是arg7-arg4。 + + r23-r26: + 这些是arg3-arg0,也就是说,如果你不再关心传入的值,你可以使用 + 它们。 + + r28,r29: + 这俩是ret0和ret1。它们是你传入返回值的地方。r28是主返回值。当返回 + 小结构体时,r29也可以用来将数据传回给调用程序。 + + r30: + 栈指针 + + r31: + ble指令将返回指针放在这里。 + + + r3-r18,r27,r30需要被保存和恢复。r3-r18只是一般用途的寄存器。 + r27是数据指针,用来使对全局变量的引用更容易。r30是栈指针。 -- cgit v1.3.1 From 2bc602cb0e0d92afec57967cf2212b66cba42ea5 Mon Sep 17 00:00:00 2001 From: Yue Hu Date: Thu, 20 May 2021 15:42:25 +0800 Subject: docs: block: blk-mq.rst: correct drive -> driver It is 'driver' to complete the request. Also remove a redundant space. Signed-off-by: Yue Hu Link: https://lore.kernel.org/r/20210520074225.1989-1-zbestahu@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/block/blk-mq.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/block/blk-mq.rst b/Documentation/block/blk-mq.rst index a980d23af48c..d96118c73954 100644 --- a/Documentation/block/blk-mq.rst +++ b/Documentation/block/blk-mq.rst @@ -62,7 +62,7 @@ queue, to be sent in the future, when the hardware is able. Software staging queues ~~~~~~~~~~~~~~~~~~~~~~~ -The block IO subsystem adds requests in the software staging queues +The block IO subsystem adds requests in the software staging queues (represented by struct blk_mq_ctx) in case that they weren't sent directly to the driver. A request is one or more BIOs. They arrived at the block layer through the data structure struct bio. The block layer @@ -132,7 +132,7 @@ In order to indicate which request has been completed, every request is identified by an integer, ranging from 0 to the dispatch queue size. This tag is generated by the block layer and later reused by the device driver, removing the need to create a redundant identifier. When a request is completed in the -drive, the tag is sent back to the block layer to notify it of the finalization. +driver, the tag is sent back to the block layer to notify it of the finalization. This removes the need to do a linear search to find out which IO has been completed. -- cgit v1.3.1 From 0e7c52da1ab82338fc91021cc34e8f2fdaf73de4 Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Thu, 20 May 2021 19:09:49 +0930 Subject: Documentation: checkpatch: Tweak BIT() macro include While include/linux/bitops.h brings in the BIT() macro, it was moved to include/linux/bits.h in commit 8bd9cb51daac ("locking/atomics, asm-generic: Move some macros from to a new file"). Since that commit BIT() has moved again into include/vdso/bits.h via commit 3945ff37d2f4 ("linux/bits.h: Extract common header for vDSO"). I think the move to the vDSO header can be considered an implementation detail, so for now update the checkpatch documentation to recommend use of include/linux/bits.h. Signed-off-by: Andrew Jeffery Acked-by: Jiri Slaby Acked-by: Lukas Bulwahn Acked-by: Dwaipayan Ray Cc: Jiri Slaby Link: https://lore.kernel.org/r/20210520093949.511471-1-andrew@aj.id.au Signed-off-by: Jonathan Corbet --- Documentation/dev-tools/checkpatch.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/dev-tools/checkpatch.rst b/Documentation/dev-tools/checkpatch.rst index e409f27f48b6..87b859f321de 100644 --- a/Documentation/dev-tools/checkpatch.rst +++ b/Documentation/dev-tools/checkpatch.rst @@ -512,7 +512,7 @@ Macros, Attributes and Symbols **BIT_MACRO** Defines like: 1 << could be BIT(digit). - The BIT() macro is defined in include/linux/bitops.h:: + The BIT() macro is defined via include/linux/bits.h:: #define BIT(nr) (1UL << (nr)) -- cgit v1.3.1 From 10505b720189ecc3852596a70a7e391b2a5c5b57 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 20 May 2021 22:36:08 -0300 Subject: usb: Restore the usb_header label Commit caa93d9bd2d7 ("usb: Fix up movement of USB core kerneldoc location") removed the reference to the _usb_header label by mistake, which causes the following htmldocs build warning: Documentation/driver-api/usb/writing_usb_driver.rst:129: WARNING: undefined label: usb_header Restore the label. Fixes: caa93d9bd2d7 ("usb: Fix up movement of USB core kerneldoc location") Reported-by: Stephen Rothwell Signed-off-by: Fabio Estevam Link: https://lore.kernel.org/r/20210521013608.17957-1-festevam@gmail.com Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/usb/usb.rst | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/driver-api/usb/usb.rst b/Documentation/driver-api/usb/usb.rst index 820e867af45a..2c94ff2f4385 100644 --- a/Documentation/driver-api/usb/usb.rst +++ b/Documentation/driver-api/usb/usb.rst @@ -123,6 +123,8 @@ are in ``drivers/usb/common/common.c``. In addition, some functions useful for creating debugging output are defined in ``drivers/usb/common/debug.c``. +.. _usb_header: + Host-Side Data Types and Macros =============================== -- cgit v1.3.1 From 58c08df5751d823332ccdb49f1d5795479097119 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 21 Apr 2021 15:58:40 +0200 Subject: media: rc: remove tango ir driver and keymap The tango platform was removed, so the driver is no longer needed. Cc: Marc Gonzalez Acked-by: Rob Herring Acked-by: Mans Rullgard Signed-off-by: Arnd Bergmann Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/rc.yaml | 1 - .../devicetree/bindings/media/tango-ir.txt | 21 -- drivers/media/rc/Kconfig | 10 - drivers/media/rc/Makefile | 1 - drivers/media/rc/keymaps/Makefile | 1 - drivers/media/rc/keymaps/rc-tango.c | 89 ------- drivers/media/rc/tango-ir.c | 267 --------------------- include/media/rc-map.h | 1 - 8 files changed, 391 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/tango-ir.txt delete mode 100644 drivers/media/rc/keymaps/rc-tango.c delete mode 100644 drivers/media/rc/tango-ir.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/rc.yaml b/Documentation/devicetree/bindings/media/rc.yaml index af9e7e59e5a1..12d838b05632 100644 --- a/Documentation/devicetree/bindings/media/rc.yaml +++ b/Documentation/devicetree/bindings/media/rc.yaml @@ -125,7 +125,6 @@ properties: - rc-snapstream-firefly - rc-streamzap - rc-su3000 - - rc-tango - rc-tanix-tx3mini - rc-tanix-tx5max - rc-tbs-nec diff --git a/Documentation/devicetree/bindings/media/tango-ir.txt b/Documentation/devicetree/bindings/media/tango-ir.txt deleted file mode 100644 index a9f00c2bf897..000000000000 --- a/Documentation/devicetree/bindings/media/tango-ir.txt +++ /dev/null @@ -1,21 +0,0 @@ -Sigma Designs Tango IR NEC/RC-5/RC-6 decoder (SMP86xx and SMP87xx) - -Required properties: - -- compatible: "sigma,smp8642-ir" -- reg: address/size of NEC+RC5 area, address/size of RC6 area -- interrupts: spec for IR IRQ -- clocks: spec for IR clock (typically the crystal oscillator) - -Optional properties: - -- linux,rc-map-name: see Documentation/devicetree/bindings/media/rc.txt - -Example: - - ir@10518 { - compatible = "sigma,smp8642-ir"; - reg = <0x10518 0x18>, <0x105e0 0x1c>; - interrupts = <21 IRQ_TYPE_EDGE_RISING>; - clocks = <&xtal>; - }; diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index f016b35c2b17..ae0025fba21c 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -499,16 +499,6 @@ config IR_SIR To compile this driver as a module, choose M here: the module will be called sir-ir. -config IR_TANGO - tristate "Sigma Designs SMP86xx IR decoder" - depends on RC_CORE - depends on ARCH_TANGO || COMPILE_TEST - help - Adds support for the HW IR decoder embedded on Sigma Designs - Tango-based systems (SMP86xx, SMP87xx). - The HW decoder supports NEC, RC-5, RC-6 IR protocols. - When compiled as a module, look for tango-ir. - config RC_XBOX_DVD tristate "Xbox DVD Movie Playback Kit" depends on RC_CORE diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index f31002288f7c..692e9b6b203f 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -48,6 +48,5 @@ obj-$(CONFIG_IR_IMG) += img-ir/ obj-$(CONFIG_IR_SERIAL) += serial_ir.o obj-$(CONFIG_IR_SIR) += sir_ir.o obj-$(CONFIG_IR_MTK) += mtk-cir.o -obj-$(CONFIG_IR_TANGO) += tango-ir.o obj-$(CONFIG_RC_XBOX_DVD) += xbox_remote.o obj-$(CONFIG_IR_TOY) += ir_toy.o diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 50b2833dbe4f..f609dfe7fd76 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -100,7 +100,6 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-reddo.o \ rc-snapstream-firefly.o \ rc-streamzap.o \ - rc-tango.o \ rc-tanix-tx3mini.o \ rc-tanix-tx5max.o \ rc-tbs-nec.o \ diff --git a/drivers/media/rc/keymaps/rc-tango.c b/drivers/media/rc/keymaps/rc-tango.c deleted file mode 100644 index 2b9cef6ef5b5..000000000000 --- a/drivers/media/rc/keymaps/rc-tango.c +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2017 Sigma Designs - */ - -#include -#include - -static struct rc_map_table tango_table[] = { - { 0x4cb4a, KEY_POWER }, - { 0x4cb48, KEY_FILE }, - { 0x4cb0f, KEY_SETUP }, - { 0x4cb4d, KEY_SUSPEND }, - { 0x4cb4e, KEY_VOLUMEUP }, - { 0x4cb44, KEY_EJECTCD }, - { 0x4cb13, KEY_TV }, - { 0x4cb51, KEY_MUTE }, - { 0x4cb52, KEY_VOLUMEDOWN }, - - { 0x4cb41, KEY_NUMERIC_1 }, - { 0x4cb03, KEY_NUMERIC_2 }, - { 0x4cb42, KEY_NUMERIC_3 }, - { 0x4cb45, KEY_NUMERIC_4 }, - { 0x4cb07, KEY_NUMERIC_5 }, - { 0x4cb46, KEY_NUMERIC_6 }, - { 0x4cb55, KEY_NUMERIC_7 }, - { 0x4cb17, KEY_NUMERIC_8 }, - { 0x4cb56, KEY_NUMERIC_9 }, - { 0x4cb1b, KEY_NUMERIC_0 }, - { 0x4cb59, KEY_DELETE }, - { 0x4cb5a, KEY_CAPSLOCK }, - - { 0x4cb47, KEY_BACK }, - { 0x4cb05, KEY_SWITCHVIDEOMODE }, - { 0x4cb06, KEY_UP }, - { 0x4cb43, KEY_LEFT }, - { 0x4cb01, KEY_RIGHT }, - { 0x4cb0a, KEY_DOWN }, - { 0x4cb02, KEY_ENTER }, - { 0x4cb4b, KEY_INFO }, - { 0x4cb09, KEY_HOME }, - - { 0x4cb53, KEY_MENU }, - { 0x4cb12, KEY_PREVIOUS }, - { 0x4cb50, KEY_PLAY }, - { 0x4cb11, KEY_NEXT }, - { 0x4cb4f, KEY_TITLE }, - { 0x4cb0e, KEY_REWIND }, - { 0x4cb4c, KEY_STOP }, - { 0x4cb0d, KEY_FORWARD }, - { 0x4cb57, KEY_MEDIA_REPEAT }, - { 0x4cb16, KEY_ANGLE }, - { 0x4cb54, KEY_PAUSE }, - { 0x4cb15, KEY_SLOW }, - { 0x4cb5b, KEY_TIME }, - { 0x4cb1a, KEY_AUDIO }, - { 0x4cb58, KEY_SUBTITLE }, - { 0x4cb19, KEY_ZOOM }, - - { 0x4cb5f, KEY_RED }, - { 0x4cb1e, KEY_GREEN }, - { 0x4cb5c, KEY_YELLOW }, - { 0x4cb1d, KEY_BLUE }, -}; - -static struct rc_map_list tango_map = { - .map = { - .scan = tango_table, - .size = ARRAY_SIZE(tango_table), - .rc_proto = RC_PROTO_NECX, - .name = RC_MAP_TANGO, - } -}; - -static int __init init_rc_map_tango(void) -{ - return rc_map_register(&tango_map); -} - -static void __exit exit_rc_map_tango(void) -{ - rc_map_unregister(&tango_map); -} - -module_init(init_rc_map_tango) -module_exit(exit_rc_map_tango) - -MODULE_AUTHOR("Sigma Designs"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/tango-ir.c b/drivers/media/rc/tango-ir.c deleted file mode 100644 index b8eb5bc4d9be..000000000000 --- a/drivers/media/rc/tango-ir.c +++ /dev/null @@ -1,267 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2015 Mans Rullgard - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_NAME "tango-ir" - -#define IR_NEC_CTRL 0x00 -#define IR_NEC_DATA 0x04 -#define IR_CTRL 0x08 -#define IR_RC5_CLK_DIV 0x0c -#define IR_RC5_DATA 0x10 -#define IR_INT 0x14 - -#define NEC_TIME_BASE 560 -#define RC5_TIME_BASE 1778 - -#define RC6_CTRL 0x00 -#define RC6_CLKDIV 0x04 -#define RC6_DATA0 0x08 -#define RC6_DATA1 0x0c -#define RC6_DATA2 0x10 -#define RC6_DATA3 0x14 -#define RC6_DATA4 0x18 - -#define RC6_CARRIER 36000 -#define RC6_TIME_BASE 16 - -#define NEC_CAP(n) ((n) << 24) -#define GPIO_SEL(n) ((n) << 16) -#define DISABLE_NEC (BIT(4) | BIT(8)) -#define ENABLE_RC5 (BIT(0) | BIT(9)) -#define ENABLE_RC6 (BIT(0) | BIT(7)) -#define ACK_IR_INT (BIT(0) | BIT(1)) -#define ACK_RC6_INT (BIT(31)) - -#define NEC_ANY (RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32) - -struct tango_ir { - void __iomem *rc5_base; - void __iomem *rc6_base; - struct rc_dev *rc; - struct clk *clk; -}; - -static void tango_ir_handle_nec(struct tango_ir *ir) -{ - u32 v, code; - enum rc_proto proto; - - v = readl_relaxed(ir->rc5_base + IR_NEC_DATA); - if (!v) { - rc_repeat(ir->rc); - return; - } - - code = ir_nec_bytes_to_scancode(v, v >> 8, v >> 16, v >> 24, &proto); - rc_keydown(ir->rc, proto, code, 0); -} - -static void tango_ir_handle_rc5(struct tango_ir *ir) -{ - u32 data, field, toggle, addr, cmd, code; - - data = readl_relaxed(ir->rc5_base + IR_RC5_DATA); - if (data & BIT(31)) - return; - - field = data >> 12 & 1; - toggle = data >> 11 & 1; - addr = data >> 6 & 0x1f; - cmd = (data & 0x3f) | (field ^ 1) << 6; - - code = RC_SCANCODE_RC5(addr, cmd); - rc_keydown(ir->rc, RC_PROTO_RC5, code, toggle); -} - -static void tango_ir_handle_rc6(struct tango_ir *ir) -{ - u32 data0, data1, toggle, mode, addr, cmd, code; - - data0 = readl_relaxed(ir->rc6_base + RC6_DATA0); - data1 = readl_relaxed(ir->rc6_base + RC6_DATA1); - - mode = data0 >> 1 & 7; - if (mode != 0) - return; - - toggle = data0 & 1; - addr = data0 >> 16; - cmd = data1; - - code = RC_SCANCODE_RC6_0(addr, cmd); - rc_keydown(ir->rc, RC_PROTO_RC6_0, code, toggle); -} - -static irqreturn_t tango_ir_irq(int irq, void *dev_id) -{ - struct tango_ir *ir = dev_id; - unsigned int rc5_stat; - unsigned int rc6_stat; - - rc5_stat = readl_relaxed(ir->rc5_base + IR_INT); - writel_relaxed(rc5_stat, ir->rc5_base + IR_INT); - - rc6_stat = readl_relaxed(ir->rc6_base + RC6_CTRL); - writel_relaxed(rc6_stat, ir->rc6_base + RC6_CTRL); - - if (!(rc5_stat & 3) && !(rc6_stat & BIT(31))) - return IRQ_NONE; - - if (rc5_stat & BIT(0)) - tango_ir_handle_rc5(ir); - - if (rc5_stat & BIT(1)) - tango_ir_handle_nec(ir); - - if (rc6_stat & BIT(31)) - tango_ir_handle_rc6(ir); - - return IRQ_HANDLED; -} - -static int tango_change_protocol(struct rc_dev *dev, u64 *rc_type) -{ - struct tango_ir *ir = dev->priv; - u32 rc5_ctrl = DISABLE_NEC; - u32 rc6_ctrl = 0; - - if (*rc_type & NEC_ANY) - rc5_ctrl = 0; - - if (*rc_type & RC_PROTO_BIT_RC5) - rc5_ctrl |= ENABLE_RC5; - - if (*rc_type & RC_PROTO_BIT_RC6_0) - rc6_ctrl = ENABLE_RC6; - - writel_relaxed(rc5_ctrl, ir->rc5_base + IR_CTRL); - writel_relaxed(rc6_ctrl, ir->rc6_base + RC6_CTRL); - - return 0; -} - -static int tango_ir_probe(struct platform_device *pdev) -{ - const char *map_name = RC_MAP_TANGO; - struct device *dev = &pdev->dev; - struct rc_dev *rc; - struct tango_ir *ir; - u64 clkrate, clkdiv; - int irq, err; - u32 val; - - irq = platform_get_irq(pdev, 0); - if (irq <= 0) - return -EINVAL; - - ir = devm_kzalloc(dev, sizeof(*ir), GFP_KERNEL); - if (!ir) - return -ENOMEM; - - ir->rc5_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(ir->rc5_base)) - return PTR_ERR(ir->rc5_base); - - ir->rc6_base = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(ir->rc6_base)) - return PTR_ERR(ir->rc6_base); - - ir->clk = devm_clk_get(dev, NULL); - if (IS_ERR(ir->clk)) - return PTR_ERR(ir->clk); - - rc = devm_rc_allocate_device(dev, RC_DRIVER_SCANCODE); - if (!rc) - return -ENOMEM; - - of_property_read_string(dev->of_node, "linux,rc-map-name", &map_name); - - rc->device_name = DRIVER_NAME; - rc->driver_name = DRIVER_NAME; - rc->input_phys = DRIVER_NAME "/input0"; - rc->map_name = map_name; - rc->allowed_protocols = NEC_ANY | RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_0; - rc->change_protocol = tango_change_protocol; - rc->priv = ir; - ir->rc = rc; - - err = clk_prepare_enable(ir->clk); - if (err) - return err; - - clkrate = clk_get_rate(ir->clk); - - clkdiv = clkrate * NEC_TIME_BASE; - do_div(clkdiv, 1000000); - - val = NEC_CAP(31) | GPIO_SEL(12) | clkdiv; - writel_relaxed(val, ir->rc5_base + IR_NEC_CTRL); - - clkdiv = clkrate * RC5_TIME_BASE; - do_div(clkdiv, 1000000); - - writel_relaxed(DISABLE_NEC, ir->rc5_base + IR_CTRL); - writel_relaxed(clkdiv, ir->rc5_base + IR_RC5_CLK_DIV); - writel_relaxed(ACK_IR_INT, ir->rc5_base + IR_INT); - - clkdiv = clkrate * RC6_TIME_BASE; - do_div(clkdiv, RC6_CARRIER); - - writel_relaxed(ACK_RC6_INT, ir->rc6_base + RC6_CTRL); - writel_relaxed((clkdiv >> 2) << 18 | clkdiv, ir->rc6_base + RC6_CLKDIV); - - err = devm_request_irq(dev, irq, tango_ir_irq, IRQF_SHARED, - dev_name(dev), ir); - if (err) - goto err_clk; - - err = devm_rc_register_device(dev, rc); - if (err) - goto err_clk; - - platform_set_drvdata(pdev, ir); - return 0; - -err_clk: - clk_disable_unprepare(ir->clk); - return err; -} - -static int tango_ir_remove(struct platform_device *pdev) -{ - struct tango_ir *ir = platform_get_drvdata(pdev); - - clk_disable_unprepare(ir->clk); - return 0; -} - -static const struct of_device_id tango_ir_dt_ids[] = { - { .compatible = "sigma,smp8642-ir" }, - { } -}; -MODULE_DEVICE_TABLE(of, tango_ir_dt_ids); - -static struct platform_driver tango_ir_driver = { - .probe = tango_ir_probe, - .remove = tango_ir_remove, - .driver = { - .name = DRIVER_NAME, - .of_match_table = tango_ir_dt_ids, - }, -}; -module_platform_driver(tango_ir_driver); - -MODULE_DESCRIPTION("SMP86xx IR decoder driver"); -MODULE_AUTHOR("Mans Rullgard "); -MODULE_LICENSE("GPL"); diff --git a/include/media/rc-map.h b/include/media/rc-map.h index b5585d14fff4..b50443d6fd77 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -312,7 +312,6 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_SNAPSTREAM_FIREFLY "rc-snapstream-firefly" #define RC_MAP_STREAMZAP "rc-streamzap" #define RC_MAP_SU3000 "rc-su3000" -#define RC_MAP_TANGO "rc-tango" #define RC_MAP_TANIX_TX3MINI "rc-tanix-tx3mini" #define RC_MAP_TANIX_TX5MAX "rc-tanix-tx5max" #define RC_MAP_TBS_NEC "rc-tbs-nec" -- cgit v1.3.1 From c3d175e4852bfdfd1e4021dff8715fc407dedd98 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 12 May 2021 16:15:48 +0200 Subject: cpufreq: intel_pstate: hybrid: Avoid exposing two global attributes The turbo_pct and num_pstates sysfs attributes represent CPU properties that may be different for differenty types of CPUs in a hybrid processor, so avoid exposing them in that case. Signed-off-by: Rafael J. Wysocki --- Documentation/admin-guide/pm/intel_pstate.rst | 6 ++++++ drivers/cpufreq/intel_pstate.c | 15 +++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/pm/intel_pstate.rst b/Documentation/admin-guide/pm/intel_pstate.rst index df29b4f1f219..235f1025a7e6 100644 --- a/Documentation/admin-guide/pm/intel_pstate.rst +++ b/Documentation/admin-guide/pm/intel_pstate.rst @@ -365,6 +365,9 @@ argument is passed to the kernel in the command line. inclusive) including both turbo and non-turbo P-states (see `Turbo P-states Support`_). + This attribute is present only if the value exposed by it is the same + for all of the CPUs in the system. + The value of this attribute is not affected by the ``no_turbo`` setting described `below `_. @@ -374,6 +377,9 @@ argument is passed to the kernel in the command line. Ratio of the `turbo range `_ size to the size of the entire range of supported P-states, in percent. + This attribute is present only if the value exposed by it is the same + for all of the CPUs in the system. + This attribute is read-only. .. _no_turbo_attr: diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 0e69dffd5a76..45f59e2827fe 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1365,8 +1365,6 @@ define_one_global_rw(energy_efficiency); static struct attribute *intel_pstate_attributes[] = { &status.attr, &no_turbo.attr, - &turbo_pct.attr, - &num_pstates.attr, NULL }; @@ -1391,6 +1389,14 @@ static void __init intel_pstate_sysfs_expose_params(void) if (WARN_ON(rc)) return; + if (!boot_cpu_has(X86_FEATURE_HYBRID_CPU)) { + rc = sysfs_create_file(intel_pstate_kobject, &turbo_pct.attr); + WARN_ON(rc); + + rc = sysfs_create_file(intel_pstate_kobject, &num_pstates.attr); + WARN_ON(rc); + } + /* * If per cpu limits are enforced there are no global limits, so * return without creating max/min_perf_pct attributes @@ -1417,6 +1423,11 @@ static void __init intel_pstate_sysfs_remove(void) sysfs_remove_group(intel_pstate_kobject, &intel_pstate_attr_group); + if (!boot_cpu_has(X86_FEATURE_HYBRID_CPU)) { + sysfs_remove_file(intel_pstate_kobject, &num_pstates.attr); + sysfs_remove_file(intel_pstate_kobject, &turbo_pct.attr); + } + if (!per_cpu_limits) { sysfs_remove_file(intel_pstate_kobject, &max_perf_pct.attr); sysfs_remove_file(intel_pstate_kobject, &min_perf_pct.attr); -- cgit v1.3.1 From 9acc89d31f0c94c8e573ed61f3e4340bbd526d0c Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Fri, 14 May 2021 17:27:44 +0200 Subject: evm: Refuse EVM_ALLOW_METADATA_WRITES only if an HMAC key is loaded EVM_ALLOW_METADATA_WRITES is an EVM initialization flag that can be set to temporarily disable metadata verification until all xattrs/attrs necessary to verify an EVM portable signature are copied to the file. This flag is cleared when EVM is initialized with an HMAC key, to avoid that the HMAC is calculated on unverified xattrs/attrs. Currently EVM unnecessarily denies setting this flag if EVM is initialized with a public key, which is not a concern as it cannot be used to trust xattrs/attrs updates. This patch removes this limitation. Fixes: ae1ba1676b88e ("EVM: Allow userland to permit modification of EVM-protected metadata") Signed-off-by: Roberto Sassu Cc: stable@vger.kernel.org # 4.16.x Signed-off-by: Mimi Zohar --- Documentation/ABI/testing/evm | 26 ++++++++++++++++++++++++-- security/integrity/evm/evm_secfs.c | 8 ++++---- 2 files changed, 28 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/evm b/Documentation/ABI/testing/evm index 3c477ba48a31..2243b72e4110 100644 --- a/Documentation/ABI/testing/evm +++ b/Documentation/ABI/testing/evm @@ -49,8 +49,30 @@ Description: modification of EVM-protected metadata and disable all further modification of policy - Note that once a key has been loaded, it will no longer be - possible to enable metadata modification. + Echoing a value is additive, the new value is added to the + existing initialization flags. + + For example, after:: + + echo 2 >/evm + + another echo can be performed:: + + echo 1 >/evm + + and the resulting value will be 3. + + Note that once an HMAC key has been loaded, it will no longer + be possible to enable metadata modification. Signaling that an + HMAC key has been loaded will clear the corresponding flag. + For example, if the current value is 6 (2 and 4 set):: + + echo 1 >/evm + + will set the new value to 3 (4 cleared). + + Loading an HMAC key is the only way to disable metadata + modification. Until key loading has been signaled EVM can not create or validate the 'security.evm' xattr, but returns diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c index 0007d3362754..5f0da41bccd0 100644 --- a/security/integrity/evm/evm_secfs.c +++ b/security/integrity/evm/evm_secfs.c @@ -81,12 +81,12 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf, if (!i || (i & ~EVM_INIT_MASK) != 0) return -EINVAL; - /* Don't allow a request to freshly enable metadata writes if - * keys are loaded. + /* + * Don't allow a request to enable metadata writes if + * an HMAC key is loaded. */ if ((i & EVM_ALLOW_METADATA_WRITES) && - ((evm_initialized & EVM_KEY_MASK) != 0) && - !(evm_initialized & EVM_ALLOW_METADATA_WRITES)) + (evm_initialized & EVM_INIT_HMAC) != 0) return -EPERM; if (i & EVM_INIT_HMAC) { -- cgit v1.3.1 From 118f3e1562f2b15e30ed65a2718cd9ed710054b1 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 29 Apr 2021 16:48:09 +0200 Subject: media: uapi: mpeg2: Rename "quantization" to "quantisation" The MPEG-2 specification refers to the quantisation matrices using the word "quantisation". Make the V4L2 interface more ergonomic by matching the MPEG-2 spec. Signed-off-by: Ezequiel Garcia Tested-by: Jernej Skrabec Reviewed-by: Jernej Skrabec Tested-by: Daniel Almeida Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/ext-ctrls-codec.rst | 16 ++++++------- .../userspace-api/media/v4l/pixfmt-compressed.rst | 4 ++-- .../userspace-api/media/v4l/vidioc-queryctrl.rst | 6 ++--- .../userspace-api/media/videodev2.h.rst.exceptions | 2 +- drivers/media/v4l2-core/v4l2-ctrls.c | 12 +++++----- drivers/staging/media/hantro/hantro_drv.c | 2 +- drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c | 17 ++++++-------- drivers/staging/media/hantro/hantro_hw.h | 2 +- drivers/staging/media/hantro/hantro_mpeg2.c | 2 +- .../staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c | 14 +++++------- drivers/staging/media/sunxi/cedrus/cedrus.c | 2 +- drivers/staging/media/sunxi/cedrus/cedrus.h | 2 +- drivers/staging/media/sunxi/cedrus/cedrus_dec.c | 4 ++-- drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c | 26 +++++++++++----------- include/media/mpeg2-ctrls.h | 6 ++--- include/media/v4l2-ctrls.h | 4 ++-- 16 files changed, 58 insertions(+), 63 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index 514b334470ea..2835ce739478 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -1755,8 +1755,8 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - \normalsize -``V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION (struct)`` - Specifies quantization matrices (as extracted from the bitstream) for the +``V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION (struct)`` + Specifies quantisation matrices (as extracted from the bitstream) for the associated MPEG-2 slice data. .. note:: @@ -1764,7 +1764,7 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - This compound control is not yet part of the public kernel API and it is expected to change. -.. c:type:: v4l2_ctrl_mpeg2_quantization +.. c:type:: v4l2_ctrl_mpeg2_quantisation .. tabularcolumns:: |p{0.8cm}|p{8.0cm}|p{8.5cm}| @@ -1774,7 +1774,7 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - \small -.. flat-table:: struct v4l2_ctrl_mpeg2_quantization +.. flat-table:: struct v4l2_ctrl_mpeg2_quantisation :header-rows: 0 :stub-columns: 0 :widths: 1 1 2 @@ -1798,24 +1798,24 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - YUV formats. * - __u8 - ``intra_quantiser_matrix[64]`` - - The quantization matrix coefficients for intra-coded frames, in zigzag + - The quantisation matrix coefficients for intra-coded frames, in zigzag scanning order. It is relevant for both luma and chroma components, although it can be superseded by the chroma-specific matrix for non-4:2:0 YUV formats. * - __u8 - ``non_intra_quantiser_matrix[64]`` - - The quantization matrix coefficients for non-intra-coded frames, in + - The quantisation matrix coefficients for non-intra-coded frames, in zigzag scanning order. It is relevant for both luma and chroma components, although it can be superseded by the chroma-specific matrix for non-4:2:0 YUV formats. * - __u8 - ``chroma_intra_quantiser_matrix[64]`` - - The quantization matrix coefficients for the chominance component of + - The quantisation matrix coefficients for the chominance component of intra-coded frames, in zigzag scanning order. Only relevant for non-4:2:0 YUV formats. * - __u8 - ``chroma_non_intra_quantiser_matrix[64]`` - - The quantization matrix coefficients for the chrominance component of + - The quantisation matrix coefficients for the chrominance component of non-intra-coded frames, in zigzag scanning order. Only relevant for non-4:2:0 YUV formats. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst index 6dba70da822b..cba607f789f0 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst @@ -115,8 +115,8 @@ Compressed Formats MPEG-2 pipeline (using the :ref:`mem2mem` and :ref:`media-request-api`). Metadata associated with the frame to decode is required to be passed through the ``V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS`` control and - quantization matrices can optionally be specified through the - ``V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION`` control. + quantisation matrices can optionally be specified through the + ``V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION`` control. See the :ref:`associated Codec Control IDs `. Exactly one output and one capture buffer must be provided for use with this pixel format. The output buffer must contain the appropriate number diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst index 8a285daedc6a..4362945fd39b 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst @@ -423,12 +423,12 @@ See also the examples in :ref:`control`. - n/a - A struct :c:type:`v4l2_ctrl_mpeg2_slice_params`, containing MPEG-2 slice parameters for stateless video decoders. - * - ``V4L2_CTRL_TYPE_MPEG2_QUANTIZATION`` + * - ``V4L2_CTRL_TYPE_MPEG2_QUANTISATION`` - n/a - n/a - n/a - - A struct :c:type:`v4l2_ctrl_mpeg2_quantization`, containing MPEG-2 - quantization matrices for stateless video decoders. + - A struct :c:type:`v4l2_ctrl_mpeg2_quantisation`, containing MPEG-2 + quantisation matrices for stateless video decoders. * - ``V4L2_CTRL_TYPE_AREA`` - n/a - n/a diff --git a/Documentation/userspace-api/media/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/videodev2.h.rst.exceptions index f59940352faa..5b2ebaa35d24 100644 --- a/Documentation/userspace-api/media/videodev2.h.rst.exceptions +++ b/Documentation/userspace-api/media/videodev2.h.rst.exceptions @@ -135,7 +135,7 @@ replace symbol V4L2_CTRL_TYPE_U16 :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_U32 :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_U8 :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS :c:type:`v4l2_ctrl_type` -replace symbol V4L2_CTRL_TYPE_MPEG2_QUANTIZATION :c:type:`v4l2_ctrl_type` +replace symbol V4L2_CTRL_TYPE_MPEG2_QUANTISATION :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_H264_SPS :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_H264_PPS :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_H264_SCALING_MATRIX :c:type:`v4l2_ctrl_type` diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 0d7fe1bd975a..1ed62f0ed66f 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -966,7 +966,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX: return "Frame LTR Index"; case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES: return "Use LTR Frames"; case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS: return "MPEG-2 Slice Parameters"; - case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION: return "MPEG-2 Quantization Matrices"; + case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION: return "MPEG-2 Quantisation Matrices"; case V4L2_CID_FWHT_I_FRAME_QP: return "FWHT I-Frame QP Value"; case V4L2_CID_FWHT_P_FRAME_QP: return "FWHT P-Frame QP Value"; @@ -1490,8 +1490,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS: *type = V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS; break; - case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION: - *type = V4L2_CTRL_TYPE_MPEG2_QUANTIZATION; + case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION: + *type = V4L2_CTRL_TYPE_MPEG2_QUANTISATION; break; case V4L2_CID_STATELESS_FWHT_PARAMS: *type = V4L2_CTRL_TYPE_FWHT_PARAMS; @@ -1942,7 +1942,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, break; - case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION: + case V4L2_CTRL_TYPE_MPEG2_QUANTISATION: break; case V4L2_CTRL_TYPE_FWHT_PARAMS: @@ -2911,8 +2911,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS: elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_params); break; - case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION: - elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization); + case V4L2_CTRL_TYPE_MPEG2_QUANTISATION: + elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantisation); break; case V4L2_CTRL_TYPE_FWHT_PARAMS: elem_size = sizeof(struct v4l2_ctrl_fwht_params); diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 074b9bb30d6d..b7b4328d3c6d 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -303,7 +303,7 @@ static const struct hantro_ctrl controls[] = { }, { .codec = HANTRO_MPEG2_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION, + .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION, }, }, { .codec = HANTRO_VP8_DECODER, diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c index 0fd306806f16..55d07aa7756b 100644 --- a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c @@ -82,17 +82,14 @@ #define PICT_FRAME 3 static void -hantro_g1_mpeg2_dec_set_quantization(struct hantro_dev *vpu, +hantro_g1_mpeg2_dec_set_quantisation(struct hantro_dev *vpu, struct hantro_ctx *ctx) { - struct v4l2_ctrl_mpeg2_quantization *quantization; - - quantization = hantro_get_ctrl(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION); - hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, - quantization); - vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, - G1_REG_QTABLE_BASE); + struct v4l2_ctrl_mpeg2_quantisation *q; + + q = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION); + hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, q); + vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, G1_REG_QTABLE_BASE); } static void @@ -238,7 +235,7 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) reg = G1_REG_APF_THRESHOLD(8); vdpu_write_relaxed(vpu, reg, G1_SWREG(55)); - hantro_g1_mpeg2_dec_set_quantization(vpu, ctx); + hantro_g1_mpeg2_dec_set_quantisation(vpu, ctx); hantro_g1_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf, &dst_buf->vb2_buf, diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 0a42df22472e..3d8b53567f16 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -223,7 +223,7 @@ hantro_h264_mv_size(unsigned int width, unsigned int height) void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx); void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx); void hantro_mpeg2_dec_copy_qtable(u8 *qtable, - const struct v4l2_ctrl_mpeg2_quantization *ctrl); + const struct v4l2_ctrl_mpeg2_quantisation *ctrl); int hantro_mpeg2_dec_init(struct hantro_ctx *ctx); void hantro_mpeg2_dec_exit(struct hantro_ctx *ctx); diff --git a/drivers/staging/media/hantro/hantro_mpeg2.c b/drivers/staging/media/hantro/hantro_mpeg2.c index 53a99a9988d5..04e545eb0a83 100644 --- a/drivers/staging/media/hantro/hantro_mpeg2.c +++ b/drivers/staging/media/hantro/hantro_mpeg2.c @@ -19,7 +19,7 @@ static const u8 zigzag[64] = { }; void hantro_mpeg2_dec_copy_qtable(u8 *qtable, - const struct v4l2_ctrl_mpeg2_quantization *ctrl) + const struct v4l2_ctrl_mpeg2_quantisation *ctrl) { int i, n; diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c index f610fa5b4335..61a54549774d 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c @@ -84,16 +84,14 @@ #define PICT_FRAME 3 static void -rk3399_vpu_mpeg2_dec_set_quantization(struct hantro_dev *vpu, +rk3399_vpu_mpeg2_dec_set_quantisation(struct hantro_dev *vpu, struct hantro_ctx *ctx) { - struct v4l2_ctrl_mpeg2_quantization *quantization; + struct v4l2_ctrl_mpeg2_quantisation *q; - quantization = hantro_get_ctrl(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION); - hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, quantization); - vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, - VDPU_REG_QTABLE_BASE); + q = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION); + hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, q); + vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, VDPU_REG_QTABLE_BASE); } static void @@ -243,7 +241,7 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) VDPU_REG_MV_ACCURACY_BWD(1); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(136)); - rk3399_vpu_mpeg2_dec_set_quantization(vpu, ctx); + rk3399_vpu_mpeg2_dec_set_quantisation(vpu, ctx); rk3399_vpu_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf, &dst_buf->vb2_buf, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 92812d1a39d4..62a5407664ae 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -37,7 +37,7 @@ static const struct cedrus_control cedrus_controls[] = { }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION, + .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION, }, .codec = CEDRUS_CODEC_MPEG2, }, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 15f147dad4cb..6516bff3d319 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -69,7 +69,7 @@ struct cedrus_h264_run { struct cedrus_mpeg2_run { const struct v4l2_ctrl_mpeg2_slice_params *slice_params; - const struct v4l2_ctrl_mpeg2_quantization *quantization; + const struct v4l2_ctrl_mpeg2_quantisation *quantisation; }; struct cedrus_h265_run { diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index d696b3ec70c0..238f779d2ba4 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -42,8 +42,8 @@ void cedrus_device_run(void *priv) case V4L2_PIX_FMT_MPEG2_SLICE: run.mpeg2.slice_params = cedrus_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); - run.mpeg2.quantization = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION); + run.mpeg2.quantisation = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION); break; case V4L2_PIX_FMT_H264_SLICE: diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c index 8bcd6b8f9e2d..459f71679a4f 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c @@ -13,9 +13,9 @@ #include "cedrus_hw.h" #include "cedrus_regs.h" -/* Default MPEG-2 quantization coefficients, from the specification. */ +/* Default MPEG-2 quantisation coefficients, from the specification. */ -static const u8 intra_quantization_matrix_default[64] = { +static const u8 intra_quantisation_matrix_default[64] = { 8, 16, 16, 19, 16, 19, 22, 22, 22, 22, 22, 22, 26, 24, 26, 27, 27, 27, 26, 26, 26, 26, 27, 27, @@ -26,7 +26,7 @@ static const u8 intra_quantization_matrix_default[64] = { 46, 46, 56, 56, 58, 69, 69, 83 }; -static const u8 non_intra_quantization_matrix_default[64] = { +static const u8 non_intra_quantisation_matrix_default[64] = { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, @@ -77,7 +77,7 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) const struct v4l2_ctrl_mpeg2_slice_params *slice_params; const struct v4l2_mpeg2_sequence *sequence; const struct v4l2_mpeg2_picture *picture; - const struct v4l2_ctrl_mpeg2_quantization *quantization; + const struct v4l2_ctrl_mpeg2_quantisation *quantisation; dma_addr_t src_buf_addr, dst_luma_addr, dst_chroma_addr; dma_addr_t fwd_luma_addr, fwd_chroma_addr; dma_addr_t bwd_luma_addr, bwd_chroma_addr; @@ -93,17 +93,17 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) sequence = &slice_params->sequence; picture = &slice_params->picture; - quantization = run->mpeg2.quantization; + quantisation = run->mpeg2.quantisation; /* Activate MPEG engine. */ cedrus_engine_enable(ctx, CEDRUS_CODEC_MPEG2); - /* Set intra quantization matrix. */ + /* Set intra quantisation matrix. */ - if (quantization && quantization->load_intra_quantiser_matrix) - matrix = quantization->intra_quantiser_matrix; + if (quantisation && quantisation->load_intra_quantiser_matrix) + matrix = quantisation->intra_quantiser_matrix; else - matrix = intra_quantization_matrix_default; + matrix = intra_quantisation_matrix_default; for (i = 0; i < 64; i++) { reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]); @@ -112,12 +112,12 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) cedrus_write(dev, VE_DEC_MPEG_IQMINPUT, reg); } - /* Set non-intra quantization matrix. */ + /* Set non-intra quantisation matrix. */ - if (quantization && quantization->load_non_intra_quantiser_matrix) - matrix = quantization->non_intra_quantiser_matrix; + if (quantisation && quantisation->load_non_intra_quantiser_matrix) + matrix = quantisation->non_intra_quantiser_matrix; else - matrix = non_intra_quantization_matrix_default; + matrix = non_intra_quantisation_matrix_default; for (i = 0; i < 64; i++) { reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]); diff --git a/include/media/mpeg2-ctrls.h b/include/media/mpeg2-ctrls.h index 2a4ae6701166..b8adf3ac2c1d 100644 --- a/include/media/mpeg2-ctrls.h +++ b/include/media/mpeg2-ctrls.h @@ -12,11 +12,11 @@ #define _MPEG2_CTRLS_H_ #define V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS (V4L2_CID_CODEC_BASE+250) -#define V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION (V4L2_CID_CODEC_BASE+251) +#define V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION (V4L2_CID_CODEC_BASE+251) /* enum v4l2_ctrl_type type values */ #define V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS 0x0103 -#define V4L2_CTRL_TYPE_MPEG2_QUANTIZATION 0x0104 +#define V4L2_CTRL_TYPE_MPEG2_QUANTISATION 0x0104 #define V4L2_MPEG2_PICTURE_CODING_TYPE_I 1 #define V4L2_MPEG2_PICTURE_CODING_TYPE_P 2 @@ -66,7 +66,7 @@ struct v4l2_ctrl_mpeg2_slice_params { __u32 quantiser_scale_code; }; -struct v4l2_ctrl_mpeg2_quantization { +struct v4l2_ctrl_mpeg2_quantisation { /* ISO/IEC 13818-2, ITU-T Rec. H.262: Quant matrix extension */ __u8 load_intra_quantiser_matrix; __u8 load_non_intra_quantiser_matrix; diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index a5953b812878..a38e6bd02a6a 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -41,7 +41,7 @@ struct video_device; * @p_u32: Pointer to a 32-bit unsigned value. * @p_char: Pointer to a string. * @p_mpeg2_slice_params: Pointer to a MPEG2 slice parameters structure. - * @p_mpeg2_quantization: Pointer to a MPEG2 quantization data structure. + * @p_mpeg2_quantisation: Pointer to a MPEG2 quantisation data structure. * @p_fwht_params: Pointer to a FWHT stateless parameters structure. * @p_h264_sps: Pointer to a struct v4l2_ctrl_h264_sps. * @p_h264_pps: Pointer to a struct v4l2_ctrl_h264_pps. @@ -67,7 +67,7 @@ union v4l2_ctrl_ptr { u32 *p_u32; char *p_char; struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; - struct v4l2_ctrl_mpeg2_quantization *p_mpeg2_quantization; + struct v4l2_ctrl_mpeg2_quantisation *p_mpeg2_quantisation; struct v4l2_ctrl_fwht_params *p_fwht_params; struct v4l2_ctrl_h264_sps *p_h264_sps; struct v4l2_ctrl_h264_pps *p_h264_pps; -- cgit v1.3.1 From 81bbb65f19819440b42270e1f033d9b14279540c Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 29 Apr 2021 16:48:10 +0200 Subject: media: uapi: mpeg2: rework quantisation matrices semantics As stated in the MPEG-2 specification, section 6.3.7 "Quant matrix extension": Each quantisation matrix has a default set of values. When a sequence_header_code is decoded all matrices shall be reset to their default values. User defined matrices may be downloaded and this can occur in a sequence_header() or in a quant_matrix_extension(). The load_intra_quantiser_matrix syntax elements are transmitted in the bitstream headers, signalling that a quantisation matrix needs to be loaded and used for pictures transmitted afterwards (until the matrices are reset). This "load" semantics are implemented in the V4L2 interface without the need of any "load" flags: passing the control is effectively a load. Therefore, rework the V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION semantics to match the MPEG-2 semantics. Quantisation matrices values are now initialized by the V4L2 control core to their reset default value, and applications are expected to reset their values as specified. The quantisation control is therefore optional, and used to load bitstream-defined values in the quantisation matrices. Signed-off-by: Ezequiel Garcia Co-developed-by: Nicolas Dufresne Signed-off-by: Nicolas Dufresne Tested-by: Jernej Skrabec Reviewed-by: Jernej Skrabec Tested-by: Daniel Almeida Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/ext-ctrls-codec.rst | 17 ---------- drivers/media/v4l2-core/v4l2-ctrls.c | 26 +++++++++++++++ drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c | 38 ++-------------------- include/media/mpeg2-ctrls.h | 5 --- 4 files changed, 28 insertions(+), 58 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index 2835ce739478..bfbc5fda9f9b 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -1779,23 +1779,6 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - :stub-columns: 0 :widths: 1 1 2 - * - __u8 - - ``load_intra_quantiser_matrix`` - - One bit to indicate whether to load the ``intra_quantiser_matrix`` data. - * - __u8 - - ``load_non_intra_quantiser_matrix`` - - One bit to indicate whether to load the ``non_intra_quantiser_matrix`` - data. - * - __u8 - - ``load_chroma_intra_quantiser_matrix`` - - One bit to indicate whether to load the - ``chroma_intra_quantiser_matrix`` data, only relevant for non-4:2:0 YUV - formats. - * - __u8 - - ``load_chroma_non_intra_quantiser_matrix`` - - One bit to indicate whether to load the - ``chroma_non_intra_quantiser_matrix`` data, only relevant for non-4:2:0 - YUV formats. * - __u8 - ``intra_quantiser_matrix[64]`` - The quantisation matrix coefficients for intra-coded frames, in zigzag diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 1ed62f0ed66f..41955ea9230d 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -57,6 +57,18 @@ static bool is_new_manual(const struct v4l2_ctrl *master) return master->is_auto && master->val == master->manual_mode_value; } +/* Default intra MPEG-2 quantisation coefficients, from the specification. */ +static const u8 mpeg2_intra_quant_matrix[64] = { + 8, 16, 16, 19, 16, 19, 22, 22, + 22, 22, 22, 22, 26, 24, 26, 27, + 27, 27, 26, 26, 26, 26, 27, 27, + 27, 29, 29, 29, 34, 34, 34, 29, + 29, 29, 27, 27, 29, 29, 32, 32, + 34, 34, 37, 38, 37, 35, 35, 34, + 35, 38, 38, 40, 40, 40, 48, 48, + 46, 46, 56, 56, 58, 69, 69, 83 +}; + /* Returns NULL or a character pointer array containing the menu for the given control ID. The pointer array ends with a NULL pointer. An empty string signifies a menu entry that is invalid. This allows @@ -1692,6 +1704,7 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, union v4l2_ctrl_ptr ptr) { struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; + struct v4l2_ctrl_mpeg2_quantisation *p_mpeg2_quant; struct v4l2_ctrl_vp8_frame *p_vp8_frame; struct v4l2_ctrl_fwht_params *p_fwht_params; void *p = ptr.p + idx * ctrl->elem_size; @@ -1716,6 +1729,19 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, p_mpeg2_slice_params->picture.picture_coding_type = V4L2_MPEG2_PICTURE_CODING_TYPE_I; break; + case V4L2_CTRL_TYPE_MPEG2_QUANTISATION: + p_mpeg2_quant = p; + + memcpy(p_mpeg2_quant->intra_quantiser_matrix, + mpeg2_intra_quant_matrix, + ARRAY_SIZE(mpeg2_intra_quant_matrix)); + /* + * The default non-intra MPEG-2 quantisation + * coefficients are all 16, as per the specification. + */ + memset(p_mpeg2_quant->non_intra_quantiser_matrix, 16, + sizeof(p_mpeg2_quant->non_intra_quantiser_matrix)); + break; case V4L2_CTRL_TYPE_VP8_FRAME: p_vp8_frame = p; p_vp8_frame->num_dct_parts = 1; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c index 459f71679a4f..e3154f631858 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c @@ -13,30 +13,6 @@ #include "cedrus_hw.h" #include "cedrus_regs.h" -/* Default MPEG-2 quantisation coefficients, from the specification. */ - -static const u8 intra_quantisation_matrix_default[64] = { - 8, 16, 16, 19, 16, 19, 22, 22, - 22, 22, 22, 22, 26, 24, 26, 27, - 27, 27, 26, 26, 26, 26, 27, 27, - 27, 29, 29, 29, 34, 34, 34, 29, - 29, 29, 27, 27, 29, 29, 32, 32, - 34, 34, 37, 38, 37, 35, 35, 34, - 35, 38, 38, 40, 40, 40, 48, 48, - 46, 46, 56, 56, 58, 69, 69, 83 -}; - -static const u8 non_intra_quantisation_matrix_default[64] = { - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16 -}; - static enum cedrus_irq_status cedrus_mpeg2_irq_status(struct cedrus_ctx *ctx) { struct cedrus_dev *dev = ctx->dev; @@ -99,12 +75,7 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) cedrus_engine_enable(ctx, CEDRUS_CODEC_MPEG2); /* Set intra quantisation matrix. */ - - if (quantisation && quantisation->load_intra_quantiser_matrix) - matrix = quantisation->intra_quantiser_matrix; - else - matrix = intra_quantisation_matrix_default; - + matrix = quantisation->intra_quantiser_matrix; for (i = 0; i < 64; i++) { reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]); reg |= VE_DEC_MPEG_IQMINPUT_FLAG_INTRA; @@ -113,12 +84,7 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) } /* Set non-intra quantisation matrix. */ - - if (quantisation && quantisation->load_non_intra_quantiser_matrix) - matrix = quantisation->non_intra_quantiser_matrix; - else - matrix = non_intra_quantisation_matrix_default; - + matrix = quantisation->non_intra_quantiser_matrix; for (i = 0; i < 64; i++) { reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]); reg |= VE_DEC_MPEG_IQMINPUT_FLAG_NON_INTRA; diff --git a/include/media/mpeg2-ctrls.h b/include/media/mpeg2-ctrls.h index b8adf3ac2c1d..8ea2c7f3a172 100644 --- a/include/media/mpeg2-ctrls.h +++ b/include/media/mpeg2-ctrls.h @@ -68,11 +68,6 @@ struct v4l2_ctrl_mpeg2_slice_params { struct v4l2_ctrl_mpeg2_quantisation { /* ISO/IEC 13818-2, ITU-T Rec. H.262: Quant matrix extension */ - __u8 load_intra_quantiser_matrix; - __u8 load_non_intra_quantiser_matrix; - __u8 load_chroma_intra_quantiser_matrix; - __u8 load_chroma_non_intra_quantiser_matrix; - __u8 intra_quantiser_matrix[64]; __u8 non_intra_quantiser_matrix[64]; __u8 chroma_intra_quantiser_matrix[64]; -- cgit v1.3.1 From 88e78409a83a579fde7f150be7ebeefab0e1f774 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 29 Apr 2021 16:48:11 +0200 Subject: media: uapi: mpeg2: Cleanup flags Our current MPEG-2 uAPI uses 1-byte fields for MPEG-2 boolean syntax elements. Clean these by adding a 'flags' field and flag macro for each boolean syntax element. A follow-up change will refactor this uAPI so we don't need to add padding fields just yet. Signed-off-by: Ezequiel Garcia Tested-by: Jonas Karlman Tested-by: Jernej Skrabec Reviewed-by: Jernej Skrabec Tested-by: Daniel Almeida Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/ext-ctrls-codec.rst | 77 +++++++++++++++------- drivers/media/v4l2-core/v4l2-ctrls.c | 14 ++-- drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c | 76 ++++++++++----------- .../staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c | 76 ++++++++++----------- drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c | 38 +++++------ include/media/mpeg2-ctrls.h | 36 ++++++---- 6 files changed, 175 insertions(+), 142 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index bfbc5fda9f9b..aa11346e7e27 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -1687,13 +1687,28 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - - ``profile_and_level_indication`` - The current profile and level indication as extracted from the bitstream. - * - __u8 - - ``progressive_sequence`` - - Indication that all the frames for the sequence are progressive instead - of interlaced. * - __u8 - ``chroma_format`` - The chrominance sub-sampling format (1: 4:2:0, 2: 4:2:2, 3: 4:4:4). + * - __u32 + - ``flags`` + - See :ref:`MPEG-2 Sequence Flags `. + +.. _mpeg2_sequence_flags: + +``MPEG-2 Sequence Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE`` + - 0x00000001 + - Indication that all the frames for the sequence are progressive instead + of interlaced. .. c:type:: v4l2_mpeg2_picture @@ -1726,29 +1741,45 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - - ``picture_structure`` - Picture structure (1: interlaced top field, 2: interlaced bottom field, 3: progressive frame). - * - __u8 - - ``top_field_first`` - - If set to 1 and interlaced stream, top field is output first. - * - __u8 - - ``frame_pred_frame_dct`` - - If set to 1, only frame-DCT and frame prediction are used. - * - __u8 - - ``concealment_motion_vectors`` - - If set to 1, motion vectors are coded for intra macroblocks. - * - __u8 - - ``q_scale_type`` + * - __u32 + - ``flags`` + - See :ref:`MPEG-2 Picture Flags `. + + +.. _mpeg2_picture_flags: + +``MPEG-2 Picture Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST`` + - 0x00000001 + - If set and it's an interlaced stream, top field is output first. + * - ``V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT`` + - 0x00000002 + - If set only frame-DCT and frame prediction are used. + * - ``V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV`` + - 0x00000004 + - If set motion vectors are coded for intra macroblocks. + * - ``V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE`` + - 0x00000008 - This flag affects the inverse quantization process. - * - __u8 - - ``intra_vlc_format`` + * - ``V4L2_MPEG2_PIC_FLAG_INTRA_VLC`` + - 0x00000010 - This flag affects the decoding of transform coefficient data. - * - __u8 - - ``alternate_scan`` + * - ``V4L2_MPEG2_PIC_FLAG_ALT_SCAN`` + - 0x00000020 - This flag affects the decoding of transform coefficient data. - * - __u8 - - ``repeat_first_field`` + * - ``V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST`` + - 0x00000040 - This flag affects the decoding process of progressive frames. - * - __u16 - - ``progressive_frame`` + * - ``V4L2_MPEG2_PIC_FLAG_PROGRESSIVE`` + - 0x00000080 - Indicates whether the current frame is progressive. .. raw:: latex diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 41955ea9230d..37531302dd3a 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1727,7 +1727,7 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, /* interlaced top field */ p_mpeg2_slice_params->picture.picture_structure = 1; p_mpeg2_slice_params->picture.picture_coding_type = - V4L2_MPEG2_PICTURE_CODING_TYPE_I; + V4L2_MPEG2_PIC_CODING_TYPE_I; break; case V4L2_CTRL_TYPE_MPEG2_QUANTISATION: p_mpeg2_quant = p; @@ -1949,18 +1949,18 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, } switch (p_mpeg2_slice_params->picture.picture_structure) { - case 1: /* interlaced top field */ - case 2: /* interlaced bottom field */ - case 3: /* progressive */ + case V4L2_MPEG2_PIC_TOP_FIELD: + case V4L2_MPEG2_PIC_BOTTOM_FIELD: + case V4L2_MPEG2_PIC_FRAME: break; default: return -EINVAL; } switch (p_mpeg2_slice_params->picture.picture_coding_type) { - case V4L2_MPEG2_PICTURE_CODING_TYPE_I: - case V4L2_MPEG2_PICTURE_CODING_TYPE_P: - case V4L2_MPEG2_PICTURE_CODING_TYPE_B: + case V4L2_MPEG2_PIC_CODING_TYPE_I: + case V4L2_MPEG2_PIC_CODING_TYPE_P: + case V4L2_MPEG2_PIC_CODING_TYPE_B: break; default: return -EINVAL; diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c index 55d07aa7756b..925341891b7f 100644 --- a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c @@ -77,10 +77,6 @@ #define G1_REG_APF_THRESHOLD(v) (((v) << 0) & GENMASK(13, 0)) -#define PICT_TOP_FIELD 1 -#define PICT_BOTTOM_FIELD 2 -#define PICT_FRAME 3 - static void hantro_g1_mpeg2_dec_set_quantisation(struct hantro_dev *vpu, struct hantro_ctx *ctx) @@ -96,19 +92,19 @@ static void hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf, - const struct v4l2_mpeg2_sequence *sequence, - const struct v4l2_mpeg2_picture *picture, + const struct v4l2_mpeg2_sequence *seq, + const struct v4l2_mpeg2_picture *pic, const struct v4l2_ctrl_mpeg2_slice_params *slice_params) { dma_addr_t forward_addr = 0, backward_addr = 0; dma_addr_t current_addr, addr; - switch (picture->picture_coding_type) { - case V4L2_MPEG2_PICTURE_CODING_TYPE_B: + switch (pic->picture_coding_type) { + case V4L2_MPEG2_PIC_CODING_TYPE_B: backward_addr = hantro_get_ref(ctx, slice_params->backward_ref_ts); fallthrough; - case V4L2_MPEG2_PICTURE_CODING_TYPE_P: + case V4L2_MPEG2_PIC_CODING_TYPE_P: forward_addr = hantro_get_ref(ctx, slice_params->forward_ref_ts); } @@ -121,7 +117,7 @@ hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, addr = hantro_get_dec_buf_addr(ctx, dst_buf); current_addr = addr; - if (picture->picture_structure == PICT_BOTTOM_FIELD) + if (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD) addr += ALIGN(ctx->dst_fmt.width, 16); vdpu_write_relaxed(vpu, addr, G1_REG_DEC_OUT_BASE); @@ -131,18 +127,18 @@ hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, backward_addr = current_addr; /* Set forward ref frame (top/bottom field) */ - if (picture->picture_structure == PICT_FRAME || - picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B || - (picture->picture_structure == PICT_TOP_FIELD && - picture->top_field_first) || - (picture->picture_structure == PICT_BOTTOM_FIELD && - !picture->top_field_first)) { + if (pic->picture_structure == V4L2_MPEG2_PIC_FRAME || + pic->picture_coding_type == V4L2_MPEG2_PIC_CODING_TYPE_B || + (pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD && + pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST) || + (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD && + !(pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST))) { vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER0_BASE); vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER1_BASE); - } else if (picture->picture_structure == PICT_TOP_FIELD) { + } else if (pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD) { vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER0_BASE); vdpu_write_relaxed(vpu, current_addr, G1_REG_REFER1_BASE); - } else if (picture->picture_structure == PICT_BOTTOM_FIELD) { + } else if (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD) { vdpu_write_relaxed(vpu, current_addr, G1_REG_REFER0_BASE); vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER1_BASE); } @@ -157,8 +153,8 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; const struct v4l2_ctrl_mpeg2_slice_params *slice_params; - const struct v4l2_mpeg2_sequence *sequence; - const struct v4l2_mpeg2_picture *picture; + const struct v4l2_mpeg2_sequence *seq; + const struct v4l2_mpeg2_picture *pic; u32 reg; src_buf = hantro_get_src_buf(ctx); @@ -169,8 +165,8 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) slice_params = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); - sequence = &slice_params->sequence; - picture = &slice_params->picture; + seq = &slice_params->sequence; + pic = &slice_params->picture; reg = G1_REG_DEC_AXI_RD_ID(0) | G1_REG_DEC_TIMEOUT_E(1) | @@ -190,11 +186,11 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) reg = G1_REG_DEC_MODE(5) | G1_REG_RLC_MODE_E(0) | - G1_REG_PIC_INTERLACE_E(!sequence->progressive_sequence) | - G1_REG_PIC_FIELDMODE_E(picture->picture_structure != PICT_FRAME) | - G1_REG_PIC_B_E(picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B) | - G1_REG_PIC_INTER_E(picture->picture_coding_type != V4L2_MPEG2_PICTURE_CODING_TYPE_I) | - G1_REG_PIC_TOPFIELD_E(picture->picture_structure == PICT_TOP_FIELD) | + G1_REG_PIC_INTERLACE_E(!(seq->flags & V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE)) | + G1_REG_PIC_FIELDMODE_E(pic->picture_structure != V4L2_MPEG2_PIC_FRAME) | + G1_REG_PIC_B_E(pic->picture_coding_type == V4L2_MPEG2_PIC_CODING_TYPE_B) | + G1_REG_PIC_INTER_E(pic->picture_coding_type != V4L2_MPEG2_PIC_CODING_TYPE_I) | + G1_REG_PIC_TOPFIELD_E(pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD) | G1_REG_FWD_INTERLACE_E(0) | G1_REG_FILTERING_DIS(1) | G1_REG_WRITE_MVS_E(0) | @@ -203,27 +199,27 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) reg = G1_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->dst_fmt.width)) | G1_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->dst_fmt.height)) | - G1_REG_ALT_SCAN_E(picture->alternate_scan) | - G1_REG_TOPFIELDFIRST_E(picture->top_field_first); + G1_REG_ALT_SCAN_E(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN) | + G1_REG_TOPFIELDFIRST_E(pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST); vdpu_write_relaxed(vpu, reg, G1_SWREG(4)); reg = G1_REG_STRM_START_BIT(slice_params->data_bit_offset) | - G1_REG_QSCALE_TYPE(picture->q_scale_type) | - G1_REG_CON_MV_E(picture->concealment_motion_vectors) | - G1_REG_INTRA_DC_PREC(picture->intra_dc_precision) | - G1_REG_INTRA_VLC_TAB(picture->intra_vlc_format) | - G1_REG_FRAME_PRED_DCT(picture->frame_pred_frame_dct); + G1_REG_QSCALE_TYPE(pic->flags & V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE) | + G1_REG_CON_MV_E(pic->flags & V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV) | + G1_REG_INTRA_DC_PREC(pic->intra_dc_precision) | + G1_REG_INTRA_VLC_TAB(pic->flags & V4L2_MPEG2_PIC_FLAG_INTRA_VLC) | + G1_REG_FRAME_PRED_DCT(pic->flags & V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT); vdpu_write_relaxed(vpu, reg, G1_SWREG(5)); reg = G1_REG_INIT_QP(1) | G1_REG_STREAM_LEN(slice_params->bit_size >> 3); vdpu_write_relaxed(vpu, reg, G1_SWREG(6)); - reg = G1_REG_ALT_SCAN_FLAG_E(picture->alternate_scan) | - G1_REG_FCODE_FWD_HOR(picture->f_code[0][0]) | - G1_REG_FCODE_FWD_VER(picture->f_code[0][1]) | - G1_REG_FCODE_BWD_HOR(picture->f_code[1][0]) | - G1_REG_FCODE_BWD_VER(picture->f_code[1][1]) | + reg = G1_REG_ALT_SCAN_FLAG_E(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN) | + G1_REG_FCODE_FWD_HOR(pic->f_code[0][0]) | + G1_REG_FCODE_FWD_VER(pic->f_code[0][1]) | + G1_REG_FCODE_BWD_HOR(pic->f_code[1][0]) | + G1_REG_FCODE_BWD_VER(pic->f_code[1][1]) | G1_REG_MV_ACCURACY_FWD(1) | G1_REG_MV_ACCURACY_BWD(1); vdpu_write_relaxed(vpu, reg, G1_SWREG(18)); @@ -239,7 +235,7 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) hantro_g1_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf, &dst_buf->vb2_buf, - sequence, picture, slice_params); + seq, pic, slice_params); hantro_end_prepare_run(ctx); diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c index 61a54549774d..ff54398f6643 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c @@ -79,10 +79,6 @@ #define VDPU_REG_MV_ACCURACY_FWD(v) ((v) ? BIT(2) : 0) #define VDPU_REG_MV_ACCURACY_BWD(v) ((v) ? BIT(1) : 0) -#define PICT_TOP_FIELD 1 -#define PICT_BOTTOM_FIELD 2 -#define PICT_FRAME 3 - static void rk3399_vpu_mpeg2_dec_set_quantisation(struct hantro_dev *vpu, struct hantro_ctx *ctx) @@ -99,19 +95,19 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf, - const struct v4l2_mpeg2_sequence *sequence, - const struct v4l2_mpeg2_picture *picture, + const struct v4l2_mpeg2_sequence *seq, + const struct v4l2_mpeg2_picture *pic, const struct v4l2_ctrl_mpeg2_slice_params *slice_params) { dma_addr_t forward_addr = 0, backward_addr = 0; dma_addr_t current_addr, addr; - switch (picture->picture_coding_type) { - case V4L2_MPEG2_PICTURE_CODING_TYPE_B: + switch (pic->picture_coding_type) { + case V4L2_MPEG2_PIC_CODING_TYPE_B: backward_addr = hantro_get_ref(ctx, slice_params->backward_ref_ts); fallthrough; - case V4L2_MPEG2_PICTURE_CODING_TYPE_P: + case V4L2_MPEG2_PIC_CODING_TYPE_P: forward_addr = hantro_get_ref(ctx, slice_params->forward_ref_ts); } @@ -124,7 +120,7 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu, addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); current_addr = addr; - if (picture->picture_structure == PICT_BOTTOM_FIELD) + if (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD) addr += ALIGN(ctx->dst_fmt.width, 16); vdpu_write_relaxed(vpu, addr, VDPU_REG_DEC_OUT_BASE); @@ -134,18 +130,18 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu, backward_addr = current_addr; /* Set forward ref frame (top/bottom field) */ - if (picture->picture_structure == PICT_FRAME || - picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B || - (picture->picture_structure == PICT_TOP_FIELD && - picture->top_field_first) || - (picture->picture_structure == PICT_BOTTOM_FIELD && - !picture->top_field_first)) { + if (pic->picture_structure == V4L2_MPEG2_PIC_FRAME || + pic->picture_coding_type == V4L2_MPEG2_PIC_CODING_TYPE_B || + (pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD && + pic->flags & V4L2_MPEG2_PIC_TOP_FIELD) || + (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD && + !(pic->flags & V4L2_MPEG2_PIC_TOP_FIELD))) { vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER0_BASE); vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE); - } else if (picture->picture_structure == PICT_TOP_FIELD) { + } else if (pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD) { vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER0_BASE); vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER1_BASE); - } else if (picture->picture_structure == PICT_BOTTOM_FIELD) { + } else if (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD) { vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER0_BASE); vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE); } @@ -160,8 +156,8 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; const struct v4l2_ctrl_mpeg2_slice_params *slice_params; - const struct v4l2_mpeg2_sequence *sequence; - const struct v4l2_mpeg2_picture *picture; + const struct v4l2_mpeg2_sequence *seq; + const struct v4l2_mpeg2_picture *pic; u32 reg; src_buf = hantro_get_src_buf(ctx); @@ -171,8 +167,8 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) slice_params = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); - sequence = &slice_params->sequence; - picture = &slice_params->picture; + seq = &slice_params->sequence; + pic = &slice_params->picture; reg = VDPU_REG_DEC_ADV_PRE_DIS(0) | VDPU_REG_DEC_SCMD_DIS(0) | @@ -207,11 +203,11 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) vdpu_write_relaxed(vpu, reg, VDPU_SWREG(56)); reg = VDPU_REG_RLC_MODE_E(0) | - VDPU_REG_PIC_INTERLACE_E(!sequence->progressive_sequence) | - VDPU_REG_PIC_FIELDMODE_E(picture->picture_structure != PICT_FRAME) | - VDPU_REG_PIC_B_E(picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B) | - VDPU_REG_PIC_INTER_E(picture->picture_coding_type != V4L2_MPEG2_PICTURE_CODING_TYPE_I) | - VDPU_REG_PIC_TOPFIELD_E(picture->picture_structure == PICT_TOP_FIELD) | + VDPU_REG_PIC_INTERLACE_E(!(seq->flags & V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE)) | + VDPU_REG_PIC_FIELDMODE_E(pic->picture_structure != V4L2_MPEG2_PIC_FRAME) | + VDPU_REG_PIC_B_E(pic->picture_coding_type == V4L2_MPEG2_PIC_CODING_TYPE_B) | + VDPU_REG_PIC_INTER_E(pic->picture_coding_type != V4L2_MPEG2_PIC_CODING_TYPE_I) | + VDPU_REG_PIC_TOPFIELD_E(pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD) | VDPU_REG_FWD_INTERLACE_E(0) | VDPU_REG_WRITE_MVS_E(0) | VDPU_REG_DEC_TIMEOUT_E(1) | @@ -220,23 +216,23 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) reg = VDPU_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->dst_fmt.width)) | VDPU_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->dst_fmt.height)) | - VDPU_REG_ALT_SCAN_E(picture->alternate_scan) | - VDPU_REG_TOPFIELDFIRST_E(picture->top_field_first); + VDPU_REG_ALT_SCAN_E(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN) | + VDPU_REG_TOPFIELDFIRST_E(pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(120)); reg = VDPU_REG_STRM_START_BIT(slice_params->data_bit_offset) | - VDPU_REG_QSCALE_TYPE(picture->q_scale_type) | - VDPU_REG_CON_MV_E(picture->concealment_motion_vectors) | - VDPU_REG_INTRA_DC_PREC(picture->intra_dc_precision) | - VDPU_REG_INTRA_VLC_TAB(picture->intra_vlc_format) | - VDPU_REG_FRAME_PRED_DCT(picture->frame_pred_frame_dct); + VDPU_REG_QSCALE_TYPE(pic->flags & V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE) | + VDPU_REG_CON_MV_E(pic->flags & V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV) | + VDPU_REG_INTRA_DC_PREC(pic->intra_dc_precision) | + VDPU_REG_INTRA_VLC_TAB(pic->flags & V4L2_MPEG2_PIC_FLAG_INTRA_VLC) | + VDPU_REG_FRAME_PRED_DCT(pic->flags & V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(122)); - reg = VDPU_REG_ALT_SCAN_FLAG_E(picture->alternate_scan) | - VDPU_REG_FCODE_FWD_HOR(picture->f_code[0][0]) | - VDPU_REG_FCODE_FWD_VER(picture->f_code[0][1]) | - VDPU_REG_FCODE_BWD_HOR(picture->f_code[1][0]) | - VDPU_REG_FCODE_BWD_VER(picture->f_code[1][1]) | + reg = VDPU_REG_ALT_SCAN_FLAG_E(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN) | + VDPU_REG_FCODE_FWD_HOR(pic->f_code[0][0]) | + VDPU_REG_FCODE_FWD_VER(pic->f_code[0][1]) | + VDPU_REG_FCODE_BWD_HOR(pic->f_code[1][0]) | + VDPU_REG_FCODE_BWD_VER(pic->f_code[1][1]) | VDPU_REG_MV_ACCURACY_FWD(1) | VDPU_REG_MV_ACCURACY_BWD(1); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(136)); @@ -245,7 +241,7 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) rk3399_vpu_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf, &dst_buf->vb2_buf, - sequence, picture, slice_params); + seq, pic, slice_params); /* Kick the watchdog and start decoding */ hantro_end_prepare_run(ctx); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c index e3154f631858..e39a17d28c7d 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c @@ -51,8 +51,8 @@ static void cedrus_mpeg2_irq_disable(struct cedrus_ctx *ctx) static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) { const struct v4l2_ctrl_mpeg2_slice_params *slice_params; - const struct v4l2_mpeg2_sequence *sequence; - const struct v4l2_mpeg2_picture *picture; + const struct v4l2_mpeg2_sequence *seq; + const struct v4l2_mpeg2_picture *pic; const struct v4l2_ctrl_mpeg2_quantisation *quantisation; dma_addr_t src_buf_addr, dst_luma_addr, dst_chroma_addr; dma_addr_t fwd_luma_addr, fwd_chroma_addr; @@ -66,8 +66,8 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) u32 reg; slice_params = run->mpeg2.slice_params; - sequence = &slice_params->sequence; - picture = &slice_params->picture; + seq = &slice_params->sequence; + pic = &slice_params->picture; quantisation = run->mpeg2.quantisation; @@ -94,19 +94,19 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) /* Set MPEG picture header. */ - reg = VE_DEC_MPEG_MP12HDR_SLICE_TYPE(picture->picture_coding_type); - reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 0, picture->f_code[0][0]); - reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 1, picture->f_code[0][1]); - reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 0, picture->f_code[1][0]); - reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 1, picture->f_code[1][1]); - reg |= VE_DEC_MPEG_MP12HDR_INTRA_DC_PRECISION(picture->intra_dc_precision); - reg |= VE_DEC_MPEG_MP12HDR_INTRA_PICTURE_STRUCTURE(picture->picture_structure); - reg |= VE_DEC_MPEG_MP12HDR_TOP_FIELD_FIRST(picture->top_field_first); - reg |= VE_DEC_MPEG_MP12HDR_FRAME_PRED_FRAME_DCT(picture->frame_pred_frame_dct); - reg |= VE_DEC_MPEG_MP12HDR_CONCEALMENT_MOTION_VECTORS(picture->concealment_motion_vectors); - reg |= VE_DEC_MPEG_MP12HDR_Q_SCALE_TYPE(picture->q_scale_type); - reg |= VE_DEC_MPEG_MP12HDR_INTRA_VLC_FORMAT(picture->intra_vlc_format); - reg |= VE_DEC_MPEG_MP12HDR_ALTERNATE_SCAN(picture->alternate_scan); + reg = VE_DEC_MPEG_MP12HDR_SLICE_TYPE(pic->picture_coding_type); + reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 0, pic->f_code[0][0]); + reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 1, pic->f_code[0][1]); + reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 0, pic->f_code[1][0]); + reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 1, pic->f_code[1][1]); + reg |= VE_DEC_MPEG_MP12HDR_INTRA_DC_PRECISION(pic->intra_dc_precision); + reg |= VE_DEC_MPEG_MP12HDR_INTRA_PICTURE_STRUCTURE(pic->picture_structure); + reg |= VE_DEC_MPEG_MP12HDR_TOP_FIELD_FIRST(pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST); + reg |= VE_DEC_MPEG_MP12HDR_FRAME_PRED_FRAME_DCT(pic->flags & V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT); + reg |= VE_DEC_MPEG_MP12HDR_CONCEALMENT_MOTION_VECTORS(pic->flags & V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV); + reg |= VE_DEC_MPEG_MP12HDR_Q_SCALE_TYPE(pic->flags & V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE); + reg |= VE_DEC_MPEG_MP12HDR_INTRA_VLC_FORMAT(pic->flags & V4L2_MPEG2_PIC_FLAG_INTRA_VLC); + reg |= VE_DEC_MPEG_MP12HDR_ALTERNATE_SCAN(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN); reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_FORWARD_VECTOR(0); reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_BACKWARD_VECTOR(0); @@ -114,8 +114,8 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) /* Set frame dimensions. */ - reg = VE_DEC_MPEG_PICCODEDSIZE_WIDTH(sequence->horizontal_size); - reg |= VE_DEC_MPEG_PICCODEDSIZE_HEIGHT(sequence->vertical_size); + reg = VE_DEC_MPEG_PICCODEDSIZE_WIDTH(seq->horizontal_size); + reg |= VE_DEC_MPEG_PICCODEDSIZE_HEIGHT(seq->vertical_size); cedrus_write(dev, VE_DEC_MPEG_PICCODEDSIZE, reg); diff --git a/include/media/mpeg2-ctrls.h b/include/media/mpeg2-ctrls.h index 8ea2c7f3a172..d3190979d574 100644 --- a/include/media/mpeg2-ctrls.h +++ b/include/media/mpeg2-ctrls.h @@ -18,10 +18,7 @@ #define V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS 0x0103 #define V4L2_CTRL_TYPE_MPEG2_QUANTISATION 0x0104 -#define V4L2_MPEG2_PICTURE_CODING_TYPE_I 1 -#define V4L2_MPEG2_PICTURE_CODING_TYPE_P 2 -#define V4L2_MPEG2_PICTURE_CODING_TYPE_B 3 -#define V4L2_MPEG2_PICTURE_CODING_TYPE_D 4 +#define V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE 0x0001 struct v4l2_mpeg2_sequence { /* ISO/IEC 13818-2, ITU-T Rec. H.262: Sequence header */ @@ -31,10 +28,29 @@ struct v4l2_mpeg2_sequence { /* ISO/IEC 13818-2, ITU-T Rec. H.262: Sequence extension */ __u16 profile_and_level_indication; - __u8 progressive_sequence; __u8 chroma_format; + + __u32 flags; }; +#define V4L2_MPEG2_PIC_CODING_TYPE_I 1 +#define V4L2_MPEG2_PIC_CODING_TYPE_P 2 +#define V4L2_MPEG2_PIC_CODING_TYPE_B 3 +#define V4L2_MPEG2_PIC_CODING_TYPE_D 4 + +#define V4L2_MPEG2_PIC_TOP_FIELD 0x1 +#define V4L2_MPEG2_PIC_BOTTOM_FIELD 0x2 +#define V4L2_MPEG2_PIC_FRAME 0x3 + +#define V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST 0x0001 +#define V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT 0x0002 +#define V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV 0x0004 +#define V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE 0x0008 +#define V4L2_MPEG2_PIC_FLAG_INTRA_VLC 0x0010 +#define V4L2_MPEG2_PIC_FLAG_ALT_SCAN 0x0020 +#define V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST 0x0040 +#define V4L2_MPEG2_PIC_FLAG_PROGRESSIVE 0x0080 + struct v4l2_mpeg2_picture { /* ISO/IEC 13818-2, ITU-T Rec. H.262: Picture header */ __u8 picture_coding_type; @@ -43,14 +59,8 @@ struct v4l2_mpeg2_picture { __u8 f_code[2][2]; __u8 intra_dc_precision; __u8 picture_structure; - __u8 top_field_first; - __u8 frame_pred_frame_dct; - __u8 concealment_motion_vectors; - __u8 q_scale_type; - __u8 intra_vlc_format; - __u8 alternate_scan; - __u8 repeat_first_field; - __u16 progressive_frame; + + __u32 flags; }; struct v4l2_ctrl_mpeg2_slice_params { -- cgit v1.3.1 From f329e21e9dadc5c8ee37c781b30fe63bf7217201 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 29 Apr 2021 16:48:12 +0200 Subject: media: uapi: mpeg2: Split sequence and picture parameters Typically, bitstreams are composed of a sequence header, followed by a number of picture header and picture coding extension headers. Each picture can be composed of a number of slices. Let's split the MPEG-2 uAPI to follow these semantics more closely, allowing more usage flexibility. Having these controls split up allows applications to set a sequence control at the beginning of a sequence, and then set a picture control for each frame. While here add padding fields where needed, and document the uAPI header thoroughly. Note that the V4L2_CTRL_TYPE_{} defines had to be moved because it clashes with existing ones. This is not really an issue since they will be re-defined when the controls are moved out of staging. Signed-off-by: Ezequiel Garcia Tested-by: Jonas Karlman Tested-by: Jernej Skrabec Reviewed-by: Jernej Skrabec Tested-by: Daniel Almeida Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/ext-ctrls-codec.rst | 64 ++++++++----- .../userspace-api/media/v4l/pixfmt-compressed.rst | 5 +- .../userspace-api/media/v4l/vidioc-queryctrl.rst | 12 +++ .../userspace-api/media/videodev2.h.rst.exceptions | 2 + drivers/media/v4l2-core/v4l2-ctrls.c | 56 ++++++++--- drivers/staging/media/hantro/hantro_drv.c | 10 ++ drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c | 14 +-- .../staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c | 14 +-- drivers/staging/media/sunxi/cedrus/cedrus.c | 12 +++ drivers/staging/media/sunxi/cedrus/cedrus.h | 2 + drivers/staging/media/sunxi/cedrus/cedrus_dec.c | 4 + drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c | 8 +- include/media/mpeg2-ctrls.h | 105 ++++++++++++++++----- include/media/v4l2-ctrls.h | 4 + 14 files changed, 237 insertions(+), 75 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index aa11346e7e27..f96a2dcb22cc 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -1636,14 +1636,6 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - * - __u32 - ``data_bit_offset`` - Offset (in bits) to the video data in the current slice data. - * - struct :c:type:`v4l2_mpeg2_sequence` - - ``sequence`` - - Structure with MPEG-2 sequence metadata, merging relevant fields from - the sequence header and sequence extension parts of the bitstream. - * - struct :c:type:`v4l2_mpeg2_picture` - - ``picture`` - - Structure with MPEG-2 picture metadata, merging relevant fields from - the picture header and picture coding extension parts of the bitstream. * - __u64 - ``backward_ref_ts`` - Timestamp of the V4L2 capture buffer to use as backward reference, used @@ -1661,14 +1653,28 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - * - __u32 - ``quantiser_scale_code`` - Code used to determine the quantization scale to use for the IDCT. + * - __u8 + - ``reserved`` + - Applications and drivers must set this to zero. -.. c:type:: v4l2_mpeg2_sequence +``V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE (struct)`` + Specifies the sequence parameters (as extracted from the bitstream) for the + associated MPEG-2 slice data. This includes fields matching the syntax + elements from the sequence header and sequence extension parts of the + bitstream as specified by :ref:`mpeg2part2`. + + .. note:: + + This compound control is not yet part of the public kernel API and + it is expected to change. + +.. c:type:: v4l2_ctrl_mpeg2_sequence .. cssclass:: longtable .. tabularcolumns:: |p{1.4cm}|p{6.5cm}|p{9.4cm}| -.. flat-table:: struct v4l2_mpeg2_sequence +.. flat-table:: struct v4l2_ctrl_mpeg2_sequence :header-rows: 0 :stub-columns: 0 :widths: 1 1 2 @@ -1690,7 +1696,7 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - * - __u8 - ``chroma_format`` - The chrominance sub-sampling format (1: 4:2:0, 2: 4:2:2, 3: 4:4:4). - * - __u32 + * - __u8 - ``flags`` - See :ref:`MPEG-2 Sequence Flags `. @@ -1706,11 +1712,22 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - :widths: 1 1 2 * - ``V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE`` - - 0x00000001 + - 0x01 - Indication that all the frames for the sequence are progressive instead of interlaced. -.. c:type:: v4l2_mpeg2_picture +``V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE (struct)`` + Specifies the picture parameters (as extracted from the bitstream) for the + associated MPEG-2 slice data. This includes fields matching the syntax + elements from the picture header and picture coding extension parts of the + bitstream as specified by :ref:`mpeg2part2`. + + .. note:: + + This compound control is not yet part of the public kernel API and + it is expected to change. + +.. c:type:: v4l2_ctrl_mpeg2_picture .. raw:: latex @@ -1720,30 +1737,33 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - .. tabularcolumns:: |p{1.0cm}|p{5.6cm}|p{10.7cm}| -.. flat-table:: struct v4l2_mpeg2_picture +.. flat-table:: struct v4l2_ctrl_mpeg2_picture :header-rows: 0 :stub-columns: 0 :widths: 1 1 2 + * - __u32 + - ``flags`` + - See :ref:`MPEG-2 Picture Flags `. + * - __u8 + - ``f_code[2][2]`` + - Motion vector codes. * - __u8 - ``picture_coding_type`` - Picture coding type for the frame covered by the current slice (V4L2_MPEG2_PICTURE_CODING_TYPE_I, V4L2_MPEG2_PICTURE_CODING_TYPE_P or V4L2_MPEG2_PICTURE_CODING_TYPE_B). * - __u8 - - ``f_code[2][2]`` - - Motion vector codes. + - ``picture_structure`` + - Picture structure (1: interlaced top field, 2: interlaced bottom field, + 3: progressive frame). * - __u8 - ``intra_dc_precision`` - Precision of Discrete Cosine transform (0: 8 bits precision, 1: 9 bits precision, 2: 10 bits precision, 3: 11 bits precision). * - __u8 - - ``picture_structure`` - - Picture structure (1: interlaced top field, 2: interlaced bottom field, - 3: progressive frame). - * - __u32 - - ``flags`` - - See :ref:`MPEG-2 Picture Flags `. + - ``reserved[5]`` + - Applications and drivers must set this to zero. .. _mpeg2_picture_flags: diff --git a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst index cba607f789f0..bbbacbd65d6f 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst @@ -114,8 +114,9 @@ Compressed Formats This format is adapted for stateless video decoders that implement a MPEG-2 pipeline (using the :ref:`mem2mem` and :ref:`media-request-api`). Metadata associated with the frame to decode is required to be passed - through the ``V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS`` control and - quantisation matrices can optionally be specified through the + through the ``V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE``, + ``V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE``, and ``V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS`` + controls. Quantisation matrices can optionally be specified through the ``V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION`` control. See the :ref:`associated Codec Control IDs `. Exactly one output and one capture buffer must be provided for use with diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst index 4362945fd39b..afc1505a3a7e 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst @@ -429,6 +429,18 @@ See also the examples in :ref:`control`. - n/a - A struct :c:type:`v4l2_ctrl_mpeg2_quantisation`, containing MPEG-2 quantisation matrices for stateless video decoders. + * - ``V4L2_CTRL_TYPE_MPEG2_SEQUENCE`` + - n/a + - n/a + - n/a + - A struct :c:type:`v4l2_ctrl_mpeg2_sequence`, containing MPEG-2 + sequence parameters for stateless video decoders. + * - ``V4L2_CTRL_TYPE_MPEG2_PICTURE`` + - n/a + - n/a + - n/a + - A struct :c:type:`v4l2_ctrl_mpeg2_picture`, containing MPEG-2 + picture parameters for stateless video decoders. * - ``V4L2_CTRL_TYPE_AREA`` - n/a - n/a diff --git a/Documentation/userspace-api/media/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/videodev2.h.rst.exceptions index 5b2ebaa35d24..928fdc419ee3 100644 --- a/Documentation/userspace-api/media/videodev2.h.rst.exceptions +++ b/Documentation/userspace-api/media/videodev2.h.rst.exceptions @@ -134,6 +134,8 @@ replace symbol V4L2_CTRL_TYPE_STRING :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_U16 :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_U32 :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_U8 :c:type:`v4l2_ctrl_type` +replace symbol V4L2_CTRL_TYPE_MPEG2_SEQUENCE :c:type:`v4l2_ctrl_type` +replace symbol V4L2_CTRL_TYPE_MPEG2_PICTURE :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_MPEG2_QUANTISATION :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_H264_SPS :c:type:`v4l2_ctrl_type` diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 37531302dd3a..59b16f70b093 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -977,6 +977,8 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_LTR_COUNT: return "LTR Count"; case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX: return "Frame LTR Index"; case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES: return "Use LTR Frames"; + case V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE: return "MPEG-2 Sequence Header"; + case V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE: return "MPEG-2 Picture Header"; case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS: return "MPEG-2 Slice Parameters"; case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION: return "MPEG-2 Quantisation Matrices"; case V4L2_CID_FWHT_I_FRAME_QP: return "FWHT I-Frame QP Value"; @@ -1499,6 +1501,12 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_RDS_TX_ALT_FREQS: *type = V4L2_CTRL_TYPE_U32; break; + case V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE: + *type = V4L2_CTRL_TYPE_MPEG2_SEQUENCE; + break; + case V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE: + *type = V4L2_CTRL_TYPE_MPEG2_PICTURE; + break; case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS: *type = V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS; break; @@ -1703,7 +1711,8 @@ static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx, static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, union v4l2_ctrl_ptr ptr) { - struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; + struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence; + struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture; struct v4l2_ctrl_mpeg2_quantisation *p_mpeg2_quant; struct v4l2_ctrl_vp8_frame *p_vp8_frame; struct v4l2_ctrl_fwht_params *p_fwht_params; @@ -1720,13 +1729,18 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, * v4l2_ctrl_type enum. */ switch ((u32)ctrl->type) { - case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS: - p_mpeg2_slice_params = p; + case V4L2_CTRL_TYPE_MPEG2_SEQUENCE: + p_mpeg2_sequence = p; + /* 4:2:0 */ - p_mpeg2_slice_params->sequence.chroma_format = 1; + p_mpeg2_sequence->chroma_format = 1; + break; + case V4L2_CTRL_TYPE_MPEG2_PICTURE: + p_mpeg2_picture = p; + /* interlaced top field */ - p_mpeg2_slice_params->picture.picture_structure = 1; - p_mpeg2_slice_params->picture.picture_coding_type = + p_mpeg2_picture->picture_structure = V4L2_MPEG2_PIC_TOP_FIELD; + p_mpeg2_picture->picture_coding_type = V4L2_MPEG2_PIC_CODING_TYPE_I; break; case V4L2_CTRL_TYPE_MPEG2_QUANTISATION: @@ -1909,6 +1923,8 @@ static void std_log(const struct v4l2_ctrl *ctrl) static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, union v4l2_ctrl_ptr ptr) { + struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence; + struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture; struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; struct v4l2_ctrl_vp8_frame *p_vp8_frame; struct v4l2_ctrl_fwht_params *p_fwht_params; @@ -1926,10 +1942,10 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, unsigned int i; switch ((u32)ctrl->type) { - case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS: - p_mpeg2_slice_params = p; + case V4L2_CTRL_TYPE_MPEG2_SEQUENCE: + p_mpeg2_sequence = p; - switch (p_mpeg2_slice_params->sequence.chroma_format) { + switch (p_mpeg2_sequence->chroma_format) { case 1: /* 4:2:0 */ case 2: /* 4:2:2 */ case 3: /* 4:4:4 */ @@ -1937,8 +1953,12 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, default: return -EINVAL; } + break; + + case V4L2_CTRL_TYPE_MPEG2_PICTURE: + p_mpeg2_picture = p; - switch (p_mpeg2_slice_params->picture.intra_dc_precision) { + switch (p_mpeg2_picture->intra_dc_precision) { case 0: /* 8 bits */ case 1: /* 9 bits */ case 2: /* 10 bits */ @@ -1948,7 +1968,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, return -EINVAL; } - switch (p_mpeg2_slice_params->picture.picture_structure) { + switch (p_mpeg2_picture->picture_structure) { case V4L2_MPEG2_PIC_TOP_FIELD: case V4L2_MPEG2_PIC_BOTTOM_FIELD: case V4L2_MPEG2_PIC_FRAME: @@ -1957,7 +1977,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, return -EINVAL; } - switch (p_mpeg2_slice_params->picture.picture_coding_type) { + switch (p_mpeg2_picture->picture_coding_type) { case V4L2_MPEG2_PIC_CODING_TYPE_I: case V4L2_MPEG2_PIC_CODING_TYPE_P: case V4L2_MPEG2_PIC_CODING_TYPE_B: @@ -1965,7 +1985,13 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, default: return -EINVAL; } + zero_reserved(*p_mpeg2_picture); + break; + case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS: + p_mpeg2_slice_params = p; + + zero_reserved(*p_mpeg2_slice_params); break; case V4L2_CTRL_TYPE_MPEG2_QUANTISATION: @@ -2934,6 +2960,12 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, case V4L2_CTRL_TYPE_U32: elem_size = sizeof(u32); break; + case V4L2_CTRL_TYPE_MPEG2_SEQUENCE: + elem_size = sizeof(struct v4l2_ctrl_mpeg2_sequence); + break; + case V4L2_CTRL_TYPE_MPEG2_PICTURE: + elem_size = sizeof(struct v4l2_ctrl_mpeg2_picture); + break; case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS: elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_params); break; diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index b7b4328d3c6d..4505aac2b9bb 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -295,6 +295,16 @@ static const struct hantro_ctrl controls[] = { .def = 50, .ops = &hantro_jpeg_ctrl_ops, }, + }, { + .codec = HANTRO_MPEG2_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE, + }, + }, { + .codec = HANTRO_MPEG2_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE, + }, }, { .codec = HANTRO_MPEG2_DECODER, .cfg = { diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c index 925341891b7f..fd61e1fae30e 100644 --- a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c @@ -92,8 +92,8 @@ static void hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf, - const struct v4l2_mpeg2_sequence *seq, - const struct v4l2_mpeg2_picture *pic, + const struct v4l2_ctrl_mpeg2_sequence *seq, + const struct v4l2_ctrl_mpeg2_picture *pic, const struct v4l2_ctrl_mpeg2_slice_params *slice_params) { dma_addr_t forward_addr = 0, backward_addr = 0; @@ -153,8 +153,8 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; const struct v4l2_ctrl_mpeg2_slice_params *slice_params; - const struct v4l2_mpeg2_sequence *seq; - const struct v4l2_mpeg2_picture *pic; + const struct v4l2_ctrl_mpeg2_sequence *seq; + const struct v4l2_ctrl_mpeg2_picture *pic; u32 reg; src_buf = hantro_get_src_buf(ctx); @@ -165,8 +165,10 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) slice_params = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); - seq = &slice_params->sequence; - pic = &slice_params->picture; + seq = hantro_get_ctrl(ctx, + V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE); + pic = hantro_get_ctrl(ctx, + V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE); reg = G1_REG_DEC_AXI_RD_ID(0) | G1_REG_DEC_TIMEOUT_E(1) | diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c index ff54398f6643..5b383906af59 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c @@ -95,8 +95,8 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf, - const struct v4l2_mpeg2_sequence *seq, - const struct v4l2_mpeg2_picture *pic, + const struct v4l2_ctrl_mpeg2_sequence *seq, + const struct v4l2_ctrl_mpeg2_picture *pic, const struct v4l2_ctrl_mpeg2_slice_params *slice_params) { dma_addr_t forward_addr = 0, backward_addr = 0; @@ -156,8 +156,8 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; const struct v4l2_ctrl_mpeg2_slice_params *slice_params; - const struct v4l2_mpeg2_sequence *seq; - const struct v4l2_mpeg2_picture *pic; + const struct v4l2_ctrl_mpeg2_sequence *seq; + const struct v4l2_ctrl_mpeg2_picture *pic; u32 reg; src_buf = hantro_get_src_buf(ctx); @@ -167,8 +167,10 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) slice_params = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); - seq = &slice_params->sequence; - pic = &slice_params->picture; + seq = hantro_get_ctrl(ctx, + V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE); + pic = hantro_get_ctrl(ctx, + V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE); reg = VDPU_REG_DEC_ADV_PRE_DIS(0) | VDPU_REG_DEC_SCMD_DIS(0) | diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 62a5407664ae..878752b30c10 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -29,6 +29,18 @@ #include "cedrus_hw.h" static const struct cedrus_control cedrus_controls[] = { + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE, + }, + .codec = CEDRUS_CODEC_MPEG2, + }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE, + }, + .codec = CEDRUS_CODEC_MPEG2, + }, { .cfg = { .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 6516bff3d319..989873ccb98c 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -68,6 +68,8 @@ struct cedrus_h264_run { }; struct cedrus_mpeg2_run { + const struct v4l2_ctrl_mpeg2_sequence *sequence; + const struct v4l2_ctrl_mpeg2_picture *picture; const struct v4l2_ctrl_mpeg2_slice_params *slice_params; const struct v4l2_ctrl_mpeg2_quantisation *quantisation; }; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index 238f779d2ba4..f4cc6aebfac9 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -40,6 +40,10 @@ void cedrus_device_run(void *priv) switch (ctx->src_fmt.pixelformat) { case V4L2_PIX_FMT_MPEG2_SLICE: + run.mpeg2.sequence = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE); + run.mpeg2.picture = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE); run.mpeg2.slice_params = cedrus_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); run.mpeg2.quantisation = cedrus_find_control_data(ctx, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c index e39a17d28c7d..65a175c6a5c2 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c @@ -51,8 +51,8 @@ static void cedrus_mpeg2_irq_disable(struct cedrus_ctx *ctx) static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) { const struct v4l2_ctrl_mpeg2_slice_params *slice_params; - const struct v4l2_mpeg2_sequence *seq; - const struct v4l2_mpeg2_picture *pic; + const struct v4l2_ctrl_mpeg2_sequence *seq; + const struct v4l2_ctrl_mpeg2_picture *pic; const struct v4l2_ctrl_mpeg2_quantisation *quantisation; dma_addr_t src_buf_addr, dst_luma_addr, dst_chroma_addr; dma_addr_t fwd_luma_addr, fwd_chroma_addr; @@ -66,8 +66,8 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) u32 reg; slice_params = run->mpeg2.slice_params; - seq = &slice_params->sequence; - pic = &slice_params->picture; + seq = run->mpeg2.sequence; + pic = run->mpeg2.picture; quantisation = run->mpeg2.quantisation; diff --git a/include/media/mpeg2-ctrls.h b/include/media/mpeg2-ctrls.h index d3190979d574..b4a6aa16d4c0 100644 --- a/include/media/mpeg2-ctrls.h +++ b/include/media/mpeg2-ctrls.h @@ -13,24 +13,44 @@ #define V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS (V4L2_CID_CODEC_BASE+250) #define V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION (V4L2_CID_CODEC_BASE+251) +#define V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE (V4L2_CID_CODEC_BASE+252) +#define V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE (V4L2_CID_CODEC_BASE+253) /* enum v4l2_ctrl_type type values */ -#define V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS 0x0103 -#define V4L2_CTRL_TYPE_MPEG2_QUANTISATION 0x0104 +#define V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS 0x0130 +#define V4L2_CTRL_TYPE_MPEG2_QUANTISATION 0x0131 +#define V4L2_CTRL_TYPE_MPEG2_SEQUENCE 0x0132 +#define V4L2_CTRL_TYPE_MPEG2_PICTURE 0x0133 -#define V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE 0x0001 +#define V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE 0x01 -struct v4l2_mpeg2_sequence { - /* ISO/IEC 13818-2, ITU-T Rec. H.262: Sequence header */ +/** + * struct v4l2_ctrl_mpeg2_sequence - MPEG-2 sequence header + * + * All the members on this structure match the sequence header and sequence + * extension syntaxes as specified by the MPEG-2 specification. + * + * Fields horizontal_size, vertical_size and vbv_buffer_size are a + * combination of respective _value and extension syntax elements, + * as described in section 6.3.3 "Sequence header". + * + * @horizontal_size: combination of elements horizontal_size_value and + * horizontal_size_extension. + * @vertical_size: combination of elements vertical_size_value and + * vertical_size_extension. + * @vbv_buffer_size: combination of elements vbv_buffer_size_value and + * vbv_buffer_size_extension. + * @profile_and_level_indication: see MPEG-2 specification. + * @chroma_format: see MPEG-2 specification. + * @flags: see V4L2_MPEG2_SEQ_FLAG_{}. + */ +struct v4l2_ctrl_mpeg2_sequence { __u16 horizontal_size; __u16 vertical_size; __u32 vbv_buffer_size; - - /* ISO/IEC 13818-2, ITU-T Rec. H.262: Sequence extension */ __u16 profile_and_level_indication; __u8 chroma_format; - - __u32 flags; + __u8 flags; }; #define V4L2_MPEG2_PIC_CODING_TYPE_I 1 @@ -51,33 +71,72 @@ struct v4l2_mpeg2_sequence { #define V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST 0x0040 #define V4L2_MPEG2_PIC_FLAG_PROGRESSIVE 0x0080 -struct v4l2_mpeg2_picture { - /* ISO/IEC 13818-2, ITU-T Rec. H.262: Picture header */ - __u8 picture_coding_type; - - /* ISO/IEC 13818-2, ITU-T Rec. H.262: Picture coding extension */ +/** + * struct v4l2_ctrl_mpeg2_picture - MPEG-2 picture header + * + * All the members on this structure match the picture header and picture + * coding extension syntaxes as specified by the MPEG-2 specification. + * + * @flags: see V4L2_MPEG2_PIC_FLAG_{}. + * @f_code[2][2]: see MPEG-2 specification. + * @picture_coding_type: see MPEG-2 specification. + * @picture_structure: see V4L2_MPEG2_PIC_{}_FIELD. + * @intra_dc_precision: see MPEG-2 specification. + * @reserved: padding field. Should be zeroed by applications. + */ +struct v4l2_ctrl_mpeg2_picture { + __u32 flags; __u8 f_code[2][2]; - __u8 intra_dc_precision; + __u8 picture_coding_type; __u8 picture_structure; - - __u32 flags; + __u8 intra_dc_precision; + __u8 reserved[5]; }; +/** + * struct v4l2_ctrl_mpeg2_slice_params - MPEG-2 slice header + * + * @backward_ref_ts: timestamp of the V4L2 capture buffer to use as + * reference for backward prediction. + * @forward_ref_ts: timestamp of the V4L2 capture buffer to use as + * reference for forward prediction. These timestamp refers to the + * timestamp field in struct v4l2_buffer. Use v4l2_timeval_to_ns() + * to convert the struct timeval to a __u64. + * @quantiser_scale_code: quantiser scale integer matching an + * homonymous syntax element. + * @reserved: padding field. Should be zeroed by applications. + */ struct v4l2_ctrl_mpeg2_slice_params { __u32 bit_size; __u32 data_bit_offset; __u64 backward_ref_ts; __u64 forward_ref_ts; - - struct v4l2_mpeg2_sequence sequence; - struct v4l2_mpeg2_picture picture; - - /* ISO/IEC 13818-2, ITU-T Rec. H.262: Slice */ __u32 quantiser_scale_code; + __u32 reserved; }; +/** + * struct v4l2_ctrl_mpeg2_quantisation - MPEG-2 quantisation + * + * Quantization matrices as specified by section 6.3.7 + * "Quant matrix extension". + * + * @intra_quantiser_matrix: The quantisation matrix coefficients + * for intra-coded frames, in zigzag scanning order. It is relevant + * for both luma and chroma components, although it can be superseded + * by the chroma-specific matrix for non-4:2:0 YUV formats. + * @non_intra_quantiser_matrix: The quantisation matrix coefficients + * for non-intra-coded frames, in zigzag scanning order. It is relevant + * for both luma and chroma components, although it can be superseded + * by the chroma-specific matrix for non-4:2:0 YUV formats. + * @chroma_intra_quantiser_matrix: The quantisation matrix coefficients + * for the chominance component of intra-coded frames, in zigzag scanning + * order. Only relevant for 4:2:2 and 4:4:4 YUV formats. + * @chroma_non_intra_quantiser_matrix: The quantisation matrix coefficients + * for the chrominance component of non-intra-coded frames, in zigzag scanning + * order. Only relevant for 4:2:2 and 4:4:4 YUV formats. + */ struct v4l2_ctrl_mpeg2_quantisation { - /* ISO/IEC 13818-2, ITU-T Rec. H.262: Quant matrix extension */ __u8 intra_quantiser_matrix[64]; __u8 non_intra_quantiser_matrix[64]; __u8 chroma_intra_quantiser_matrix[64]; diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index a38e6bd02a6a..572ff7eb7be1 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -40,6 +40,8 @@ struct video_device; * @p_u16: Pointer to a 16-bit unsigned value. * @p_u32: Pointer to a 32-bit unsigned value. * @p_char: Pointer to a string. + * @p_mpeg2_sequence: Pointer to a MPEG2 sequence structure. + * @p_mpeg2_picture: Pointer to a MPEG2 picture structure. * @p_mpeg2_slice_params: Pointer to a MPEG2 slice parameters structure. * @p_mpeg2_quantisation: Pointer to a MPEG2 quantisation data structure. * @p_fwht_params: Pointer to a FWHT stateless parameters structure. @@ -66,6 +68,8 @@ union v4l2_ctrl_ptr { u16 *p_u16; u32 *p_u32; char *p_char; + struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence; + struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture; struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; struct v4l2_ctrl_mpeg2_quantisation *p_mpeg2_quantisation; struct v4l2_ctrl_fwht_params *p_fwht_params; -- cgit v1.3.1 From b6d7e8031c9c17462935329ca8b37f0da2f99da0 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 29 Apr 2021 16:48:13 +0200 Subject: media: uapi: mpeg2: Move reference buffer fields The forward and backwards references are specified per-picture and not per-slice. Move it to V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE. Signed-off-by: Ezequiel Garcia Tested-by: Jernej Skrabec Reviewed-by: Jernej Skrabec Tested-by: Daniel Almeida Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/ext-ctrls-codec.rst | 28 +++++++++++----------- drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c | 6 ++--- .../staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c | 6 ++--- drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c | 4 ++-- include/media/mpeg2-ctrls.h | 16 ++++++------- 5 files changed, 28 insertions(+), 32 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index f96a2dcb22cc..1765b2a1129d 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -1636,20 +1636,6 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - * - __u32 - ``data_bit_offset`` - Offset (in bits) to the video data in the current slice data. - * - __u64 - - ``backward_ref_ts`` - - Timestamp of the V4L2 capture buffer to use as backward reference, used - with B-coded and P-coded frames. The timestamp refers to the - ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the - :c:func:`v4l2_timeval_to_ns()` function to convert the struct - :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64. - * - __u64 - - ``forward_ref_ts`` - - Timestamp for the V4L2 capture buffer to use as forward reference, used - with B-coded frames. The timestamp refers to the ``timestamp`` field in - struct :c:type:`v4l2_buffer`. Use the :c:func:`v4l2_timeval_to_ns()` - function to convert the struct :c:type:`timeval` in struct - :c:type:`v4l2_buffer` to a __u64. * - __u32 - ``quantiser_scale_code`` - Code used to determine the quantization scale to use for the IDCT. @@ -1742,6 +1728,20 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - :stub-columns: 0 :widths: 1 1 2 + * - __u64 + - ``backward_ref_ts`` + - Timestamp of the V4L2 capture buffer to use as backward reference, used + with B-coded and P-coded frames. The timestamp refers to the + ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the + :c:func:`v4l2_timeval_to_ns()` function to convert the struct + :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64. + * - __u64 + - ``forward_ref_ts`` + - Timestamp for the V4L2 capture buffer to use as forward reference, used + with B-coded frames. The timestamp refers to the ``timestamp`` field in + struct :c:type:`v4l2_buffer`. Use the :c:func:`v4l2_timeval_to_ns()` + function to convert the struct :c:type:`timeval` in struct + :c:type:`v4l2_buffer` to a __u64. * - __u32 - ``flags`` - See :ref:`MPEG-2 Picture Flags `. diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c index fd61e1fae30e..19c897cbd348 100644 --- a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c @@ -101,12 +101,10 @@ hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, switch (pic->picture_coding_type) { case V4L2_MPEG2_PIC_CODING_TYPE_B: - backward_addr = hantro_get_ref(ctx, - slice_params->backward_ref_ts); + backward_addr = hantro_get_ref(ctx, pic->backward_ref_ts); fallthrough; case V4L2_MPEG2_PIC_CODING_TYPE_P: - forward_addr = hantro_get_ref(ctx, - slice_params->forward_ref_ts); + forward_addr = hantro_get_ref(ctx, pic->forward_ref_ts); } /* Source bitstream buffer */ diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c index 5b383906af59..18bd14704ebf 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c @@ -104,12 +104,10 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu, switch (pic->picture_coding_type) { case V4L2_MPEG2_PIC_CODING_TYPE_B: - backward_addr = hantro_get_ref(ctx, - slice_params->backward_ref_ts); + backward_addr = hantro_get_ref(ctx, pic->backward_ref_ts); fallthrough; case V4L2_MPEG2_PIC_CODING_TYPE_P: - forward_addr = hantro_get_ref(ctx, - slice_params->forward_ref_ts); + forward_addr = hantro_get_ref(ctx, pic->forward_ref_ts); } /* Source bitstream buffer */ diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c index 65a175c6a5c2..16e99792cf42 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c @@ -128,14 +128,14 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - forward_idx = vb2_find_timestamp(vq, slice_params->forward_ref_ts, 0); + forward_idx = vb2_find_timestamp(vq, pic->forward_ref_ts, 0); fwd_luma_addr = cedrus_dst_buf_addr(ctx, forward_idx, 0); fwd_chroma_addr = cedrus_dst_buf_addr(ctx, forward_idx, 1); cedrus_write(dev, VE_DEC_MPEG_FWD_REF_LUMA_ADDR, fwd_luma_addr); cedrus_write(dev, VE_DEC_MPEG_FWD_REF_CHROMA_ADDR, fwd_chroma_addr); - backward_idx = vb2_find_timestamp(vq, slice_params->backward_ref_ts, 0); + backward_idx = vb2_find_timestamp(vq, pic->backward_ref_ts, 0); bwd_luma_addr = cedrus_dst_buf_addr(ctx, backward_idx, 0); bwd_chroma_addr = cedrus_dst_buf_addr(ctx, backward_idx, 1); diff --git a/include/media/mpeg2-ctrls.h b/include/media/mpeg2-ctrls.h index b4a6aa16d4c0..922ca2243f44 100644 --- a/include/media/mpeg2-ctrls.h +++ b/include/media/mpeg2-ctrls.h @@ -77,6 +77,12 @@ struct v4l2_ctrl_mpeg2_sequence { * All the members on this structure match the picture header and picture * coding extension syntaxes as specified by the MPEG-2 specification. * + * @backward_ref_ts: timestamp of the V4L2 capture buffer to use as + * reference for backward prediction. + * @forward_ref_ts: timestamp of the V4L2 capture buffer to use as + * reference for forward prediction. These timestamp refers to the + * timestamp field in struct v4l2_buffer. Use v4l2_timeval_to_ns() + * to convert the struct timeval to a __u64. * @flags: see V4L2_MPEG2_PIC_FLAG_{}. * @f_code[2][2]: see MPEG-2 specification. * @picture_coding_type: see MPEG-2 specification. @@ -85,6 +91,8 @@ struct v4l2_ctrl_mpeg2_sequence { * @reserved: padding field. Should be zeroed by applications. */ struct v4l2_ctrl_mpeg2_picture { + __u64 backward_ref_ts; + __u64 forward_ref_ts; __u32 flags; __u8 f_code[2][2]; __u8 picture_coding_type; @@ -96,12 +104,6 @@ struct v4l2_ctrl_mpeg2_picture { /** * struct v4l2_ctrl_mpeg2_slice_params - MPEG-2 slice header * - * @backward_ref_ts: timestamp of the V4L2 capture buffer to use as - * reference for backward prediction. - * @forward_ref_ts: timestamp of the V4L2 capture buffer to use as - * reference for forward prediction. These timestamp refers to the - * timestamp field in struct v4l2_buffer. Use v4l2_timeval_to_ns() - * to convert the struct timeval to a __u64. * @quantiser_scale_code: quantiser scale integer matching an * homonymous syntax element. * @reserved: padding field. Should be zeroed by applications. @@ -109,8 +111,6 @@ struct v4l2_ctrl_mpeg2_picture { struct v4l2_ctrl_mpeg2_slice_params { __u32 bit_size; __u32 data_bit_offset; - __u64 backward_ref_ts; - __u64 forward_ref_ts; __u32 quantiser_scale_code; __u32 reserved; }; -- cgit v1.3.1 From 45f97ba1ce8059632c6f1518fda1faedd7db55fb Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 29 Apr 2021 16:48:15 +0200 Subject: media: uapi: mpeg2: Remove V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS The Hantro and Cedrus drivers work in frame-mode, meaning they expect all the slices in a picture (either frame or field structure) to be passed in each OUTPUT buffer. These two are the only V4L2 MPEG-2 stateless decoders currently supported. Given the VA-API drivers also work per-frame, coalescing all the MPEG-2 slices in a buffer before the decoding operation, it makes sense to not expect slice-mode drivers and therefore remove V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS. This is done to avoid carrying an unused interface. If needed, this control can be added without breaking backwards compatibility. Note that this would mean introducing a enumerator control to specify the decoding mode (see V4L2_CID_STATELESS_H264_DECODE_MODE). Signed-off-by: Ezequiel Garcia Co-developed-by: Nicolas Dufresne Signed-off-by: Nicolas Dufresne Tested-by: Jernej Skrabec Reviewed-by: Jernej Skrabec Tested-by: Daniel Almeida Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/ext-ctrls-codec.rst | 35 ---------------------- .../userspace-api/media/v4l/pixfmt-compressed.rst | 6 ++-- .../userspace-api/media/v4l/vidioc-queryctrl.rst | 6 ---- .../userspace-api/media/videodev2.h.rst.exceptions | 1 - drivers/media/v4l2-core/v4l2-ctrls.c | 19 ------------ drivers/staging/media/hantro/hantro_drv.c | 5 ---- drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c | 9 ++---- .../staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c | 8 ++--- drivers/staging/media/sunxi/cedrus/cedrus.c | 6 ---- drivers/staging/media/sunxi/cedrus/cedrus.h | 1 - drivers/staging/media/sunxi/cedrus/cedrus_dec.c | 2 -- drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c | 2 -- include/media/mpeg2-ctrls.h | 16 ---------- include/media/v4l2-ctrls.h | 2 -- 14 files changed, 7 insertions(+), 111 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index 1765b2a1129d..f10b04fba229 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -1608,41 +1608,6 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - .. _v4l2-mpeg-mpeg2: -``V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS (struct)`` - Specifies the slice parameters (as extracted from the bitstream) for the - associated MPEG-2 slice data. This includes the necessary parameters for - configuring a stateless hardware decoding pipeline for MPEG-2. - The bitstream parameters are defined according to :ref:`mpeg2part2`. - - .. note:: - - This compound control is not yet part of the public kernel API and - it is expected to change. - -.. c:type:: v4l2_ctrl_mpeg2_slice_params - -.. tabularcolumns:: |p{5.6cm}|p{4.6cm}|p{7.1cm}| - -.. cssclass:: longtable - -.. flat-table:: struct v4l2_ctrl_mpeg2_slice_params - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __u32 - - ``bit_size`` - - Size (in bits) of the current slice data. - * - __u32 - - ``data_bit_offset`` - - Offset (in bits) to the video data in the current slice data. - * - __u32 - - ``quantiser_scale_code`` - - Code used to determine the quantization scale to use for the IDCT. - * - __u8 - - ``reserved`` - - Applications and drivers must set this to zero. - ``V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE (struct)`` Specifies the sequence parameters (as extracted from the bitstream) for the associated MPEG-2 slice data. This includes fields matching the syntax diff --git a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst index bbbacbd65d6f..6c10a062adac 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst @@ -114,9 +114,9 @@ Compressed Formats This format is adapted for stateless video decoders that implement a MPEG-2 pipeline (using the :ref:`mem2mem` and :ref:`media-request-api`). Metadata associated with the frame to decode is required to be passed - through the ``V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE``, - ``V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE``, and ``V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS`` - controls. Quantisation matrices can optionally be specified through the + through the ``V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE`` and + ``V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE`` controls. + Quantisation matrices can optionally be specified through the ``V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION`` control. See the :ref:`associated Codec Control IDs `. Exactly one output and one capture buffer must be provided for use with diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst index afc1505a3a7e..07e54029e1e9 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst @@ -417,12 +417,6 @@ See also the examples in :ref:`control`. - any - An unsigned 32-bit valued control ranging from minimum to maximum inclusive. The step value indicates the increment between values. - * - ``V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS`` - - n/a - - n/a - - n/a - - A struct :c:type:`v4l2_ctrl_mpeg2_slice_params`, containing MPEG-2 - slice parameters for stateless video decoders. * - ``V4L2_CTRL_TYPE_MPEG2_QUANTISATION`` - n/a - n/a diff --git a/Documentation/userspace-api/media/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/videodev2.h.rst.exceptions index 928fdc419ee3..2217b56c2686 100644 --- a/Documentation/userspace-api/media/videodev2.h.rst.exceptions +++ b/Documentation/userspace-api/media/videodev2.h.rst.exceptions @@ -136,7 +136,6 @@ replace symbol V4L2_CTRL_TYPE_U32 :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_U8 :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_MPEG2_SEQUENCE :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_MPEG2_PICTURE :c:type:`v4l2_ctrl_type` -replace symbol V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_MPEG2_QUANTISATION :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_H264_SPS :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_H264_PPS :c:type:`v4l2_ctrl_type` diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 59b16f70b093..6a033102d31b 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -979,7 +979,6 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES: return "Use LTR Frames"; case V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE: return "MPEG-2 Sequence Header"; case V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE: return "MPEG-2 Picture Header"; - case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS: return "MPEG-2 Slice Parameters"; case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION: return "MPEG-2 Quantisation Matrices"; case V4L2_CID_FWHT_I_FRAME_QP: return "FWHT I-Frame QP Value"; case V4L2_CID_FWHT_P_FRAME_QP: return "FWHT P-Frame QP Value"; @@ -1507,9 +1506,6 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE: *type = V4L2_CTRL_TYPE_MPEG2_PICTURE; break; - case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS: - *type = V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS; - break; case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION: *type = V4L2_CTRL_TYPE_MPEG2_QUANTISATION; break; @@ -1723,11 +1719,6 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, else memset(p, 0, ctrl->elem_size); - /* - * The cast is needed to get rid of a gcc warning complaining that - * V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS is not part of the - * v4l2_ctrl_type enum. - */ switch ((u32)ctrl->type) { case V4L2_CTRL_TYPE_MPEG2_SEQUENCE: p_mpeg2_sequence = p; @@ -1925,7 +1916,6 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, { struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence; struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture; - struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; struct v4l2_ctrl_vp8_frame *p_vp8_frame; struct v4l2_ctrl_fwht_params *p_fwht_params; struct v4l2_ctrl_h264_sps *p_h264_sps; @@ -1988,12 +1978,6 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, zero_reserved(*p_mpeg2_picture); break; - case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS: - p_mpeg2_slice_params = p; - - zero_reserved(*p_mpeg2_slice_params); - break; - case V4L2_CTRL_TYPE_MPEG2_QUANTISATION: break; @@ -2966,9 +2950,6 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, case V4L2_CTRL_TYPE_MPEG2_PICTURE: elem_size = sizeof(struct v4l2_ctrl_mpeg2_picture); break; - case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS: - elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_params); - break; case V4L2_CTRL_TYPE_MPEG2_QUANTISATION: elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantisation); break; diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 4505aac2b9bb..dc9478ac7141 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -305,11 +305,6 @@ static const struct hantro_ctrl controls[] = { .cfg = { .id = V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE, }, - }, { - .codec = HANTRO_MPEG2_DECODER, - .cfg = { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS, - }, }, { .codec = HANTRO_MPEG2_DECODER, .cfg = { diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c index b9c8b288987a..25d912cbe2ff 100644 --- a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c @@ -93,8 +93,7 @@ hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf, const struct v4l2_ctrl_mpeg2_sequence *seq, - const struct v4l2_ctrl_mpeg2_picture *pic, - const struct v4l2_ctrl_mpeg2_slice_params *slice_params) + const struct v4l2_ctrl_mpeg2_picture *pic) { dma_addr_t forward_addr = 0, backward_addr = 0; dma_addr_t current_addr, addr; @@ -150,7 +149,6 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; - const struct v4l2_ctrl_mpeg2_slice_params *slice_params; const struct v4l2_ctrl_mpeg2_sequence *seq; const struct v4l2_ctrl_mpeg2_picture *pic; u32 reg; @@ -161,8 +159,6 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) /* Apply request controls if any */ hantro_start_prepare_run(ctx); - slice_params = hantro_get_ctrl(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); seq = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE); pic = hantro_get_ctrl(ctx, @@ -232,10 +228,9 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) vdpu_write_relaxed(vpu, reg, G1_SWREG(55)); hantro_g1_mpeg2_dec_set_quantisation(vpu, ctx); - hantro_g1_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf, &dst_buf->vb2_buf, - seq, pic, slice_params); + seq, pic); hantro_end_prepare_run(ctx); diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c index 314269811244..d16d76760278 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c @@ -96,8 +96,7 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf, const struct v4l2_ctrl_mpeg2_sequence *seq, - const struct v4l2_ctrl_mpeg2_picture *pic, - const struct v4l2_ctrl_mpeg2_slice_params *slice_params) + const struct v4l2_ctrl_mpeg2_picture *pic) { dma_addr_t forward_addr = 0, backward_addr = 0; dma_addr_t current_addr, addr; @@ -153,7 +152,6 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; - const struct v4l2_ctrl_mpeg2_slice_params *slice_params; const struct v4l2_ctrl_mpeg2_sequence *seq; const struct v4l2_ctrl_mpeg2_picture *pic; u32 reg; @@ -163,8 +161,6 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) hantro_start_prepare_run(ctx); - slice_params = hantro_get_ctrl(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); seq = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE); pic = hantro_get_ctrl(ctx, @@ -241,7 +237,7 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) rk3399_vpu_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf, &dst_buf->vb2_buf, - seq, pic, slice_params); + seq, pic); /* Kick the watchdog and start decoding */ hantro_end_prepare_run(ctx); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 878752b30c10..4430c8fa2cc7 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -41,12 +41,6 @@ static const struct cedrus_control cedrus_controls[] = { }, .codec = CEDRUS_CODEC_MPEG2, }, - { - .cfg = { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS, - }, - .codec = CEDRUS_CODEC_MPEG2, - }, { .cfg = { .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 989873ccb98c..bbcdcd0787cf 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -70,7 +70,6 @@ struct cedrus_h264_run { struct cedrus_mpeg2_run { const struct v4l2_ctrl_mpeg2_sequence *sequence; const struct v4l2_ctrl_mpeg2_picture *picture; - const struct v4l2_ctrl_mpeg2_slice_params *slice_params; const struct v4l2_ctrl_mpeg2_quantisation *quantisation; }; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index f4cc6aebfac9..e98185c1f5a7 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -44,8 +44,6 @@ void cedrus_device_run(void *priv) V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE); run.mpeg2.picture = cedrus_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE); - run.mpeg2.slice_params = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); run.mpeg2.quantisation = cedrus_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION); break; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c index fd71cb175318..5dad2f296c6d 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c @@ -50,7 +50,6 @@ static void cedrus_mpeg2_irq_disable(struct cedrus_ctx *ctx) static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) { - const struct v4l2_ctrl_mpeg2_slice_params *slice_params; const struct v4l2_ctrl_mpeg2_sequence *seq; const struct v4l2_ctrl_mpeg2_picture *pic; const struct v4l2_ctrl_mpeg2_quantisation *quantisation; @@ -65,7 +64,6 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) unsigned int i; u32 reg; - slice_params = run->mpeg2.slice_params; seq = run->mpeg2.sequence; pic = run->mpeg2.picture; diff --git a/include/media/mpeg2-ctrls.h b/include/media/mpeg2-ctrls.h index 922ca2243f44..a84ce088a42e 100644 --- a/include/media/mpeg2-ctrls.h +++ b/include/media/mpeg2-ctrls.h @@ -11,13 +11,11 @@ #ifndef _MPEG2_CTRLS_H_ #define _MPEG2_CTRLS_H_ -#define V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS (V4L2_CID_CODEC_BASE+250) #define V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION (V4L2_CID_CODEC_BASE+251) #define V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE (V4L2_CID_CODEC_BASE+252) #define V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE (V4L2_CID_CODEC_BASE+253) /* enum v4l2_ctrl_type type values */ -#define V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS 0x0130 #define V4L2_CTRL_TYPE_MPEG2_QUANTISATION 0x0131 #define V4L2_CTRL_TYPE_MPEG2_SEQUENCE 0x0132 #define V4L2_CTRL_TYPE_MPEG2_PICTURE 0x0133 @@ -101,20 +99,6 @@ struct v4l2_ctrl_mpeg2_picture { __u8 reserved[5]; }; -/** - * struct v4l2_ctrl_mpeg2_slice_params - MPEG-2 slice header - * - * @quantiser_scale_code: quantiser scale integer matching an - * homonymous syntax element. - * @reserved: padding field. Should be zeroed by applications. - */ -struct v4l2_ctrl_mpeg2_slice_params { - __u32 bit_size; - __u32 data_bit_offset; - __u32 quantiser_scale_code; - __u32 reserved; -}; - /** * struct v4l2_ctrl_mpeg2_quantisation - MPEG-2 quantisation * diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 572ff7eb7be1..215e44172c66 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -42,7 +42,6 @@ struct video_device; * @p_char: Pointer to a string. * @p_mpeg2_sequence: Pointer to a MPEG2 sequence structure. * @p_mpeg2_picture: Pointer to a MPEG2 picture structure. - * @p_mpeg2_slice_params: Pointer to a MPEG2 slice parameters structure. * @p_mpeg2_quantisation: Pointer to a MPEG2 quantisation data structure. * @p_fwht_params: Pointer to a FWHT stateless parameters structure. * @p_h264_sps: Pointer to a struct v4l2_ctrl_h264_sps. @@ -70,7 +69,6 @@ union v4l2_ctrl_ptr { char *p_char; struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence; struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture; - struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; struct v4l2_ctrl_mpeg2_quantisation *p_mpeg2_quantisation; struct v4l2_ctrl_fwht_params *p_fwht_params; struct v4l2_ctrl_h264_sps *p_h264_sps; -- cgit v1.3.1 From f4815b399111d992c1118c708f464a847dfd29e2 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 29 Apr 2021 16:48:18 +0200 Subject: media: uapi: move MPEG-2 stateless controls out of staging Until now, the MPEG-2 V4L2 API was not exported as a public API, and only defined in a private media header (media/mpeg2-ctrls.h). After reviewing the MPEG-2 specification in detail, and reworking the controls so they match the MPEG-2 semantics properly, we can consider it ready. Signed-off-by: Ezequiel Garcia Tested-by: Jernej Skrabec Reviewed-by: Jernej Skrabec Tested-by: Daniel Almeida Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/v4l/ext-ctrls-codec-stateless.rst | 214 ++++++++++++++++++++ .../userspace-api/media/v4l/ext-ctrls-codec.rst | 216 --------------------- .../userspace-api/media/v4l/pixfmt-compressed.rst | 10 +- .../userspace-api/media/v4l/vidioc-g-ext-ctrls.rst | 12 ++ drivers/media/v4l2-core/v4l2-ctrls.c | 12 +- drivers/staging/media/hantro/hantro_drv.c | 6 +- drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c | 6 +- .../staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c | 6 +- drivers/staging/media/sunxi/cedrus/cedrus.c | 6 +- drivers/staging/media/sunxi/cedrus/cedrus_dec.c | 6 +- include/media/mpeg2-ctrls.h | 126 ------------ include/media/v4l2-ctrls.h | 1 - include/uapi/linux/v4l2-controls.h | 112 +++++++++++ include/uapi/linux/videodev2.h | 3 + 14 files changed, 367 insertions(+), 369 deletions(-) delete mode 100644 include/media/mpeg2-ctrls.h (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst index 3fc04daa9ffb..2aa508ffb6b9 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst @@ -1244,3 +1244,217 @@ FWHT Flags * - __u8 - ``padding[3]`` - Applications and drivers must set this to zero. + +.. _v4l2-codec-stateless-mpeg2: + +``V4L2_CID_STATELESS_MPEG2_SEQUENCE (struct)`` + Specifies the sequence parameters (as extracted from the bitstream) for the + associated MPEG-2 slice data. This includes fields matching the syntax + elements from the sequence header and sequence extension parts of the + bitstream as specified by :ref:`mpeg2part2`. + +.. c:type:: v4l2_ctrl_mpeg2_sequence + +.. raw:: latex + + \small + +.. cssclass:: longtable + +.. tabularcolumns:: |p{1.4cm}|p{6.5cm}|p{9.4cm}| + +.. flat-table:: struct v4l2_ctrl_mpeg2_sequence + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u16 + - ``horizontal_size`` + - The width of the displayable part of the frame's luminance component. + * - __u16 + - ``vertical_size`` + - The height of the displayable part of the frame's luminance component. + * - __u32 + - ``vbv_buffer_size`` + - Used to calculate the required size of the video buffering verifier, + defined (in bits) as: 16 * 1024 * vbv_buffer_size. + * - __u16 + - ``profile_and_level_indication`` + - The current profile and level indication as extracted from the + bitstream. + * - __u8 + - ``chroma_format`` + - The chrominance sub-sampling format (1: 4:2:0, 2: 4:2:2, 3: 4:4:4). + * - __u8 + - ``flags`` + - See :ref:`MPEG-2 Sequence Flags `. + +.. _mpeg2_sequence_flags: + +``MPEG-2 Sequence Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE`` + - 0x01 + - Indication that all the frames for the sequence are progressive instead + of interlaced. + +.. raw:: latex + + \normalsize + +``V4L2_CID_STATELESS_MPEG2_PICTURE (struct)`` + Specifies the picture parameters (as extracted from the bitstream) for the + associated MPEG-2 slice data. This includes fields matching the syntax + elements from the picture header and picture coding extension parts of the + bitstream as specified by :ref:`mpeg2part2`. + +.. c:type:: v4l2_ctrl_mpeg2_picture + +.. raw:: latex + + \small + +.. cssclass:: longtable + +.. tabularcolumns:: |p{1.0cm}|p{5.6cm}|p{10.7cm}| + +.. flat-table:: struct v4l2_ctrl_mpeg2_picture + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u64 + - ``backward_ref_ts`` + - Timestamp of the V4L2 capture buffer to use as backward reference, used + with B-coded and P-coded frames. The timestamp refers to the + ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the + :c:func:`v4l2_timeval_to_ns()` function to convert the struct + :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64. + * - __u64 + - ``forward_ref_ts`` + - Timestamp for the V4L2 capture buffer to use as forward reference, used + with B-coded frames. The timestamp refers to the ``timestamp`` field in + struct :c:type:`v4l2_buffer`. Use the :c:func:`v4l2_timeval_to_ns()` + function to convert the struct :c:type:`timeval` in struct + :c:type:`v4l2_buffer` to a __u64. + * - __u32 + - ``flags`` + - See :ref:`MPEG-2 Picture Flags `. + * - __u8 + - ``f_code[2][2]`` + - Motion vector codes. + * - __u8 + - ``picture_coding_type`` + - Picture coding type for the frame covered by the current slice + (V4L2_MPEG2_PICTURE_CODING_TYPE_I, V4L2_MPEG2_PICTURE_CODING_TYPE_P or + V4L2_MPEG2_PICTURE_CODING_TYPE_B). + * - __u8 + - ``picture_structure`` + - Picture structure (1: interlaced top field, 2: interlaced bottom field, + 3: progressive frame). + * - __u8 + - ``intra_dc_precision`` + - Precision of Discrete Cosine transform (0: 8 bits precision, + 1: 9 bits precision, 2: 10 bits precision, 3: 11 bits precision). + * - __u8 + - ``reserved[5]`` + - Applications and drivers must set this to zero. + +.. _mpeg2_picture_flags: + +``MPEG-2 Picture Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST`` + - 0x00000001 + - If set and it's an interlaced stream, top field is output first. + * - ``V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT`` + - 0x00000002 + - If set only frame-DCT and frame prediction are used. + * - ``V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV`` + - 0x00000004 + - If set motion vectors are coded for intra macroblocks. + * - ``V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE`` + - 0x00000008 + - This flag affects the inverse quantization process. + * - ``V4L2_MPEG2_PIC_FLAG_INTRA_VLC`` + - 0x00000010 + - This flag affects the decoding of transform coefficient data. + * - ``V4L2_MPEG2_PIC_FLAG_ALT_SCAN`` + - 0x00000020 + - This flag affects the decoding of transform coefficient data. + * - ``V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST`` + - 0x00000040 + - This flag affects the decoding process of progressive frames. + * - ``V4L2_MPEG2_PIC_FLAG_PROGRESSIVE`` + - 0x00000080 + - Indicates whether the current frame is progressive. + +.. raw:: latex + + \normalsize + +``V4L2_CID_STATELESS_MPEG2_QUANTISATION (struct)`` + Specifies quantisation matrices, in zigzag scanning order, for the + associated MPEG-2 slice data. This control is initialized by the kernel + to the matrices default values. If a bitstream transmits a user-defined + quantisation matrices load, applications are expected to use this control. + Applications are also expected to set the control loading the default + values, if the quantisation matrices need to be reset, for instance on a + sequence header. This process is specified by section 6.3.7. + "Quant matrix extension" of the specification. + +.. c:type:: v4l2_ctrl_mpeg2_quantisation + +.. tabularcolumns:: |p{0.8cm}|p{8.0cm}|p{8.5cm}| + +.. cssclass:: longtable + +.. raw:: latex + + \small + +.. flat-table:: struct v4l2_ctrl_mpeg2_quantisation + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u8 + - ``intra_quantiser_matrix[64]`` + - The quantisation matrix coefficients for intra-coded frames, in zigzag + scanning order. It is relevant for both luma and chroma components, + although it can be superseded by the chroma-specific matrix for + non-4:2:0 YUV formats. + * - __u8 + - ``non_intra_quantiser_matrix[64]`` + - The quantisation matrix coefficients for non-intra-coded frames, in + zigzag scanning order. It is relevant for both luma and chroma + components, although it can be superseded by the chroma-specific matrix + for non-4:2:0 YUV formats. + * - __u8 + - ``chroma_intra_quantiser_matrix[64]`` + - The quantisation matrix coefficients for the chominance component of + intra-coded frames, in zigzag scanning order. Only relevant for + non-4:2:0 YUV formats. + * - __u8 + - ``chroma_non_intra_quantiser_matrix[64]`` + - The quantisation matrix coefficients for the chrominance component of + non-intra-coded frames, in zigzag scanning order. Only relevant for + non-4:2:0 YUV formats. + +.. raw:: latex + + \normalsize diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index f10b04fba229..0b8061666c57 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -1606,222 +1606,6 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - ``V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L6_BR (integer)`` Indicates bit rate (bps) for hierarchical coding layer 6 for H264 encoder. -.. _v4l2-mpeg-mpeg2: - -``V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE (struct)`` - Specifies the sequence parameters (as extracted from the bitstream) for the - associated MPEG-2 slice data. This includes fields matching the syntax - elements from the sequence header and sequence extension parts of the - bitstream as specified by :ref:`mpeg2part2`. - - .. note:: - - This compound control is not yet part of the public kernel API and - it is expected to change. - -.. c:type:: v4l2_ctrl_mpeg2_sequence - -.. cssclass:: longtable - -.. tabularcolumns:: |p{1.4cm}|p{6.5cm}|p{9.4cm}| - -.. flat-table:: struct v4l2_ctrl_mpeg2_sequence - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __u16 - - ``horizontal_size`` - - The width of the displayable part of the frame's luminance component. - * - __u16 - - ``vertical_size`` - - The height of the displayable part of the frame's luminance component. - * - __u32 - - ``vbv_buffer_size`` - - Used to calculate the required size of the video buffering verifier, - defined (in bits) as: 16 * 1024 * vbv_buffer_size. - * - __u16 - - ``profile_and_level_indication`` - - The current profile and level indication as extracted from the - bitstream. - * - __u8 - - ``chroma_format`` - - The chrominance sub-sampling format (1: 4:2:0, 2: 4:2:2, 3: 4:4:4). - * - __u8 - - ``flags`` - - See :ref:`MPEG-2 Sequence Flags `. - -.. _mpeg2_sequence_flags: - -``MPEG-2 Sequence Flags`` - -.. cssclass:: longtable - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - ``V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE`` - - 0x01 - - Indication that all the frames for the sequence are progressive instead - of interlaced. - -``V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE (struct)`` - Specifies the picture parameters (as extracted from the bitstream) for the - associated MPEG-2 slice data. This includes fields matching the syntax - elements from the picture header and picture coding extension parts of the - bitstream as specified by :ref:`mpeg2part2`. - - .. note:: - - This compound control is not yet part of the public kernel API and - it is expected to change. - -.. c:type:: v4l2_ctrl_mpeg2_picture - -.. raw:: latex - - \small - -.. cssclass:: longtable - -.. tabularcolumns:: |p{1.0cm}|p{5.6cm}|p{10.7cm}| - -.. flat-table:: struct v4l2_ctrl_mpeg2_picture - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __u64 - - ``backward_ref_ts`` - - Timestamp of the V4L2 capture buffer to use as backward reference, used - with B-coded and P-coded frames. The timestamp refers to the - ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the - :c:func:`v4l2_timeval_to_ns()` function to convert the struct - :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64. - * - __u64 - - ``forward_ref_ts`` - - Timestamp for the V4L2 capture buffer to use as forward reference, used - with B-coded frames. The timestamp refers to the ``timestamp`` field in - struct :c:type:`v4l2_buffer`. Use the :c:func:`v4l2_timeval_to_ns()` - function to convert the struct :c:type:`timeval` in struct - :c:type:`v4l2_buffer` to a __u64. - * - __u32 - - ``flags`` - - See :ref:`MPEG-2 Picture Flags `. - * - __u8 - - ``f_code[2][2]`` - - Motion vector codes. - * - __u8 - - ``picture_coding_type`` - - Picture coding type for the frame covered by the current slice - (V4L2_MPEG2_PICTURE_CODING_TYPE_I, V4L2_MPEG2_PICTURE_CODING_TYPE_P or - V4L2_MPEG2_PICTURE_CODING_TYPE_B). - * - __u8 - - ``picture_structure`` - - Picture structure (1: interlaced top field, 2: interlaced bottom field, - 3: progressive frame). - * - __u8 - - ``intra_dc_precision`` - - Precision of Discrete Cosine transform (0: 8 bits precision, - 1: 9 bits precision, 2: 10 bits precision, 3: 11 bits precision). - * - __u8 - - ``reserved[5]`` - - Applications and drivers must set this to zero. - - -.. _mpeg2_picture_flags: - -``MPEG-2 Picture Flags`` - -.. cssclass:: longtable - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - ``V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST`` - - 0x00000001 - - If set and it's an interlaced stream, top field is output first. - * - ``V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT`` - - 0x00000002 - - If set only frame-DCT and frame prediction are used. - * - ``V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV`` - - 0x00000004 - - If set motion vectors are coded for intra macroblocks. - * - ``V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE`` - - 0x00000008 - - This flag affects the inverse quantization process. - * - ``V4L2_MPEG2_PIC_FLAG_INTRA_VLC`` - - 0x00000010 - - This flag affects the decoding of transform coefficient data. - * - ``V4L2_MPEG2_PIC_FLAG_ALT_SCAN`` - - 0x00000020 - - This flag affects the decoding of transform coefficient data. - * - ``V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST`` - - 0x00000040 - - This flag affects the decoding process of progressive frames. - * - ``V4L2_MPEG2_PIC_FLAG_PROGRESSIVE`` - - 0x00000080 - - Indicates whether the current frame is progressive. - -.. raw:: latex - - \normalsize - -``V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION (struct)`` - Specifies quantisation matrices (as extracted from the bitstream) for the - associated MPEG-2 slice data. - - .. note:: - - This compound control is not yet part of the public kernel API and - it is expected to change. - -.. c:type:: v4l2_ctrl_mpeg2_quantisation - -.. tabularcolumns:: |p{0.8cm}|p{8.0cm}|p{8.5cm}| - -.. cssclass:: longtable - -.. raw:: latex - - \small - -.. flat-table:: struct v4l2_ctrl_mpeg2_quantisation - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __u8 - - ``intra_quantiser_matrix[64]`` - - The quantisation matrix coefficients for intra-coded frames, in zigzag - scanning order. It is relevant for both luma and chroma components, - although it can be superseded by the chroma-specific matrix for - non-4:2:0 YUV formats. - * - __u8 - - ``non_intra_quantiser_matrix[64]`` - - The quantisation matrix coefficients for non-intra-coded frames, in - zigzag scanning order. It is relevant for both luma and chroma - components, although it can be superseded by the chroma-specific matrix - for non-4:2:0 YUV formats. - * - __u8 - - ``chroma_intra_quantiser_matrix[64]`` - - The quantisation matrix coefficients for the chominance component of - intra-coded frames, in zigzag scanning order. Only relevant for - non-4:2:0 YUV formats. - * - __u8 - - ``chroma_non_intra_quantiser_matrix[64]`` - - The quantisation matrix coefficients for the chrominance component of - non-intra-coded frames, in zigzag scanning order. Only relevant for - non-4:2:0 YUV formats. - -.. raw:: latex - - \normalsize - ``V4L2_CID_FWHT_I_FRAME_QP (integer)`` Quantization parameter for an I frame for FWHT. Valid range: from 1 to 31. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst index 6c10a062adac..0ede39907ee2 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst @@ -112,13 +112,13 @@ Compressed Formats - 'MG2S' - MPEG-2 parsed slice data, as extracted from the MPEG-2 bitstream. This format is adapted for stateless video decoders that implement a - MPEG-2 pipeline (using the :ref:`mem2mem` and :ref:`media-request-api`). + MPEG-2 pipeline with the :ref:`stateless_decoder`. Metadata associated with the frame to decode is required to be passed - through the ``V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE`` and - ``V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE`` controls. + through the ``V4L2_CID_STATELESS_MPEG2_SEQUENCE`` and + ``V4L2_CID_STATELESS_MPEG2_PICTURE`` controls. Quantisation matrices can optionally be specified through the - ``V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION`` control. - See the :ref:`associated Codec Control IDs `. + ``V4L2_CID_STATELESS_MPEG2_QUANTISATION`` control. + See the :ref:`associated Codec Control IDs `. Exactly one output and one capture buffer must be provided for use with this pixel format. The output buffer must contain the appropriate number of macroblocks to decode a full corresponding frame to the matching diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst index 3ba22983d21f..2d6bc8d94380 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst @@ -221,6 +221,18 @@ still cause this situation. - ``p_vp8_frame`` - A pointer to a struct :c:type:`v4l2_ctrl_vp8_frame`. Valid if this control is of type ``V4L2_CTRL_TYPE_VP8_FRAME``. + * - struct :c:type:`v4l2_ctrl_mpeg2_sequence` * + - ``p_mpeg2_sequence`` + - A pointer to a struct :c:type:`v4l2_ctrl_mpeg2_sequence`. Valid if this control is + of type ``V4L2_CTRL_TYPE_MPEG2_SEQUENCE``. + * - struct :c:type:`v4l2_ctrl_mpeg2_picture` * + - ``p_mpeg2_picture`` + - A pointer to a struct :c:type:`v4l2_ctrl_mpeg2_picture`. Valid if this control is + of type ``V4L2_CTRL_TYPE_MPEG2_PICTURE``. + * - struct :c:type:`v4l2_ctrl_mpeg2_quantisation` * + - ``p_mpeg2_quantisation`` + - A pointer to a struct :c:type:`v4l2_ctrl_mpeg2_quantisation`. Valid if this control is + of type ``V4L2_CTRL_TYPE_MPEG2_QUANTISATION``. * - struct :c:type:`v4l2_ctrl_hdr10_cll_info` * - ``p_hdr10_cll`` - A pointer to a struct :c:type:`v4l2_ctrl_hdr10_cll_info`. Valid if this control is diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index a693ff8dc3dc..d4e2c7318ee6 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -977,9 +977,6 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_LTR_COUNT: return "LTR Count"; case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX: return "Frame LTR Index"; case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES: return "Use LTR Frames"; - case V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE: return "MPEG-2 Sequence Header"; - case V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE: return "MPEG-2 Picture Header"; - case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION: return "MPEG-2 Quantisation Matrices"; case V4L2_CID_FWHT_I_FRAME_QP: return "FWHT I-Frame QP Value"; case V4L2_CID_FWHT_P_FRAME_QP: return "FWHT P-Frame QP Value"; @@ -1228,6 +1225,9 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_STATELESS_H264_DECODE_PARAMS: return "H264 Decode Parameters"; case V4L2_CID_STATELESS_FWHT_PARAMS: return "FWHT Stateless Parameters"; case V4L2_CID_STATELESS_VP8_FRAME: return "VP8 Frame Parameters"; + case V4L2_CID_STATELESS_MPEG2_SEQUENCE: return "MPEG-2 Sequence Header"; + case V4L2_CID_STATELESS_MPEG2_PICTURE: return "MPEG-2 Picture Header"; + case V4L2_CID_STATELESS_MPEG2_QUANTISATION: return "MPEG-2 Quantisation Matrices"; /* Colorimetry controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ @@ -1500,13 +1500,13 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_RDS_TX_ALT_FREQS: *type = V4L2_CTRL_TYPE_U32; break; - case V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE: + case V4L2_CID_STATELESS_MPEG2_SEQUENCE: *type = V4L2_CTRL_TYPE_MPEG2_SEQUENCE; break; - case V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE: + case V4L2_CID_STATELESS_MPEG2_PICTURE: *type = V4L2_CTRL_TYPE_MPEG2_PICTURE; break; - case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION: + case V4L2_CID_STATELESS_MPEG2_QUANTISATION: *type = V4L2_CTRL_TYPE_MPEG2_QUANTISATION; break; case V4L2_CID_STATELESS_FWHT_PARAMS: diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index dc9478ac7141..2f6b01c7a6a0 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -298,17 +298,17 @@ static const struct hantro_ctrl controls[] = { }, { .codec = HANTRO_MPEG2_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE, + .id = V4L2_CID_STATELESS_MPEG2_SEQUENCE, }, }, { .codec = HANTRO_MPEG2_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE, + .id = V4L2_CID_STATELESS_MPEG2_PICTURE, }, }, { .codec = HANTRO_MPEG2_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION, + .id = V4L2_CID_STATELESS_MPEG2_QUANTISATION, }, }, { .codec = HANTRO_VP8_DECODER, diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c index 25d912cbe2ff..6ee1a19d189b 100644 --- a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c @@ -83,7 +83,7 @@ hantro_g1_mpeg2_dec_set_quantisation(struct hantro_dev *vpu, { struct v4l2_ctrl_mpeg2_quantisation *q; - q = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION); + q = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_MPEG2_QUANTISATION); hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, q); vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, G1_REG_QTABLE_BASE); } @@ -160,9 +160,9 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) hantro_start_prepare_run(ctx); seq = hantro_get_ctrl(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE); + V4L2_CID_STATELESS_MPEG2_SEQUENCE); pic = hantro_get_ctrl(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE); + V4L2_CID_STATELESS_MPEG2_PICTURE); reg = G1_REG_DEC_AXI_RD_ID(0) | G1_REG_DEC_TIMEOUT_E(1) | diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c index d16d76760278..2527dce7eb18 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c @@ -85,7 +85,7 @@ rk3399_vpu_mpeg2_dec_set_quantisation(struct hantro_dev *vpu, { struct v4l2_ctrl_mpeg2_quantisation *q; - q = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION); + q = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_MPEG2_QUANTISATION); hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, q); vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, VDPU_REG_QTABLE_BASE); } @@ -162,9 +162,9 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) hantro_start_prepare_run(ctx); seq = hantro_get_ctrl(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE); + V4L2_CID_STATELESS_MPEG2_SEQUENCE); pic = hantro_get_ctrl(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE); + V4L2_CID_STATELESS_MPEG2_PICTURE); reg = VDPU_REG_DEC_ADV_PRE_DIS(0) | VDPU_REG_DEC_SCMD_DIS(0) | diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 4430c8fa2cc7..fa348c09f844 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -31,19 +31,19 @@ static const struct cedrus_control cedrus_controls[] = { { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE, + .id = V4L2_CID_STATELESS_MPEG2_SEQUENCE, }, .codec = CEDRUS_CODEC_MPEG2, }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE, + .id = V4L2_CID_STATELESS_MPEG2_PICTURE, }, .codec = CEDRUS_CODEC_MPEG2, }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION, + .id = V4L2_CID_STATELESS_MPEG2_QUANTISATION, }, .codec = CEDRUS_CODEC_MPEG2, }, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index e98185c1f5a7..97e410d92506 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -41,11 +41,11 @@ void cedrus_device_run(void *priv) switch (ctx->src_fmt.pixelformat) { case V4L2_PIX_FMT_MPEG2_SLICE: run.mpeg2.sequence = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE); + V4L2_CID_STATELESS_MPEG2_SEQUENCE); run.mpeg2.picture = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE); + V4L2_CID_STATELESS_MPEG2_PICTURE); run.mpeg2.quantisation = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION); + V4L2_CID_STATELESS_MPEG2_QUANTISATION); break; case V4L2_PIX_FMT_H264_SLICE: diff --git a/include/media/mpeg2-ctrls.h b/include/media/mpeg2-ctrls.h deleted file mode 100644 index a3d19de9e53a..000000000000 --- a/include/media/mpeg2-ctrls.h +++ /dev/null @@ -1,126 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * These are the MPEG2 state controls for use with stateless MPEG-2 - * codec drivers. - * - * It turns out that these structs are not stable yet and will undergo - * more changes. So keep them private until they are stable and ready to - * become part of the official public API. - */ - -#ifndef _MPEG2_CTRLS_H_ -#define _MPEG2_CTRLS_H_ - -#define V4L2_CID_MPEG_VIDEO_MPEG2_QUANTISATION (V4L2_CID_CODEC_BASE+251) -#define V4L2_CID_MPEG_VIDEO_MPEG2_SEQUENCE (V4L2_CID_CODEC_BASE+252) -#define V4L2_CID_MPEG_VIDEO_MPEG2_PICTURE (V4L2_CID_CODEC_BASE+253) - -/* enum v4l2_ctrl_type type values */ -#define V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE 0x01 - -/** - * struct v4l2_ctrl_mpeg2_sequence - MPEG-2 sequence header - * - * All the members on this structure match the sequence header and sequence - * extension syntaxes as specified by the MPEG-2 specification. - * - * Fields horizontal_size, vertical_size and vbv_buffer_size are a - * combination of respective _value and extension syntax elements, - * as described in section 6.3.3 "Sequence header". - * - * @horizontal_size: combination of elements horizontal_size_value and - * horizontal_size_extension. - * @vertical_size: combination of elements vertical_size_value and - * vertical_size_extension. - * @vbv_buffer_size: combination of elements vbv_buffer_size_value and - * vbv_buffer_size_extension. - * @profile_and_level_indication: see MPEG-2 specification. - * @chroma_format: see MPEG-2 specification. - * @flags: see V4L2_MPEG2_SEQ_FLAG_{}. - */ -struct v4l2_ctrl_mpeg2_sequence { - __u16 horizontal_size; - __u16 vertical_size; - __u32 vbv_buffer_size; - __u16 profile_and_level_indication; - __u8 chroma_format; - __u8 flags; -}; - -#define V4L2_MPEG2_PIC_CODING_TYPE_I 1 -#define V4L2_MPEG2_PIC_CODING_TYPE_P 2 -#define V4L2_MPEG2_PIC_CODING_TYPE_B 3 -#define V4L2_MPEG2_PIC_CODING_TYPE_D 4 - -#define V4L2_MPEG2_PIC_TOP_FIELD 0x1 -#define V4L2_MPEG2_PIC_BOTTOM_FIELD 0x2 -#define V4L2_MPEG2_PIC_FRAME 0x3 - -#define V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST 0x0001 -#define V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT 0x0002 -#define V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV 0x0004 -#define V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE 0x0008 -#define V4L2_MPEG2_PIC_FLAG_INTRA_VLC 0x0010 -#define V4L2_MPEG2_PIC_FLAG_ALT_SCAN 0x0020 -#define V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST 0x0040 -#define V4L2_MPEG2_PIC_FLAG_PROGRESSIVE 0x0080 - -/** - * struct v4l2_ctrl_mpeg2_picture - MPEG-2 picture header - * - * All the members on this structure match the picture header and picture - * coding extension syntaxes as specified by the MPEG-2 specification. - * - * @backward_ref_ts: timestamp of the V4L2 capture buffer to use as - * reference for backward prediction. - * @forward_ref_ts: timestamp of the V4L2 capture buffer to use as - * reference for forward prediction. These timestamp refers to the - * timestamp field in struct v4l2_buffer. Use v4l2_timeval_to_ns() - * to convert the struct timeval to a __u64. - * @flags: see V4L2_MPEG2_PIC_FLAG_{}. - * @f_code[2][2]: see MPEG-2 specification. - * @picture_coding_type: see MPEG-2 specification. - * @picture_structure: see V4L2_MPEG2_PIC_{}_FIELD. - * @intra_dc_precision: see MPEG-2 specification. - * @reserved: padding field. Should be zeroed by applications. - */ -struct v4l2_ctrl_mpeg2_picture { - __u64 backward_ref_ts; - __u64 forward_ref_ts; - __u32 flags; - __u8 f_code[2][2]; - __u8 picture_coding_type; - __u8 picture_structure; - __u8 intra_dc_precision; - __u8 reserved[5]; -}; - -/** - * struct v4l2_ctrl_mpeg2_quantisation - MPEG-2 quantisation - * - * Quantization matrices as specified by section 6.3.7 - * "Quant matrix extension". - * - * @intra_quantiser_matrix: The quantisation matrix coefficients - * for intra-coded frames, in zigzag scanning order. It is relevant - * for both luma and chroma components, although it can be superseded - * by the chroma-specific matrix for non-4:2:0 YUV formats. - * @non_intra_quantiser_matrix: The quantisation matrix coefficients - * for non-intra-coded frames, in zigzag scanning order. It is relevant - * for both luma and chroma components, although it can be superseded - * by the chroma-specific matrix for non-4:2:0 YUV formats. - * @chroma_intra_quantiser_matrix: The quantisation matrix coefficients - * for the chominance component of intra-coded frames, in zigzag scanning - * order. Only relevant for 4:2:2 and 4:4:4 YUV formats. - * @chroma_non_intra_quantiser_matrix: The quantisation matrix coefficients - * for the chrominance component of non-intra-coded frames, in zigzag scanning - * order. Only relevant for 4:2:2 and 4:4:4 YUV formats. - */ -struct v4l2_ctrl_mpeg2_quantisation { - __u8 intra_quantiser_matrix[64]; - __u8 non_intra_quantiser_matrix[64]; - __u8 chroma_intra_quantiser_matrix[64]; - __u8 chroma_non_intra_quantiser_matrix[64]; -}; - -#endif diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 215e44172c66..575b59fbac77 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -17,7 +17,6 @@ * Include the stateless codec compound control definitions. * This will move to the public headers once this API is fully stable. */ -#include #include /* forward references */ diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index d43bec5f1afd..f96bea19c991 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -1862,6 +1862,118 @@ struct v4l2_ctrl_vp8_frame { __u64 flags; }; +/* Stateless MPEG-2 controls */ + +#define V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE 0x01 + +#define V4L2_CID_STATELESS_MPEG2_SEQUENCE (V4L2_CID_CODEC_STATELESS_BASE+220) +/** + * struct v4l2_ctrl_mpeg2_sequence - MPEG-2 sequence header + * + * All the members on this structure match the sequence header and sequence + * extension syntaxes as specified by the MPEG-2 specification. + * + * Fields horizontal_size, vertical_size and vbv_buffer_size are a + * combination of respective _value and extension syntax elements, + * as described in section 6.3.3 "Sequence header". + * + * @horizontal_size: combination of elements horizontal_size_value and + * horizontal_size_extension. + * @vertical_size: combination of elements vertical_size_value and + * vertical_size_extension. + * @vbv_buffer_size: combination of elements vbv_buffer_size_value and + * vbv_buffer_size_extension. + * @profile_and_level_indication: see MPEG-2 specification. + * @chroma_format: see MPEG-2 specification. + * @flags: see V4L2_MPEG2_SEQ_FLAG_{}. + */ +struct v4l2_ctrl_mpeg2_sequence { + __u16 horizontal_size; + __u16 vertical_size; + __u32 vbv_buffer_size; + __u16 profile_and_level_indication; + __u8 chroma_format; + __u8 flags; +}; + +#define V4L2_MPEG2_PIC_CODING_TYPE_I 1 +#define V4L2_MPEG2_PIC_CODING_TYPE_P 2 +#define V4L2_MPEG2_PIC_CODING_TYPE_B 3 +#define V4L2_MPEG2_PIC_CODING_TYPE_D 4 + +#define V4L2_MPEG2_PIC_TOP_FIELD 0x1 +#define V4L2_MPEG2_PIC_BOTTOM_FIELD 0x2 +#define V4L2_MPEG2_PIC_FRAME 0x3 + +#define V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST 0x0001 +#define V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT 0x0002 +#define V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV 0x0004 +#define V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE 0x0008 +#define V4L2_MPEG2_PIC_FLAG_INTRA_VLC 0x0010 +#define V4L2_MPEG2_PIC_FLAG_ALT_SCAN 0x0020 +#define V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST 0x0040 +#define V4L2_MPEG2_PIC_FLAG_PROGRESSIVE 0x0080 + +#define V4L2_CID_STATELESS_MPEG2_PICTURE (V4L2_CID_CODEC_STATELESS_BASE+221) +/** + * struct v4l2_ctrl_mpeg2_picture - MPEG-2 picture header + * + * All the members on this structure match the picture header and picture + * coding extension syntaxes as specified by the MPEG-2 specification. + * + * @backward_ref_ts: timestamp of the V4L2 capture buffer to use as + * reference for backward prediction. + * @forward_ref_ts: timestamp of the V4L2 capture buffer to use as + * reference for forward prediction. These timestamp refers to the + * timestamp field in struct v4l2_buffer. Use v4l2_timeval_to_ns() + * to convert the struct timeval to a __u64. + * @flags: see V4L2_MPEG2_PIC_FLAG_{}. + * @f_code: see MPEG-2 specification. + * @picture_coding_type: see MPEG-2 specification. + * @picture_structure: see V4L2_MPEG2_PIC_{}_FIELD. + * @intra_dc_precision: see MPEG-2 specification. + * @reserved: padding field. Should be zeroed by applications. + */ +struct v4l2_ctrl_mpeg2_picture { + __u64 backward_ref_ts; + __u64 forward_ref_ts; + __u32 flags; + __u8 f_code[2][2]; + __u8 picture_coding_type; + __u8 picture_structure; + __u8 intra_dc_precision; + __u8 reserved[5]; +}; + +#define V4L2_CID_STATELESS_MPEG2_QUANTISATION (V4L2_CID_CODEC_STATELESS_BASE+222) +/** + * struct v4l2_ctrl_mpeg2_quantisation - MPEG-2 quantisation + * + * Quantisation matrices as specified by section 6.3.7 + * "Quant matrix extension". + * + * @intra_quantiser_matrix: The quantisation matrix coefficients + * for intra-coded frames, in zigzag scanning order. It is relevant + * for both luma and chroma components, although it can be superseded + * by the chroma-specific matrix for non-4:2:0 YUV formats. + * @non_intra_quantiser_matrix: The quantisation matrix coefficients + * for non-intra-coded frames, in zigzag scanning order. It is relevant + * for both luma and chroma components, although it can be superseded + * by the chroma-specific matrix for non-4:2:0 YUV formats. + * @chroma_intra_quantiser_matrix: The quantisation matrix coefficients + * for the chominance component of intra-coded frames, in zigzag scanning + * order. Only relevant for 4:2:2 and 4:4:4 YUV formats. + * @chroma_non_intra_quantiser_matrix: The quantisation matrix coefficients + * for the chrominance component of non-intra-coded frames, in zigzag scanning + * order. Only relevant for 4:2:2 and 4:4:4 YUV formats. + */ +struct v4l2_ctrl_mpeg2_quantisation { + __u8 intra_quantiser_matrix[64]; + __u8 non_intra_quantiser_matrix[64]; + __u8 chroma_intra_quantiser_matrix[64]; + __u8 chroma_non_intra_quantiser_matrix[64]; +}; + #define V4L2_CID_COLORIMETRY_CLASS_BASE (V4L2_CTRL_CLASS_COLORIMETRY | 0x900) #define V4L2_CID_COLORIMETRY_CLASS (V4L2_CTRL_CLASS_COLORIMETRY | 1) diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index d3bb18a3a51b..9260791b8438 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1747,6 +1747,9 @@ struct v4l2_ext_control { struct v4l2_ctrl_h264_decode_params __user *p_h264_decode_params; struct v4l2_ctrl_fwht_params __user *p_fwht_params; struct v4l2_ctrl_vp8_frame __user *p_vp8_frame; + struct v4l2_ctrl_mpeg2_sequence __user *p_mpeg2_sequence; + struct v4l2_ctrl_mpeg2_picture __user *p_mpeg2_picture; + struct v4l2_ctrl_mpeg2_quantisation __user *p_mpeg2_quantisation; void __user *ptr; }; } __attribute__ ((packed)); -- cgit v1.3.1 From 85b62ff2cb971c53a9a0cfafd31b07a92bb0fa19 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 18 Apr 2021 22:15:56 +0200 Subject: media: dt-bindings: media: nxp,imx7-mipi-csi2: Add i.MX8MM support The i.MX8MM integrates a newer version of the CSIS CSI-2 receiver as the i.MX7 family. Differences in integration are are: - An additional clock is required - Up to 4 data lanes are supported - No reset or PHY supply is present Support it in the DT binding. Signed-off-by: Laurent Pinchart Acked-by: Rui Miguel Silva Reviewed-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/nxp,imx7-mipi-csi2.yaml | 109 ++++++++++++++++++--- 1 file changed, 95 insertions(+), 14 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml b/Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml index d8ed480482b9..7c09eec78ce5 100644 --- a/Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml +++ b/Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml @@ -4,15 +4,17 @@ $id: http://devicetree.org/schemas/media/nxp,imx7-mipi-csi2.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: NXP i.MX7 MIPI CSI-2 receiver +title: NXP i.MX7 and i.MX8 MIPI CSI-2 receiver maintainers: - Rui Miguel Silva + - Laurent Pinchart description: |- - The NXP i.MX7 SoC family includes a MIPI CSI-2 receiver IP core, documented - as "CSIS V3.3". The IP core seems to originate from Samsung, and may be - compatible with some of the Exynos4 ad S5P SoCs. + The NXP i.MX7 and i.MX8 families contain SoCs that include a MIPI CSI-2 + receiver IP core named CSIS. The IP core originates from Samsung, and may be + compatible with some of the Exynos4 and S5P SoCs. i.MX7 SoCs use CSIS version + 3.3, and i.MX8 SoCs use CSIS version 3.6.3. While the CSI-2 receiver is separate from the MIPI D-PHY IP core, the PHY is completely wrapped by the CSIS and doesn't expose a control interface of its @@ -20,7 +22,9 @@ description: |- properties: compatible: - const: fsl,imx7-mipi-csi2 + enum: + - fsl,imx7-mipi-csi2 + - fsl,imx8mm-mipi-csi2 reg: maxItems: 1 @@ -29,16 +33,20 @@ properties: maxItems: 1 clocks: + minItems: 3 items: - description: The peripheral clock (a.k.a. APB clock) - description: The external clock (optionally used as the pixel clock) - description: The MIPI D-PHY clock + - description: The AXI clock clock-names: + minItems: 3 items: - const: pclk - const: wrap - const: phy + - const: axi power-domains: maxItems: 1 @@ -71,16 +79,30 @@ properties: properties: data-lanes: - oneOf: - - items: - - const: 1 - - items: - - const: 1 - - const: 2 + items: + minItems: 1 + maxItems: 4 + items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 required: - data-lanes + allOf: + - if: + properties: + compatible: + contains: + const: fsl,imx7-mipi-csi2 + then: + properties: + data-lanes: + items: + maxItems: 2 + port@1: $ref: /schemas/graph.yaml#/properties/port description: @@ -93,12 +115,29 @@ required: - clocks - clock-names - power-domains - - phy-supply - - resets - ports additionalProperties: false +allOf: + - if: + properties: + compatible: + contains: + const: fsl,imx7-mipi-csi2 + then: + required: + - phy-supply + - resets + else: + properties: + clocks: + minItems: 4 + clock-names: + minItems: 4 + phy-supply: false + resets: false + examples: - | #include @@ -106,7 +145,7 @@ examples: #include #include - mipi_csi: mipi-csi@30750000 { + mipi-csi@30750000 { compatible = "fsl,imx7-mipi-csi2"; reg = <0x30750000 0x10000>; interrupts = ; @@ -144,4 +183,46 @@ examples: }; }; + - | + #include + #include + #include + + mipi-csi@32e30000 { + compatible = "fsl,imx8mm-mipi-csi2"; + reg = <0x32e30000 0x1000>; + interrupts = ; + clock-frequency = <333000000>; + clocks = <&clk IMX8MM_CLK_DISP_APB_ROOT>, + <&clk IMX8MM_CLK_CSI1_ROOT>, + <&clk IMX8MM_CLK_CSI1_PHY_REF>, + <&clk IMX8MM_CLK_DISP_AXI_ROOT>; + clock-names = "pclk", "wrap", "phy", "axi"; + power-domains = <&mipi_pd>; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + imx8mm_mipi_csi_in: endpoint { + remote-endpoint = <&imx477_out>; + data-lanes = <1 2 3 4>; + }; + }; + + port@1 { + reg = <1>; + + imx8mm_mipi_csi_out: endpoint { + remote-endpoint = <&csi_in>; + }; + }; + }; + }; + ... -- cgit v1.3.1 From 71c689dc2e732d4cb190aaf0edea73116b1611bd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 27 Apr 2021 14:07:03 +0200 Subject: media: v4l2-ctrls: split up into four source files The v4l2-ctrls.c source has become much too big, so split it up into four separate parts: v4l2-ctrls-core.c: contains the core framework code v4l2-ctrls-api.c: contains the uAPI interface to the framework v4l2-ctrls-defs.c: contains the control definitions v4l2-ctrls-request.c: contains the Request API helpers And it adds a new v4l2-ctrls-priv.h. No code was changed, but a number of checkpatch.pl warnings were fixed (alignment, f == NULL -> !f, long comment block coding style, unsigned -> unsigned int). The copyright statements were updated as well since they were quite out of date. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/v4l/ext-ctrls-codec-stateless.rst | 4 +- drivers/media/v4l2-core/Makefile | 5 +- drivers/media/v4l2-core/v4l2-ctrls-api.c | 1225 +++++ drivers/media/v4l2-core/v4l2-ctrls-core.c | 1939 ++++++++ drivers/media/v4l2-core/v4l2-ctrls-defs.c | 1575 ++++++ drivers/media/v4l2-core/v4l2-ctrls-priv.h | 96 + drivers/media/v4l2-core/v4l2-ctrls-request.c | 496 ++ drivers/media/v4l2-core/v4l2-ctrls.c | 5111 -------------------- 8 files changed, 5336 insertions(+), 5115 deletions(-) create mode 100644 drivers/media/v4l2-core/v4l2-ctrls-api.c create mode 100644 drivers/media/v4l2-core/v4l2-ctrls-core.c create mode 100644 drivers/media/v4l2-core/v4l2-ctrls-defs.c create mode 100644 drivers/media/v4l2-core/v4l2-ctrls-priv.h create mode 100644 drivers/media/v4l2-core/v4l2-ctrls-request.c delete mode 100644 drivers/media/v4l2-core/v4l2-ctrls.c (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst index 2aa508ffb6b9..72f5e85b4f34 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst @@ -1353,8 +1353,8 @@ FWHT Flags * - __u8 - ``picture_coding_type`` - Picture coding type for the frame covered by the current slice - (V4L2_MPEG2_PICTURE_CODING_TYPE_I, V4L2_MPEG2_PICTURE_CODING_TYPE_P or - V4L2_MPEG2_PICTURE_CODING_TYPE_B). + (V4L2_MPEG2_PIC_CODING_TYPE_I, V4L2_MPEG2_PIC_CODING_TYPE_P or + V4L2_MPEG2_PIC_CODING_TYPE_B). * - __u8 - ``picture_structure`` - Picture structure (1: interlaced top field, 2: interlaced bottom field, diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index e4cd589b99a5..ad967b72fb5d 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -6,8 +6,9 @@ tuner-objs := tuner-core.o videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ - v4l2-event.o v4l2-ctrls.o v4l2-subdev.o \ - v4l2-async.o v4l2-common.o + v4l2-event.o v4l2-subdev.o v4l2-async.o v4l2-common.o \ + v4l2-ctrls-core.o v4l2-ctrls-api.o \ + v4l2-ctrls-request.o v4l2-ctrls-defs.o videodev-$(CONFIG_COMPAT) += v4l2-compat-ioctl32.o videodev-$(CONFIG_TRACEPOINTS) += v4l2-trace.o videodev-$(CONFIG_MEDIA_CONTROLLER) += v4l2-mc.o diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c new file mode 100644 index 000000000000..db9baa0bd05f --- /dev/null +++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c @@ -0,0 +1,1225 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * V4L2 controls framework uAPI implementation: + * + * Copyright (C) 2010-2021 Hans Verkuil + */ + +#define pr_fmt(fmt) "v4l2-ctrls: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "v4l2-ctrls-priv.h" + +/* Internal temporary helper struct, one for each v4l2_ext_control */ +struct v4l2_ctrl_helper { + /* Pointer to the control reference of the master control */ + struct v4l2_ctrl_ref *mref; + /* The control ref corresponding to the v4l2_ext_control ID field. */ + struct v4l2_ctrl_ref *ref; + /* + * v4l2_ext_control index of the next control belonging to the + * same cluster, or 0 if there isn't any. + */ + u32 next; +}; + +/* + * Helper functions to copy control payload data from kernel space to + * user space and vice versa. + */ + +/* Helper function: copy the given control value back to the caller */ +static int ptr_to_user(struct v4l2_ext_control *c, + struct v4l2_ctrl *ctrl, + union v4l2_ctrl_ptr ptr) +{ + u32 len; + + if (ctrl->is_ptr && !ctrl->is_string) + return copy_to_user(c->ptr, ptr.p_const, c->size) ? + -EFAULT : 0; + + switch (ctrl->type) { + case V4L2_CTRL_TYPE_STRING: + len = strlen(ptr.p_char); + if (c->size < len + 1) { + c->size = ctrl->elem_size; + return -ENOSPC; + } + return copy_to_user(c->string, ptr.p_char, len + 1) ? + -EFAULT : 0; + case V4L2_CTRL_TYPE_INTEGER64: + c->value64 = *ptr.p_s64; + break; + default: + c->value = *ptr.p_s32; + break; + } + return 0; +} + +/* Helper function: copy the current control value back to the caller */ +static int cur_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl) +{ + return ptr_to_user(c, ctrl, ctrl->p_cur); +} + +/* Helper function: copy the new control value back to the caller */ +static int new_to_user(struct v4l2_ext_control *c, + struct v4l2_ctrl *ctrl) +{ + return ptr_to_user(c, ctrl, ctrl->p_new); +} + +/* Helper function: copy the request value back to the caller */ +static int req_to_user(struct v4l2_ext_control *c, + struct v4l2_ctrl_ref *ref) +{ + return ptr_to_user(c, ref->ctrl, ref->p_req); +} + +/* Helper function: copy the initial control value back to the caller */ +static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl) +{ + int idx; + + for (idx = 0; idx < ctrl->elems; idx++) + ctrl->type_ops->init(ctrl, idx, ctrl->p_new); + + return ptr_to_user(c, ctrl, ctrl->p_new); +} + +/* Helper function: copy the caller-provider value to the given control value */ +static int user_to_ptr(struct v4l2_ext_control *c, + struct v4l2_ctrl *ctrl, + union v4l2_ctrl_ptr ptr) +{ + int ret; + u32 size; + + ctrl->is_new = 1; + if (ctrl->is_ptr && !ctrl->is_string) { + unsigned int idx; + + ret = copy_from_user(ptr.p, c->ptr, c->size) ? -EFAULT : 0; + if (ret || !ctrl->is_array) + return ret; + for (idx = c->size / ctrl->elem_size; idx < ctrl->elems; idx++) + ctrl->type_ops->init(ctrl, idx, ptr); + return 0; + } + + switch (ctrl->type) { + case V4L2_CTRL_TYPE_INTEGER64: + *ptr.p_s64 = c->value64; + break; + case V4L2_CTRL_TYPE_STRING: + size = c->size; + if (size == 0) + return -ERANGE; + if (size > ctrl->maximum + 1) + size = ctrl->maximum + 1; + ret = copy_from_user(ptr.p_char, c->string, size) ? -EFAULT : 0; + if (!ret) { + char last = ptr.p_char[size - 1]; + + ptr.p_char[size - 1] = 0; + /* + * If the string was longer than ctrl->maximum, + * then return an error. + */ + if (strlen(ptr.p_char) == ctrl->maximum && last) + return -ERANGE; + } + return ret; + default: + *ptr.p_s32 = c->value; + break; + } + return 0; +} + +/* Helper function: copy the caller-provider value as the new control value */ +static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl) +{ + return user_to_ptr(c, ctrl, ctrl->p_new); +} + +/* + * VIDIOC_G/TRY/S_EXT_CTRLS implementation + */ + +/* + * Some general notes on the atomic requirements of VIDIOC_G/TRY/S_EXT_CTRLS: + * + * It is not a fully atomic operation, just best-effort only. After all, if + * multiple controls have to be set through multiple i2c writes (for example) + * then some initial writes may succeed while others fail. Thus leaving the + * system in an inconsistent state. The question is how much effort you are + * willing to spend on trying to make something atomic that really isn't. + * + * From the point of view of an application the main requirement is that + * when you call VIDIOC_S_EXT_CTRLS and some values are invalid then an + * error should be returned without actually affecting any controls. + * + * If all the values are correct, then it is acceptable to just give up + * in case of low-level errors. + * + * It is important though that the application can tell when only a partial + * configuration was done. The way we do that is through the error_idx field + * of struct v4l2_ext_controls: if that is equal to the count field then no + * controls were affected. Otherwise all controls before that index were + * successful in performing their 'get' or 'set' operation, the control at + * the given index failed, and you don't know what happened with the controls + * after the failed one. Since if they were part of a control cluster they + * could have been successfully processed (if a cluster member was encountered + * at index < error_idx), they could have failed (if a cluster member was at + * error_idx), or they may not have been processed yet (if the first cluster + * member appeared after error_idx). + * + * It is all fairly theoretical, though. In practice all you can do is to + * bail out. If error_idx == count, then it is an application bug. If + * error_idx < count then it is only an application bug if the error code was + * EBUSY. That usually means that something started streaming just when you + * tried to set the controls. In all other cases it is a driver/hardware + * problem and all you can do is to retry or bail out. + * + * Note that these rules do not apply to VIDIOC_TRY_EXT_CTRLS: since that + * never modifies controls the error_idx is just set to whatever control + * has an invalid value. + */ + +/* + * Prepare for the extended g/s/try functions. + * Find the controls in the control array and do some basic checks. + */ +static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl, + struct v4l2_ext_controls *cs, + struct v4l2_ctrl_helper *helpers, + struct video_device *vdev, + bool get) +{ + struct v4l2_ctrl_helper *h; + bool have_clusters = false; + u32 i; + + for (i = 0, h = helpers; i < cs->count; i++, h++) { + struct v4l2_ext_control *c = &cs->controls[i]; + struct v4l2_ctrl_ref *ref; + struct v4l2_ctrl *ctrl; + u32 id = c->id & V4L2_CTRL_ID_MASK; + + cs->error_idx = i; + + if (cs->which && + cs->which != V4L2_CTRL_WHICH_DEF_VAL && + cs->which != V4L2_CTRL_WHICH_REQUEST_VAL && + V4L2_CTRL_ID2WHICH(id) != cs->which) { + dprintk(vdev, + "invalid which 0x%x or control id 0x%x\n", + cs->which, id); + return -EINVAL; + } + + /* + * Old-style private controls are not allowed for + * extended controls. + */ + if (id >= V4L2_CID_PRIVATE_BASE) { + dprintk(vdev, + "old-style private controls not allowed\n"); + return -EINVAL; + } + ref = find_ref_lock(hdl, id); + if (!ref) { + dprintk(vdev, "cannot find control id 0x%x\n", id); + return -EINVAL; + } + h->ref = ref; + ctrl = ref->ctrl; + if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED) { + dprintk(vdev, "control id 0x%x is disabled\n", id); + return -EINVAL; + } + + if (ctrl->cluster[0]->ncontrols > 1) + have_clusters = true; + if (ctrl->cluster[0] != ctrl) + ref = find_ref_lock(hdl, ctrl->cluster[0]->id); + if (ctrl->is_ptr && !ctrl->is_string) { + unsigned int tot_size = ctrl->elems * ctrl->elem_size; + + if (c->size < tot_size) { + /* + * In the get case the application first + * queries to obtain the size of the control. + */ + if (get) { + c->size = tot_size; + return -ENOSPC; + } + dprintk(vdev, + "pointer control id 0x%x size too small, %d bytes but %d bytes needed\n", + id, c->size, tot_size); + return -EFAULT; + } + c->size = tot_size; + } + /* Store the ref to the master control of the cluster */ + h->mref = ref; + /* + * Initially set next to 0, meaning that there is no other + * control in this helper array belonging to the same + * cluster. + */ + h->next = 0; + } + + /* + * We are done if there were no controls that belong to a multi- + * control cluster. + */ + if (!have_clusters) + return 0; + + /* + * The code below figures out in O(n) time which controls in the list + * belong to the same cluster. + */ + + /* This has to be done with the handler lock taken. */ + mutex_lock(hdl->lock); + + /* First zero the helper field in the master control references */ + for (i = 0; i < cs->count; i++) + helpers[i].mref->helper = NULL; + for (i = 0, h = helpers; i < cs->count; i++, h++) { + struct v4l2_ctrl_ref *mref = h->mref; + + /* + * If the mref->helper is set, then it points to an earlier + * helper that belongs to the same cluster. + */ + if (mref->helper) { + /* + * Set the next field of mref->helper to the current + * index: this means that the earlier helper now + * points to the next helper in the same cluster. + */ + mref->helper->next = i; + /* + * mref should be set only for the first helper in the + * cluster, clear the others. + */ + h->mref = NULL; + } + /* Point the mref helper to the current helper struct. */ + mref->helper = h; + } + mutex_unlock(hdl->lock); + return 0; +} + +/* + * Handles the corner case where cs->count == 0. It checks whether the + * specified control class exists. If that class ID is 0, then it checks + * whether there are any controls at all. + */ +static int class_check(struct v4l2_ctrl_handler *hdl, u32 which) +{ + if (which == 0 || which == V4L2_CTRL_WHICH_DEF_VAL || + which == V4L2_CTRL_WHICH_REQUEST_VAL) + return 0; + return find_ref_lock(hdl, which | 1) ? 0 : -EINVAL; +} + +/* + * Get extended controls. Allocates the helpers array if needed. + * + * Note that v4l2_g_ext_ctrls_common() with 'which' set to + * V4L2_CTRL_WHICH_REQUEST_VAL is only called if the request was + * completed, and in that case valid_p_req is true for all controls. + */ +int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl, + struct v4l2_ext_controls *cs, + struct video_device *vdev) +{ + struct v4l2_ctrl_helper helper[4]; + struct v4l2_ctrl_helper *helpers = helper; + int ret; + int i, j; + bool is_default, is_request; + + is_default = (cs->which == V4L2_CTRL_WHICH_DEF_VAL); + is_request = (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL); + + cs->error_idx = cs->count; + cs->which = V4L2_CTRL_ID2WHICH(cs->which); + + if (!hdl) + return -EINVAL; + + if (cs->count == 0) + return class_check(hdl, cs->which); + + if (cs->count > ARRAY_SIZE(helper)) { + helpers = kvmalloc_array(cs->count, sizeof(helper[0]), + GFP_KERNEL); + if (!helpers) + return -ENOMEM; + } + + ret = prepare_ext_ctrls(hdl, cs, helpers, vdev, true); + cs->error_idx = cs->count; + + for (i = 0; !ret && i < cs->count; i++) + if (helpers[i].ref->ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY) + ret = -EACCES; + + for (i = 0; !ret && i < cs->count; i++) { + struct v4l2_ctrl *master; + bool is_volatile = false; + u32 idx = i; + + if (!helpers[i].mref) + continue; + + master = helpers[i].mref->ctrl; + cs->error_idx = i; + + v4l2_ctrl_lock(master); + + /* + * g_volatile_ctrl will update the new control values. + * This makes no sense for V4L2_CTRL_WHICH_DEF_VAL and + * V4L2_CTRL_WHICH_REQUEST_VAL. In the case of requests + * it is v4l2_ctrl_request_complete() that copies the + * volatile controls at the time of request completion + * to the request, so you don't want to do that again. + */ + if (!is_default && !is_request && + ((master->flags & V4L2_CTRL_FLAG_VOLATILE) || + (master->has_volatiles && !is_cur_manual(master)))) { + for (j = 0; j < master->ncontrols; j++) + cur_to_new(master->cluster[j]); + ret = call_op(master, g_volatile_ctrl); + is_volatile = true; + } + + if (ret) { + v4l2_ctrl_unlock(master); + break; + } + + /* + * Copy the default value (if is_default is true), the + * request value (if is_request is true and p_req is valid), + * the new volatile value (if is_volatile is true) or the + * current value. + */ + do { + struct v4l2_ctrl_ref *ref = helpers[idx].ref; + + if (is_default) + ret = def_to_user(cs->controls + idx, ref->ctrl); + else if (is_request && ref->valid_p_req) + ret = req_to_user(cs->controls + idx, ref); + else if (is_volatile) + ret = new_to_user(cs->controls + idx, ref->ctrl); + else + ret = cur_to_user(cs->controls + idx, ref->ctrl); + idx = helpers[idx].next; + } while (!ret && idx); + + v4l2_ctrl_unlock(master); + } + + if (cs->count > ARRAY_SIZE(helper)) + kvfree(helpers); + return ret; +} + +int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct video_device *vdev, + struct media_device *mdev, struct v4l2_ext_controls *cs) +{ + if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL) + return v4l2_g_ext_ctrls_request(hdl, vdev, mdev, cs); + + return v4l2_g_ext_ctrls_common(hdl, cs, vdev); +} +EXPORT_SYMBOL(v4l2_g_ext_ctrls); + +/* Validate controls. */ +static int validate_ctrls(struct v4l2_ext_controls *cs, + struct v4l2_ctrl_helper *helpers, + struct video_device *vdev, + bool set) +{ + unsigned int i; + int ret = 0; + + cs->error_idx = cs->count; + for (i = 0; i < cs->count; i++) { + struct v4l2_ctrl *ctrl = helpers[i].ref->ctrl; + union v4l2_ctrl_ptr p_new; + + cs->error_idx = i; + + if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) { + dprintk(vdev, + "control id 0x%x is read-only\n", + ctrl->id); + return -EACCES; + } + /* + * This test is also done in try_set_control_cluster() which + * is called in atomic context, so that has the final say, + * but it makes sense to do an up-front check as well. Once + * an error occurs in try_set_control_cluster() some other + * controls may have been set already and we want to do a + * best-effort to avoid that. + */ + if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) { + dprintk(vdev, + "control id 0x%x is grabbed, cannot set\n", + ctrl->id); + return -EBUSY; + } + /* + * Skip validation for now if the payload needs to be copied + * from userspace into kernelspace. We'll validate those later. + */ + if (ctrl->is_ptr) + continue; + if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) + p_new.p_s64 = &cs->controls[i].value64; + else + p_new.p_s32 = &cs->controls[i].value; + ret = validate_new(ctrl, p_new); + if (ret) + return ret; + } + return 0; +} + +/* Try or try-and-set controls */ +int try_set_ext_ctrls_common(struct v4l2_fh *fh, + struct v4l2_ctrl_handler *hdl, + struct v4l2_ext_controls *cs, + struct video_device *vdev, bool set) +{ + struct v4l2_ctrl_helper helper[4]; + struct v4l2_ctrl_helper *helpers = helper; + unsigned int i, j; + int ret; + + cs->error_idx = cs->count; + + /* Default value cannot be changed */ + if (cs->which == V4L2_CTRL_WHICH_DEF_VAL) { + dprintk(vdev, "%s: cannot change default value\n", + video_device_node_name(vdev)); + return -EINVAL; + } + + cs->which = V4L2_CTRL_ID2WHICH(cs->which); + + if (!hdl) { + dprintk(vdev, "%s: invalid null control handler\n", + video_device_node_name(vdev)); + return -EINVAL; + } + + if (cs->count == 0) + return class_check(hdl, cs->which); + + if (cs->count > ARRAY_SIZE(helper)) { + helpers = kvmalloc_array(cs->count, sizeof(helper[0]), + GFP_KERNEL); + if (!helpers) + return -ENOMEM; + } + ret = prepare_ext_ctrls(hdl, cs, helpers, vdev, false); + if (!ret) + ret = validate_ctrls(cs, helpers, vdev, set); + if (ret && set) + cs->error_idx = cs->count; + for (i = 0; !ret && i < cs->count; i++) { + struct v4l2_ctrl *master; + u32 idx = i; + + if (!helpers[i].mref) + continue; + + cs->error_idx = i; + master = helpers[i].mref->ctrl; + v4l2_ctrl_lock(master); + + /* Reset the 'is_new' flags of the cluster */ + for (j = 0; j < master->ncontrols; j++) + if (master->cluster[j]) + master->cluster[j]->is_new = 0; + + /* + * For volatile autoclusters that are currently in auto mode + * we need to discover if it will be set to manual mode. + * If so, then we have to copy the current volatile values + * first since those will become the new manual values (which + * may be overwritten by explicit new values from this set + * of controls). + */ + if (master->is_auto && master->has_volatiles && + !is_cur_manual(master)) { + /* Pick an initial non-manual value */ + s32 new_auto_val = master->manual_mode_value + 1; + u32 tmp_idx = idx; + + do { + /* + * Check if the auto control is part of the + * list, and remember the new value. + */ + if (helpers[tmp_idx].ref->ctrl == master) + new_auto_val = cs->controls[tmp_idx].value; + tmp_idx = helpers[tmp_idx].next; + } while (tmp_idx); + /* + * If the new value == the manual value, then copy + * the current volatile values. + */ + if (new_auto_val == master->manual_mode_value) + update_from_auto_cluster(master); + } + + /* + * Copy the new caller-supplied control values. + * user_to_new() sets 'is_new' to 1. + */ + do { + struct v4l2_ctrl *ctrl = helpers[idx].ref->ctrl; + + ret = user_to_new(cs->controls + idx, ctrl); + if (!ret && ctrl->is_ptr) { + ret = validate_new(ctrl, ctrl->p_new); + if (ret) + dprintk(vdev, + "failed to validate control %s (%d)\n", + v4l2_ctrl_get_name(ctrl->id), ret); + } + idx = helpers[idx].next; + } while (!ret && idx); + + if (!ret) + ret = try_or_set_cluster(fh, master, + !hdl->req_obj.req && set, 0); + if (!ret && hdl->req_obj.req && set) { + for (j = 0; j < master->ncontrols; j++) { + struct v4l2_ctrl_ref *ref = + find_ref(hdl, master->cluster[j]->id); + + new_to_req(ref); + } + } + + /* Copy the new values back to userspace. */ + if (!ret) { + idx = i; + do { + ret = new_to_user(cs->controls + idx, + helpers[idx].ref->ctrl); + idx = helpers[idx].next; + } while (!ret && idx); + } + v4l2_ctrl_unlock(master); + } + + if (cs->count > ARRAY_SIZE(helper)) + kvfree(helpers); + return ret; +} + +static int try_set_ext_ctrls(struct v4l2_fh *fh, + struct v4l2_ctrl_handler *hdl, + struct video_device *vdev, + struct media_device *mdev, + struct v4l2_ext_controls *cs, bool set) +{ + int ret; + + if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL) + return try_set_ext_ctrls_request(fh, hdl, vdev, mdev, cs, set); + + ret = try_set_ext_ctrls_common(fh, hdl, cs, vdev, set); + if (ret) + dprintk(vdev, + "%s: try_set_ext_ctrls_common failed (%d)\n", + video_device_node_name(vdev), ret); + + return ret; +} + +int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, + struct video_device *vdev, + struct media_device *mdev, + struct v4l2_ext_controls *cs) +{ + return try_set_ext_ctrls(NULL, hdl, vdev, mdev, cs, false); +} +EXPORT_SYMBOL(v4l2_try_ext_ctrls); + +int v4l2_s_ext_ctrls(struct v4l2_fh *fh, + struct v4l2_ctrl_handler *hdl, + struct video_device *vdev, + struct media_device *mdev, + struct v4l2_ext_controls *cs) +{ + return try_set_ext_ctrls(fh, hdl, vdev, mdev, cs, true); +} +EXPORT_SYMBOL(v4l2_s_ext_ctrls); + +/* + * VIDIOC_G/S_CTRL implementation + */ + +/* Helper function to get a single control */ +static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c) +{ + struct v4l2_ctrl *master = ctrl->cluster[0]; + int ret = 0; + int i; + + /* Compound controls are not supported. The new_to_user() and + * cur_to_user() calls below would need to be modified not to access + * userspace memory when called from get_ctrl(). + */ + if (!ctrl->is_int && ctrl->type != V4L2_CTRL_TYPE_INTEGER64) + return -EINVAL; + + if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY) + return -EACCES; + + v4l2_ctrl_lock(master); + /* g_volatile_ctrl will update the current control values */ + if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) { + for (i = 0; i < master->ncontrols; i++) + cur_to_new(master->cluster[i]); + ret = call_op(master, g_volatile_ctrl); + new_to_user(c, ctrl); + } else { + cur_to_user(c, ctrl); + } + v4l2_ctrl_unlock(master); + return ret; +} + +int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control) +{ + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id); + struct v4l2_ext_control c; + int ret; + + if (!ctrl || !ctrl->is_int) + return -EINVAL; + ret = get_ctrl(ctrl, &c); + control->value = c.value; + return ret; +} +EXPORT_SYMBOL(v4l2_g_ctrl); + +/* Helper function for VIDIOC_S_CTRL compatibility */ +static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags) +{ + struct v4l2_ctrl *master = ctrl->cluster[0]; + int ret; + int i; + + /* Reset the 'is_new' flags of the cluster */ + for (i = 0; i < master->ncontrols; i++) + if (master->cluster[i]) + master->cluster[i]->is_new = 0; + + ret = validate_new(ctrl, ctrl->p_new); + if (ret) + return ret; + + /* + * For autoclusters with volatiles that are switched from auto to + * manual mode we have to update the current volatile values since + * those will become the initial manual values after such a switch. + */ + if (master->is_auto && master->has_volatiles && ctrl == master && + !is_cur_manual(master) && ctrl->val == master->manual_mode_value) + update_from_auto_cluster(master); + + ctrl->is_new = 1; + return try_or_set_cluster(fh, master, true, ch_flags); +} + +/* Helper function for VIDIOC_S_CTRL compatibility */ +static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, + struct v4l2_ext_control *c) +{ + int ret; + + v4l2_ctrl_lock(ctrl); + user_to_new(c, ctrl); + ret = set_ctrl(fh, ctrl, 0); + if (!ret) + cur_to_user(c, ctrl); + v4l2_ctrl_unlock(ctrl); + return ret; +} + +int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, + struct v4l2_control *control) +{ + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id); + struct v4l2_ext_control c = { control->id }; + int ret; + + if (!ctrl || !ctrl->is_int) + return -EINVAL; + + if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) + return -EACCES; + + c.value = control->value; + ret = set_ctrl_lock(fh, ctrl, &c); + control->value = c.value; + return ret; +} +EXPORT_SYMBOL(v4l2_s_ctrl); + +/* + * Helper functions for drivers to get/set controls. + */ + +s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_ext_control c; + + /* It's a driver bug if this happens. */ + if (WARN_ON(!ctrl->is_int)) + return 0; + c.value = 0; + get_ctrl(ctrl, &c); + return c.value; +} +EXPORT_SYMBOL(v4l2_ctrl_g_ctrl); + +s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl) +{ + struct v4l2_ext_control c; + + /* It's a driver bug if this happens. */ + if (WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64)) + return 0; + c.value64 = 0; + get_ctrl(ctrl, &c); + return c.value64; +} +EXPORT_SYMBOL(v4l2_ctrl_g_ctrl_int64); + +int __v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val) +{ + lockdep_assert_held(ctrl->handler->lock); + + /* It's a driver bug if this happens. */ + if (WARN_ON(!ctrl->is_int)) + return -EINVAL; + ctrl->val = val; + return set_ctrl(NULL, ctrl, 0); +} +EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl); + +int __v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val) +{ + lockdep_assert_held(ctrl->handler->lock); + + /* It's a driver bug if this happens. */ + if (WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64)) + return -EINVAL; + *ctrl->p_new.p_s64 = val; + return set_ctrl(NULL, ctrl, 0); +} +EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_int64); + +int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s) +{ + lockdep_assert_held(ctrl->handler->lock); + + /* It's a driver bug if this happens. */ + if (WARN_ON(ctrl->type != V4L2_CTRL_TYPE_STRING)) + return -EINVAL; + strscpy(ctrl->p_new.p_char, s, ctrl->maximum + 1); + return set_ctrl(NULL, ctrl, 0); +} +EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string); + +int __v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl *ctrl, + enum v4l2_ctrl_type type, const void *p) +{ + lockdep_assert_held(ctrl->handler->lock); + + /* It's a driver bug if this happens. */ + if (WARN_ON(ctrl->type != type)) + return -EINVAL; + memcpy(ctrl->p_new.p, p, ctrl->elems * ctrl->elem_size); + return set_ctrl(NULL, ctrl, 0); +} +EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_compound); + +/* + * Modify the range of a control. + */ +int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, + s64 min, s64 max, u64 step, s64 def) +{ + bool value_changed; + bool range_changed = false; + int ret; + + lockdep_assert_held(ctrl->handler->lock); + + switch (ctrl->type) { + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_INTEGER64: + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_INTEGER_MENU: + case V4L2_CTRL_TYPE_BITMASK: + case V4L2_CTRL_TYPE_U8: + case V4L2_CTRL_TYPE_U16: + case V4L2_CTRL_TYPE_U32: + if (ctrl->is_array) + return -EINVAL; + ret = check_range(ctrl->type, min, max, step, def); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + if (ctrl->minimum != min || ctrl->maximum != max || + ctrl->step != step || ctrl->default_value != def) { + range_changed = true; + ctrl->minimum = min; + ctrl->maximum = max; + ctrl->step = step; + ctrl->default_value = def; + } + cur_to_new(ctrl); + if (validate_new(ctrl, ctrl->p_new)) { + if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) + *ctrl->p_new.p_s64 = def; + else + *ctrl->p_new.p_s32 = def; + } + + if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) + value_changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64; + else + value_changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32; + if (value_changed) + ret = set_ctrl(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE); + else if (range_changed) + send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE); + return ret; +} +EXPORT_SYMBOL(__v4l2_ctrl_modify_range); + +/* Implement VIDIOC_QUERY_EXT_CTRL */ +int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctrl *qc) +{ + const unsigned int next_flags = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND; + u32 id = qc->id & V4L2_CTRL_ID_MASK; + struct v4l2_ctrl_ref *ref; + struct v4l2_ctrl *ctrl; + + if (!hdl) + return -EINVAL; + + mutex_lock(hdl->lock); + + /* Try to find it */ + ref = find_ref(hdl, id); + + if ((qc->id & next_flags) && !list_empty(&hdl->ctrl_refs)) { + bool is_compound; + /* Match any control that is not hidden */ + unsigned int mask = 1; + bool match = false; + + if ((qc->id & next_flags) == V4L2_CTRL_FLAG_NEXT_COMPOUND) { + /* Match any hidden control */ + match = true; + } else if ((qc->id & next_flags) == next_flags) { + /* Match any control, compound or not */ + mask = 0; + } + + /* Find the next control with ID > qc->id */ + + /* Did we reach the end of the control list? */ + if (id >= node2id(hdl->ctrl_refs.prev)) { + ref = NULL; /* Yes, so there is no next control */ + } else if (ref) { + /* + * We found a control with the given ID, so just get + * the next valid one in the list. + */ + list_for_each_entry_continue(ref, &hdl->ctrl_refs, node) { + is_compound = ref->ctrl->is_array || + ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES; + if (id < ref->ctrl->id && + (is_compound & mask) == match) + break; + } + if (&ref->node == &hdl->ctrl_refs) + ref = NULL; + } else { + /* + * No control with the given ID exists, so start + * searching for the next largest ID. We know there + * is one, otherwise the first 'if' above would have + * been true. + */ + list_for_each_entry(ref, &hdl->ctrl_refs, node) { + is_compound = ref->ctrl->is_array || + ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES; + if (id < ref->ctrl->id && + (is_compound & mask) == match) + break; + } + if (&ref->node == &hdl->ctrl_refs) + ref = NULL; + } + } + mutex_unlock(hdl->lock); + + if (!ref) + return -EINVAL; + + ctrl = ref->ctrl; + memset(qc, 0, sizeof(*qc)); + if (id >= V4L2_CID_PRIVATE_BASE) + qc->id = id; + else + qc->id = ctrl->id; + strscpy(qc->name, ctrl->name, sizeof(qc->name)); + qc->flags = user_flags(ctrl); + qc->type = ctrl->type; + qc->elem_size = ctrl->elem_size; + qc->elems = ctrl->elems; + qc->nr_of_dims = ctrl->nr_of_dims; + memcpy(qc->dims, ctrl->dims, qc->nr_of_dims * sizeof(qc->dims[0])); + qc->minimum = ctrl->minimum; + qc->maximum = ctrl->maximum; + qc->default_value = ctrl->default_value; + if (ctrl->type == V4L2_CTRL_TYPE_MENU || + ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU) + qc->step = 1; + else + qc->step = ctrl->step; + return 0; +} +EXPORT_SYMBOL(v4l2_query_ext_ctrl); + +/* Implement VIDIOC_QUERYCTRL */ +int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc) +{ + struct v4l2_query_ext_ctrl qec = { qc->id }; + int rc; + + rc = v4l2_query_ext_ctrl(hdl, &qec); + if (rc) + return rc; + + qc->id = qec.id; + qc->type = qec.type; + qc->flags = qec.flags; + strscpy(qc->name, qec.name, sizeof(qc->name)); + switch (qc->type) { + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_INTEGER_MENU: + case V4L2_CTRL_TYPE_STRING: + case V4L2_CTRL_TYPE_BITMASK: + qc->minimum = qec.minimum; + qc->maximum = qec.maximum; + qc->step = qec.step; + qc->default_value = qec.default_value; + break; + default: + qc->minimum = 0; + qc->maximum = 0; + qc->step = 0; + qc->default_value = 0; + break; + } + return 0; +} +EXPORT_SYMBOL(v4l2_queryctrl); + +/* Implement VIDIOC_QUERYMENU */ +int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm) +{ + struct v4l2_ctrl *ctrl; + u32 i = qm->index; + + ctrl = v4l2_ctrl_find(hdl, qm->id); + if (!ctrl) + return -EINVAL; + + qm->reserved = 0; + /* Sanity checks */ + switch (ctrl->type) { + case V4L2_CTRL_TYPE_MENU: + if (!ctrl->qmenu) + return -EINVAL; + break; + case V4L2_CTRL_TYPE_INTEGER_MENU: + if (!ctrl->qmenu_int) + return -EINVAL; + break; + default: + return -EINVAL; + } + + if (i < ctrl->minimum || i > ctrl->maximum) + return -EINVAL; + + /* Use mask to see if this menu item should be skipped */ + if (ctrl->menu_skip_mask & (1ULL << i)) + return -EINVAL; + /* Empty menu items should also be skipped */ + if (ctrl->type == V4L2_CTRL_TYPE_MENU) { + if (!ctrl->qmenu[i] || ctrl->qmenu[i][0] == '\0') + return -EINVAL; + strscpy(qm->name, ctrl->qmenu[i], sizeof(qm->name)); + } else { + qm->value = ctrl->qmenu_int[i]; + } + return 0; +} +EXPORT_SYMBOL(v4l2_querymenu); + +/* + * VIDIOC_LOG_STATUS helpers + */ + +int v4l2_ctrl_log_status(struct file *file, void *fh) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_fh *vfh = file->private_data; + + if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev) + v4l2_ctrl_handler_log_status(vfh->ctrl_handler, + vfd->v4l2_dev->name); + return 0; +} +EXPORT_SYMBOL(v4l2_ctrl_log_status); + +int v4l2_ctrl_subdev_log_status(struct v4l2_subdev *sd) +{ + v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name); + return 0; +} +EXPORT_SYMBOL(v4l2_ctrl_subdev_log_status); + +/* + * VIDIOC_(UN)SUBSCRIBE_EVENT implementation + */ + +static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev, + unsigned int elems) +{ + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id); + + if (!ctrl) + return -EINVAL; + + v4l2_ctrl_lock(ctrl); + list_add_tail(&sev->node, &ctrl->ev_subs); + if (ctrl->type != V4L2_CTRL_TYPE_CTRL_CLASS && + (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL)) + send_initial_event(sev->fh, ctrl); + v4l2_ctrl_unlock(ctrl); + return 0; +} + +static void v4l2_ctrl_del_event(struct v4l2_subscribed_event *sev) +{ + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id); + + if (!ctrl) + return; + + v4l2_ctrl_lock(ctrl); + list_del(&sev->node); + v4l2_ctrl_unlock(ctrl); +} + +void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new) +{ + u32 old_changes = old->u.ctrl.changes; + + old->u.ctrl = new->u.ctrl; + old->u.ctrl.changes |= old_changes; +} +EXPORT_SYMBOL(v4l2_ctrl_replace); + +void v4l2_ctrl_merge(const struct v4l2_event *old, struct v4l2_event *new) +{ + new->u.ctrl.changes |= old->u.ctrl.changes; +} +EXPORT_SYMBOL(v4l2_ctrl_merge); + +const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops = { + .add = v4l2_ctrl_add_event, + .del = v4l2_ctrl_del_event, + .replace = v4l2_ctrl_replace, + .merge = v4l2_ctrl_merge, +}; +EXPORT_SYMBOL(v4l2_ctrl_sub_ev_ops); + +int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + if (sub->type == V4L2_EVENT_CTRL) + return v4l2_event_subscribe(fh, sub, 0, &v4l2_ctrl_sub_ev_ops); + return -EINVAL; +} +EXPORT_SYMBOL(v4l2_ctrl_subscribe_event); + +int v4l2_ctrl_subdev_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + if (!sd->ctrl_handler) + return -EINVAL; + return v4l2_ctrl_subscribe_event(fh, sub); +} +EXPORT_SYMBOL(v4l2_ctrl_subdev_subscribe_event); + +/* + * poll helper + */ +__poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait) +{ + struct v4l2_fh *fh = file->private_data; + + poll_wait(file, &fh->wait, wait); + if (v4l2_event_pending(fh)) + return EPOLLPRI; + return 0; +} +EXPORT_SYMBOL(v4l2_ctrl_poll); diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c new file mode 100644 index 000000000000..081439224357 --- /dev/null +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -0,0 +1,1939 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * V4L2 controls framework core implementation. + * + * Copyright (C) 2010-2021 Hans Verkuil + */ + +#include +#include +#include +#include +#include +#include + +#include "v4l2-ctrls-priv.h" + +static const union v4l2_ctrl_ptr ptr_null; + +static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, + u32 changes) +{ + memset(ev, 0, sizeof(*ev)); + ev->type = V4L2_EVENT_CTRL; + ev->id = ctrl->id; + ev->u.ctrl.changes = changes; + ev->u.ctrl.type = ctrl->type; + ev->u.ctrl.flags = user_flags(ctrl); + if (ctrl->is_ptr) + ev->u.ctrl.value64 = 0; + else + ev->u.ctrl.value64 = *ctrl->p_cur.p_s64; + ev->u.ctrl.minimum = ctrl->minimum; + ev->u.ctrl.maximum = ctrl->maximum; + if (ctrl->type == V4L2_CTRL_TYPE_MENU + || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU) + ev->u.ctrl.step = 1; + else + ev->u.ctrl.step = ctrl->step; + ev->u.ctrl.default_value = ctrl->default_value; +} + +void send_initial_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl) +{ + struct v4l2_event ev; + u32 changes = V4L2_EVENT_CTRL_CH_FLAGS; + + if (!(ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)) + changes |= V4L2_EVENT_CTRL_CH_VALUE; + fill_event(&ev, ctrl, changes); + v4l2_event_queue_fh(fh, &ev); +} + +void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes) +{ + struct v4l2_event ev; + struct v4l2_subscribed_event *sev; + + if (list_empty(&ctrl->ev_subs)) + return; + fill_event(&ev, ctrl, changes); + + list_for_each_entry(sev, &ctrl->ev_subs, node) + if (sev->fh != fh || + (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK)) + v4l2_event_queue_fh(sev->fh, &ev); +} + +static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx, + union v4l2_ctrl_ptr ptr1, + union v4l2_ctrl_ptr ptr2) +{ + switch (ctrl->type) { + case V4L2_CTRL_TYPE_BUTTON: + return false; + case V4L2_CTRL_TYPE_STRING: + idx *= ctrl->elem_size; + /* strings are always 0-terminated */ + return !strcmp(ptr1.p_char + idx, ptr2.p_char + idx); + case V4L2_CTRL_TYPE_INTEGER64: + return ptr1.p_s64[idx] == ptr2.p_s64[idx]; + case V4L2_CTRL_TYPE_U8: + return ptr1.p_u8[idx] == ptr2.p_u8[idx]; + case V4L2_CTRL_TYPE_U16: + return ptr1.p_u16[idx] == ptr2.p_u16[idx]; + case V4L2_CTRL_TYPE_U32: + return ptr1.p_u32[idx] == ptr2.p_u32[idx]; + default: + if (ctrl->is_int) + return ptr1.p_s32[idx] == ptr2.p_s32[idx]; + idx *= ctrl->elem_size; + return !memcmp(ptr1.p_const + idx, ptr2.p_const + idx, + ctrl->elem_size); + } +} + +/* Default intra MPEG-2 quantisation coefficients, from the specification. */ +static const u8 mpeg2_intra_quant_matrix[64] = { + 8, 16, 16, 19, 16, 19, 22, 22, + 22, 22, 22, 22, 26, 24, 26, 27, + 27, 27, 26, 26, 26, 26, 27, 27, + 27, 29, 29, 29, 34, 34, 34, 29, + 29, 29, 27, 27, 29, 29, 32, 32, + 34, 34, 37, 38, 37, 35, 35, 34, + 35, 38, 38, 40, 40, 40, 48, 48, + 46, 46, 56, 56, 58, 69, 69, 83 +}; + +static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, + union v4l2_ctrl_ptr ptr) +{ + struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence; + struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture; + struct v4l2_ctrl_mpeg2_quantisation *p_mpeg2_quant; + struct v4l2_ctrl_vp8_frame *p_vp8_frame; + struct v4l2_ctrl_fwht_params *p_fwht_params; + void *p = ptr.p + idx * ctrl->elem_size; + + if (ctrl->p_def.p_const) + memcpy(p, ctrl->p_def.p_const, ctrl->elem_size); + else + memset(p, 0, ctrl->elem_size); + + switch ((u32)ctrl->type) { + case V4L2_CTRL_TYPE_MPEG2_SEQUENCE: + p_mpeg2_sequence = p; + + /* 4:2:0 */ + p_mpeg2_sequence->chroma_format = 1; + break; + case V4L2_CTRL_TYPE_MPEG2_PICTURE: + p_mpeg2_picture = p; + + /* interlaced top field */ + p_mpeg2_picture->picture_structure = V4L2_MPEG2_PIC_TOP_FIELD; + p_mpeg2_picture->picture_coding_type = + V4L2_MPEG2_PIC_CODING_TYPE_I; + break; + case V4L2_CTRL_TYPE_MPEG2_QUANTISATION: + p_mpeg2_quant = p; + + memcpy(p_mpeg2_quant->intra_quantiser_matrix, + mpeg2_intra_quant_matrix, + ARRAY_SIZE(mpeg2_intra_quant_matrix)); + /* + * The default non-intra MPEG-2 quantisation + * coefficients are all 16, as per the specification. + */ + memset(p_mpeg2_quant->non_intra_quantiser_matrix, 16, + sizeof(p_mpeg2_quant->non_intra_quantiser_matrix)); + break; + case V4L2_CTRL_TYPE_VP8_FRAME: + p_vp8_frame = p; + p_vp8_frame->num_dct_parts = 1; + break; + case V4L2_CTRL_TYPE_FWHT_PARAMS: + p_fwht_params = p; + p_fwht_params->version = V4L2_FWHT_VERSION; + p_fwht_params->width = 1280; + p_fwht_params->height = 720; + p_fwht_params->flags = V4L2_FWHT_FL_PIXENC_YUV | + (2 << V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET); + break; + } +} + +static void std_init(const struct v4l2_ctrl *ctrl, u32 idx, + union v4l2_ctrl_ptr ptr) +{ + switch (ctrl->type) { + case V4L2_CTRL_TYPE_STRING: + idx *= ctrl->elem_size; + memset(ptr.p_char + idx, ' ', ctrl->minimum); + ptr.p_char[idx + ctrl->minimum] = '\0'; + break; + case V4L2_CTRL_TYPE_INTEGER64: + ptr.p_s64[idx] = ctrl->default_value; + break; + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_INTEGER_MENU: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_BITMASK: + case V4L2_CTRL_TYPE_BOOLEAN: + ptr.p_s32[idx] = ctrl->default_value; + break; + case V4L2_CTRL_TYPE_BUTTON: + case V4L2_CTRL_TYPE_CTRL_CLASS: + ptr.p_s32[idx] = 0; + break; + case V4L2_CTRL_TYPE_U8: + ptr.p_u8[idx] = ctrl->default_value; + break; + case V4L2_CTRL_TYPE_U16: + ptr.p_u16[idx] = ctrl->default_value; + break; + case V4L2_CTRL_TYPE_U32: + ptr.p_u32[idx] = ctrl->default_value; + break; + default: + std_init_compound(ctrl, idx, ptr); + break; + } +} + +static void std_log(const struct v4l2_ctrl *ctrl) +{ + union v4l2_ctrl_ptr ptr = ctrl->p_cur; + + if (ctrl->is_array) { + unsigned i; + + for (i = 0; i < ctrl->nr_of_dims; i++) + pr_cont("[%u]", ctrl->dims[i]); + pr_cont(" "); + } + + switch (ctrl->type) { + case V4L2_CTRL_TYPE_INTEGER: + pr_cont("%d", *ptr.p_s32); + break; + case V4L2_CTRL_TYPE_BOOLEAN: + pr_cont("%s", *ptr.p_s32 ? "true" : "false"); + break; + case V4L2_CTRL_TYPE_MENU: + pr_cont("%s", ctrl->qmenu[*ptr.p_s32]); + break; + case V4L2_CTRL_TYPE_INTEGER_MENU: + pr_cont("%lld", ctrl->qmenu_int[*ptr.p_s32]); + break; + case V4L2_CTRL_TYPE_BITMASK: + pr_cont("0x%08x", *ptr.p_s32); + break; + case V4L2_CTRL_TYPE_INTEGER64: + pr_cont("%lld", *ptr.p_s64); + break; + case V4L2_CTRL_TYPE_STRING: + pr_cont("%s", ptr.p_char); + break; + case V4L2_CTRL_TYPE_U8: + pr_cont("%u", (unsigned)*ptr.p_u8); + break; + case V4L2_CTRL_TYPE_U16: + pr_cont("%u", (unsigned)*ptr.p_u16); + break; + case V4L2_CTRL_TYPE_U32: + pr_cont("%u", (unsigned)*ptr.p_u32); + break; + case V4L2_CTRL_TYPE_H264_SPS: + pr_cont("H264_SPS"); + break; + case V4L2_CTRL_TYPE_H264_PPS: + pr_cont("H264_PPS"); + break; + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: + pr_cont("H264_SCALING_MATRIX"); + break; + case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: + pr_cont("H264_SLICE_PARAMS"); + break; + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: + pr_cont("H264_DECODE_PARAMS"); + break; + case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: + pr_cont("H264_PRED_WEIGHTS"); + break; + case V4L2_CTRL_TYPE_FWHT_PARAMS: + pr_cont("FWHT_PARAMS"); + break; + case V4L2_CTRL_TYPE_VP8_FRAME: + pr_cont("VP8_FRAME"); + break; + case V4L2_CTRL_TYPE_HDR10_CLL_INFO: + pr_cont("HDR10_CLL_INFO"); + break; + case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY: + pr_cont("HDR10_MASTERING_DISPLAY"); + break; + case V4L2_CTRL_TYPE_MPEG2_QUANTISATION: + pr_cont("MPEG2_QUANTISATION"); + break; + case V4L2_CTRL_TYPE_MPEG2_SEQUENCE: + pr_cont("MPEG2_SEQUENCE"); + break; + case V4L2_CTRL_TYPE_MPEG2_PICTURE: + pr_cont("MPEG2_PICTURE"); + break; + default: + pr_cont("unknown type %d", ctrl->type); + break; + } +} + +/* + * Round towards the closest legal value. Be careful when we are + * close to the maximum range of the control type to prevent + * wrap-arounds. + */ +#define ROUND_TO_RANGE(val, offset_type, ctrl) \ +({ \ + offset_type offset; \ + if ((ctrl)->maximum >= 0 && \ + val >= (ctrl)->maximum - (s32)((ctrl)->step / 2)) \ + val = (ctrl)->maximum; \ + else \ + val += (s32)((ctrl)->step / 2); \ + val = clamp_t(typeof(val), val, \ + (ctrl)->minimum, (ctrl)->maximum); \ + offset = (val) - (ctrl)->minimum; \ + offset = (ctrl)->step * (offset / (u32)(ctrl)->step); \ + val = (ctrl)->minimum + offset; \ + 0; \ +}) + +/* Validate a new control */ + +#define zero_padding(s) \ + memset(&(s).padding, 0, sizeof((s).padding)) +#define zero_reserved(s) \ + memset(&(s).reserved, 0, sizeof((s).reserved)) + +/* + * Compound controls validation requires setting unused fields/flags to zero + * in order to properly detect unchanged controls with std_equal's memcmp. + */ +static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + union v4l2_ctrl_ptr ptr) +{ + struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence; + struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture; + struct v4l2_ctrl_vp8_frame *p_vp8_frame; + struct v4l2_ctrl_fwht_params *p_fwht_params; + struct v4l2_ctrl_h264_sps *p_h264_sps; + struct v4l2_ctrl_h264_pps *p_h264_pps; + struct v4l2_ctrl_h264_pred_weights *p_h264_pred_weights; + struct v4l2_ctrl_h264_slice_params *p_h264_slice_params; + struct v4l2_ctrl_h264_decode_params *p_h264_dec_params; + struct v4l2_ctrl_hevc_sps *p_hevc_sps; + struct v4l2_ctrl_hevc_pps *p_hevc_pps; + struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params; + struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering; + struct v4l2_area *area; + void *p = ptr.p + idx * ctrl->elem_size; + unsigned int i; + + switch ((u32)ctrl->type) { + case V4L2_CTRL_TYPE_MPEG2_SEQUENCE: + p_mpeg2_sequence = p; + + switch (p_mpeg2_sequence->chroma_format) { + case 1: /* 4:2:0 */ + case 2: /* 4:2:2 */ + case 3: /* 4:4:4 */ + break; + default: + return -EINVAL; + } + break; + + case V4L2_CTRL_TYPE_MPEG2_PICTURE: + p_mpeg2_picture = p; + + switch (p_mpeg2_picture->intra_dc_precision) { + case 0: /* 8 bits */ + case 1: /* 9 bits */ + case 2: /* 10 bits */ + case 3: /* 11 bits */ + break; + default: + return -EINVAL; + } + + switch (p_mpeg2_picture->picture_structure) { + case V4L2_MPEG2_PIC_TOP_FIELD: + case V4L2_MPEG2_PIC_BOTTOM_FIELD: + case V4L2_MPEG2_PIC_FRAME: + break; + default: + return -EINVAL; + } + + switch (p_mpeg2_picture->picture_coding_type) { + case V4L2_MPEG2_PIC_CODING_TYPE_I: + case V4L2_MPEG2_PIC_CODING_TYPE_P: + case V4L2_MPEG2_PIC_CODING_TYPE_B: + break; + default: + return -EINVAL; + } + zero_reserved(*p_mpeg2_picture); + break; + + case V4L2_CTRL_TYPE_MPEG2_QUANTISATION: + break; + + case V4L2_CTRL_TYPE_FWHT_PARAMS: + p_fwht_params = p; + if (p_fwht_params->version < V4L2_FWHT_VERSION) + return -EINVAL; + if (!p_fwht_params->width || !p_fwht_params->height) + return -EINVAL; + break; + + case V4L2_CTRL_TYPE_H264_SPS: + p_h264_sps = p; + + /* Some syntax elements are only conditionally valid */ + if (p_h264_sps->pic_order_cnt_type != 0) { + p_h264_sps->log2_max_pic_order_cnt_lsb_minus4 = 0; + } else if (p_h264_sps->pic_order_cnt_type != 1) { + p_h264_sps->num_ref_frames_in_pic_order_cnt_cycle = 0; + p_h264_sps->offset_for_non_ref_pic = 0; + p_h264_sps->offset_for_top_to_bottom_field = 0; + memset(&p_h264_sps->offset_for_ref_frame, 0, + sizeof(p_h264_sps->offset_for_ref_frame)); + } + + if (!V4L2_H264_SPS_HAS_CHROMA_FORMAT(p_h264_sps)) { + p_h264_sps->chroma_format_idc = 1; + p_h264_sps->bit_depth_luma_minus8 = 0; + p_h264_sps->bit_depth_chroma_minus8 = 0; + + p_h264_sps->flags &= + ~V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS; + + if (p_h264_sps->chroma_format_idc < 3) + p_h264_sps->flags &= + ~V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE; + } + + if (p_h264_sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) + p_h264_sps->flags &= + ~V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD; + + /* + * Chroma 4:2:2 format require at least High 4:2:2 profile. + * + * The H264 specification and well-known parser implementations + * use profile-idc values directly, as that is clearer and + * less ambiguous. We do the same here. + */ + if (p_h264_sps->profile_idc < 122 && + p_h264_sps->chroma_format_idc > 1) + return -EINVAL; + /* Chroma 4:4:4 format require at least High 4:2:2 profile */ + if (p_h264_sps->profile_idc < 244 && + p_h264_sps->chroma_format_idc > 2) + return -EINVAL; + if (p_h264_sps->chroma_format_idc > 3) + return -EINVAL; + + if (p_h264_sps->bit_depth_luma_minus8 > 6) + return -EINVAL; + if (p_h264_sps->bit_depth_chroma_minus8 > 6) + return -EINVAL; + if (p_h264_sps->log2_max_frame_num_minus4 > 12) + return -EINVAL; + if (p_h264_sps->pic_order_cnt_type > 2) + return -EINVAL; + if (p_h264_sps->log2_max_pic_order_cnt_lsb_minus4 > 12) + return -EINVAL; + if (p_h264_sps->max_num_ref_frames > V4L2_H264_REF_LIST_LEN) + return -EINVAL; + break; + + case V4L2_CTRL_TYPE_H264_PPS: + p_h264_pps = p; + + if (p_h264_pps->num_slice_groups_minus1 > 7) + return -EINVAL; + if (p_h264_pps->num_ref_idx_l0_default_active_minus1 > + (V4L2_H264_REF_LIST_LEN - 1)) + return -EINVAL; + if (p_h264_pps->num_ref_idx_l1_default_active_minus1 > + (V4L2_H264_REF_LIST_LEN - 1)) + return -EINVAL; + if (p_h264_pps->weighted_bipred_idc > 2) + return -EINVAL; + /* + * pic_init_qp_minus26 shall be in the range of + * -(26 + QpBdOffset_y) to +25, inclusive, + * where QpBdOffset_y is 6 * bit_depth_luma_minus8 + */ + if (p_h264_pps->pic_init_qp_minus26 < -62 || + p_h264_pps->pic_init_qp_minus26 > 25) + return -EINVAL; + if (p_h264_pps->pic_init_qs_minus26 < -26 || + p_h264_pps->pic_init_qs_minus26 > 25) + return -EINVAL; + if (p_h264_pps->chroma_qp_index_offset < -12 || + p_h264_pps->chroma_qp_index_offset > 12) + return -EINVAL; + if (p_h264_pps->second_chroma_qp_index_offset < -12 || + p_h264_pps->second_chroma_qp_index_offset > 12) + return -EINVAL; + break; + + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: + break; + + case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: + p_h264_pred_weights = p; + + if (p_h264_pred_weights->luma_log2_weight_denom > 7) + return -EINVAL; + if (p_h264_pred_weights->chroma_log2_weight_denom > 7) + return -EINVAL; + break; + + case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: + p_h264_slice_params = p; + + if (p_h264_slice_params->slice_type != V4L2_H264_SLICE_TYPE_B) + p_h264_slice_params->flags &= + ~V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED; + + if (p_h264_slice_params->colour_plane_id > 2) + return -EINVAL; + if (p_h264_slice_params->cabac_init_idc > 2) + return -EINVAL; + if (p_h264_slice_params->disable_deblocking_filter_idc > 2) + return -EINVAL; + if (p_h264_slice_params->slice_alpha_c0_offset_div2 < -6 || + p_h264_slice_params->slice_alpha_c0_offset_div2 > 6) + return -EINVAL; + if (p_h264_slice_params->slice_beta_offset_div2 < -6 || + p_h264_slice_params->slice_beta_offset_div2 > 6) + return -EINVAL; + + if (p_h264_slice_params->slice_type == V4L2_H264_SLICE_TYPE_I || + p_h264_slice_params->slice_type == V4L2_H264_SLICE_TYPE_SI) + p_h264_slice_params->num_ref_idx_l0_active_minus1 = 0; + if (p_h264_slice_params->slice_type != V4L2_H264_SLICE_TYPE_B) + p_h264_slice_params->num_ref_idx_l1_active_minus1 = 0; + + if (p_h264_slice_params->num_ref_idx_l0_active_minus1 > + (V4L2_H264_REF_LIST_LEN - 1)) + return -EINVAL; + if (p_h264_slice_params->num_ref_idx_l1_active_minus1 > + (V4L2_H264_REF_LIST_LEN - 1)) + return -EINVAL; + zero_reserved(*p_h264_slice_params); + break; + + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: + p_h264_dec_params = p; + + if (p_h264_dec_params->nal_ref_idc > 3) + return -EINVAL; + for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) { + struct v4l2_h264_dpb_entry *dpb_entry = + &p_h264_dec_params->dpb[i]; + + zero_reserved(*dpb_entry); + } + zero_reserved(*p_h264_dec_params); + break; + + case V4L2_CTRL_TYPE_VP8_FRAME: + p_vp8_frame = p; + + switch (p_vp8_frame->num_dct_parts) { + case 1: + case 2: + case 4: + case 8: + break; + default: + return -EINVAL; + } + zero_padding(p_vp8_frame->segment); + zero_padding(p_vp8_frame->lf); + zero_padding(p_vp8_frame->quant); + zero_padding(p_vp8_frame->entropy); + zero_padding(p_vp8_frame->coder_state); + break; + + case V4L2_CTRL_TYPE_HEVC_SPS: + p_hevc_sps = p; + + if (!(p_hevc_sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED)) { + p_hevc_sps->pcm_sample_bit_depth_luma_minus1 = 0; + p_hevc_sps->pcm_sample_bit_depth_chroma_minus1 = 0; + p_hevc_sps->log2_min_pcm_luma_coding_block_size_minus3 = 0; + p_hevc_sps->log2_diff_max_min_pcm_luma_coding_block_size = 0; + } + + if (!(p_hevc_sps->flags & + V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT)) + p_hevc_sps->num_long_term_ref_pics_sps = 0; + break; + + case V4L2_CTRL_TYPE_HEVC_PPS: + p_hevc_pps = p; + + if (!(p_hevc_pps->flags & + V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED)) + p_hevc_pps->diff_cu_qp_delta_depth = 0; + + if (!(p_hevc_pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED)) { + p_hevc_pps->num_tile_columns_minus1 = 0; + p_hevc_pps->num_tile_rows_minus1 = 0; + memset(&p_hevc_pps->column_width_minus1, 0, + sizeof(p_hevc_pps->column_width_minus1)); + memset(&p_hevc_pps->row_height_minus1, 0, + sizeof(p_hevc_pps->row_height_minus1)); + + p_hevc_pps->flags &= + ~V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED; + } + + if (p_hevc_pps->flags & + V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER) { + p_hevc_pps->pps_beta_offset_div2 = 0; + p_hevc_pps->pps_tc_offset_div2 = 0; + } + + zero_padding(*p_hevc_pps); + break; + + case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: + p_hevc_slice_params = p; + + if (p_hevc_slice_params->num_active_dpb_entries > + V4L2_HEVC_DPB_ENTRIES_NUM_MAX) + return -EINVAL; + + zero_padding(p_hevc_slice_params->pred_weight_table); + + for (i = 0; i < p_hevc_slice_params->num_active_dpb_entries; + i++) { + struct v4l2_hevc_dpb_entry *dpb_entry = + &p_hevc_slice_params->dpb[i]; + + zero_padding(*dpb_entry); + } + + zero_padding(*p_hevc_slice_params); + break; + + case V4L2_CTRL_TYPE_HDR10_CLL_INFO: + break; + + case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY: + p_hdr10_mastering = p; + + for (i = 0; i < 3; ++i) { + if (p_hdr10_mastering->display_primaries_x[i] < + V4L2_HDR10_MASTERING_PRIMARIES_X_LOW || + p_hdr10_mastering->display_primaries_x[i] > + V4L2_HDR10_MASTERING_PRIMARIES_X_HIGH || + p_hdr10_mastering->display_primaries_y[i] < + V4L2_HDR10_MASTERING_PRIMARIES_Y_LOW || + p_hdr10_mastering->display_primaries_y[i] > + V4L2_HDR10_MASTERING_PRIMARIES_Y_HIGH) + return -EINVAL; + } + + if (p_hdr10_mastering->white_point_x < + V4L2_HDR10_MASTERING_WHITE_POINT_X_LOW || + p_hdr10_mastering->white_point_x > + V4L2_HDR10_MASTERING_WHITE_POINT_X_HIGH || + p_hdr10_mastering->white_point_y < + V4L2_HDR10_MASTERING_WHITE_POINT_Y_LOW || + p_hdr10_mastering->white_point_y > + V4L2_HDR10_MASTERING_WHITE_POINT_Y_HIGH) + return -EINVAL; + + if (p_hdr10_mastering->max_display_mastering_luminance < + V4L2_HDR10_MASTERING_MAX_LUMA_LOW || + p_hdr10_mastering->max_display_mastering_luminance > + V4L2_HDR10_MASTERING_MAX_LUMA_HIGH || + p_hdr10_mastering->min_display_mastering_luminance < + V4L2_HDR10_MASTERING_MIN_LUMA_LOW || + p_hdr10_mastering->min_display_mastering_luminance > + V4L2_HDR10_MASTERING_MIN_LUMA_HIGH) + return -EINVAL; + + /* The following restriction comes from ITU-T Rec. H.265 spec */ + if (p_hdr10_mastering->max_display_mastering_luminance == + V4L2_HDR10_MASTERING_MAX_LUMA_LOW && + p_hdr10_mastering->min_display_mastering_luminance == + V4L2_HDR10_MASTERING_MIN_LUMA_HIGH) + return -EINVAL; + + break; + + case V4L2_CTRL_TYPE_AREA: + area = p; + if (!area->width || !area->height) + return -EINVAL; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, + union v4l2_ctrl_ptr ptr) +{ + size_t len; + u64 offset; + s64 val; + + switch ((u32)ctrl->type) { + case V4L2_CTRL_TYPE_INTEGER: + return ROUND_TO_RANGE(ptr.p_s32[idx], u32, ctrl); + case V4L2_CTRL_TYPE_INTEGER64: + /* + * We can't use the ROUND_TO_RANGE define here due to + * the u64 divide that needs special care. + */ + val = ptr.p_s64[idx]; + if (ctrl->maximum >= 0 && val >= ctrl->maximum - (s64)(ctrl->step / 2)) + val = ctrl->maximum; + else + val += (s64)(ctrl->step / 2); + val = clamp_t(s64, val, ctrl->minimum, ctrl->maximum); + offset = val - ctrl->minimum; + do_div(offset, ctrl->step); + ptr.p_s64[idx] = ctrl->minimum + offset * ctrl->step; + return 0; + case V4L2_CTRL_TYPE_U8: + return ROUND_TO_RANGE(ptr.p_u8[idx], u8, ctrl); + case V4L2_CTRL_TYPE_U16: + return ROUND_TO_RANGE(ptr.p_u16[idx], u16, ctrl); + case V4L2_CTRL_TYPE_U32: + return ROUND_TO_RANGE(ptr.p_u32[idx], u32, ctrl); + + case V4L2_CTRL_TYPE_BOOLEAN: + ptr.p_s32[idx] = !!ptr.p_s32[idx]; + return 0; + + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_INTEGER_MENU: + if (ptr.p_s32[idx] < ctrl->minimum || ptr.p_s32[idx] > ctrl->maximum) + return -ERANGE; + if (ptr.p_s32[idx] < BITS_PER_LONG_LONG && + (ctrl->menu_skip_mask & BIT_ULL(ptr.p_s32[idx]))) + return -EINVAL; + if (ctrl->type == V4L2_CTRL_TYPE_MENU && + ctrl->qmenu[ptr.p_s32[idx]][0] == '\0') + return -EINVAL; + return 0; + + case V4L2_CTRL_TYPE_BITMASK: + ptr.p_s32[idx] &= ctrl->maximum; + return 0; + + case V4L2_CTRL_TYPE_BUTTON: + case V4L2_CTRL_TYPE_CTRL_CLASS: + ptr.p_s32[idx] = 0; + return 0; + + case V4L2_CTRL_TYPE_STRING: + idx *= ctrl->elem_size; + len = strlen(ptr.p_char + idx); + if (len < ctrl->minimum) + return -ERANGE; + if ((len - (u32)ctrl->minimum) % (u32)ctrl->step) + return -ERANGE; + return 0; + + default: + return std_validate_compound(ctrl, idx, ptr); + } +} + +static const struct v4l2_ctrl_type_ops std_type_ops = { + .equal = std_equal, + .init = std_init, + .log = std_log, + .validate = std_validate, +}; + +void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv) +{ + if (!ctrl) + return; + if (!notify) { + ctrl->call_notify = 0; + return; + } + if (WARN_ON(ctrl->handler->notify && ctrl->handler->notify != notify)) + return; + ctrl->handler->notify = notify; + ctrl->handler->notify_priv = priv; + ctrl->call_notify = 1; +} +EXPORT_SYMBOL(v4l2_ctrl_notify); + +/* Copy the one value to another. */ +static void ptr_to_ptr(struct v4l2_ctrl *ctrl, + union v4l2_ctrl_ptr from, union v4l2_ctrl_ptr to) +{ + if (ctrl == NULL) + return; + memcpy(to.p, from.p_const, ctrl->elems * ctrl->elem_size); +} + +/* Copy the new value to the current value. */ +void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags) +{ + bool changed; + + if (ctrl == NULL) + return; + + /* has_changed is set by cluster_changed */ + changed = ctrl->has_changed; + if (changed) + ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur); + + if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) { + /* Note: CH_FLAGS is only set for auto clusters. */ + ctrl->flags &= + ~(V4L2_CTRL_FLAG_INACTIVE | V4L2_CTRL_FLAG_VOLATILE); + if (!is_cur_manual(ctrl->cluster[0])) { + ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (ctrl->cluster[0]->has_volatiles) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + } + fh = NULL; + } + if (changed || ch_flags) { + /* If a control was changed that was not one of the controls + modified by the application, then send the event to all. */ + if (!ctrl->is_new) + fh = NULL; + send_event(fh, ctrl, + (changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) | ch_flags); + if (ctrl->call_notify && changed && ctrl->handler->notify) + ctrl->handler->notify(ctrl, ctrl->handler->notify_priv); + } +} + +/* Copy the current value to the new value */ +void cur_to_new(struct v4l2_ctrl *ctrl) +{ + if (ctrl == NULL) + return; + ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new); +} + +/* Copy the new value to the request value */ +void new_to_req(struct v4l2_ctrl_ref *ref) +{ + if (!ref) + return; + ptr_to_ptr(ref->ctrl, ref->ctrl->p_new, ref->p_req); + ref->valid_p_req = true; +} + +/* Copy the current value to the request value */ +void cur_to_req(struct v4l2_ctrl_ref *ref) +{ + if (!ref) + return; + ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->p_req); + ref->valid_p_req = true; +} + +/* Copy the request value to the new value */ +void req_to_new(struct v4l2_ctrl_ref *ref) +{ + if (!ref) + return; + if (ref->valid_p_req) + ptr_to_ptr(ref->ctrl, ref->p_req, ref->ctrl->p_new); + else + ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->ctrl->p_new); +} + +/* Control range checking */ +int check_range(enum v4l2_ctrl_type type, + s64 min, s64 max, u64 step, s64 def) +{ + switch (type) { + case V4L2_CTRL_TYPE_BOOLEAN: + if (step != 1 || max > 1 || min < 0) + return -ERANGE; + fallthrough; + case V4L2_CTRL_TYPE_U8: + case V4L2_CTRL_TYPE_U16: + case V4L2_CTRL_TYPE_U32: + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_INTEGER64: + if (step == 0 || min > max || def < min || def > max) + return -ERANGE; + return 0; + case V4L2_CTRL_TYPE_BITMASK: + if (step || min || !max || (def & ~max)) + return -ERANGE; + return 0; + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_INTEGER_MENU: + if (min > max || def < min || def > max) + return -ERANGE; + /* Note: step == menu_skip_mask for menu controls. + So here we check if the default value is masked out. */ + if (step && ((1 << def) & step)) + return -EINVAL; + return 0; + case V4L2_CTRL_TYPE_STRING: + if (min > max || min < 0 || step < 1 || def) + return -ERANGE; + return 0; + default: + return 0; + } +} + +/* Validate a new control */ +int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new) +{ + unsigned idx; + int err = 0; + + for (idx = 0; !err && idx < ctrl->elems; idx++) + err = ctrl->type_ops->validate(ctrl, idx, p_new); + return err; +} + +/* Set the handler's error code if it wasn't set earlier already */ +static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err) +{ + if (hdl->error == 0) + hdl->error = err; + return err; +} + +/* Initialize the handler */ +int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl, + unsigned nr_of_controls_hint, + struct lock_class_key *key, const char *name) +{ + mutex_init(&hdl->_lock); + hdl->lock = &hdl->_lock; + lockdep_set_class_and_name(hdl->lock, key, name); + INIT_LIST_HEAD(&hdl->ctrls); + INIT_LIST_HEAD(&hdl->ctrl_refs); + hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8; + hdl->buckets = kvmalloc_array(hdl->nr_of_buckets, + sizeof(hdl->buckets[0]), + GFP_KERNEL | __GFP_ZERO); + hdl->error = hdl->buckets ? 0 : -ENOMEM; + v4l2_ctrl_handler_init_request(hdl); + return hdl->error; +} +EXPORT_SYMBOL(v4l2_ctrl_handler_init_class); + +/* Free all controls and control refs */ +void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl) +{ + struct v4l2_ctrl_ref *ref, *next_ref; + struct v4l2_ctrl *ctrl, *next_ctrl; + struct v4l2_subscribed_event *sev, *next_sev; + + if (hdl == NULL || hdl->buckets == NULL) + return; + + v4l2_ctrl_handler_free_request(hdl); + + mutex_lock(hdl->lock); + /* Free all nodes */ + list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) { + list_del(&ref->node); + kfree(ref); + } + /* Free all controls owned by the handler */ + list_for_each_entry_safe(ctrl, next_ctrl, &hdl->ctrls, node) { + list_del(&ctrl->node); + list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node) + list_del(&sev->node); + kvfree(ctrl); + } + kvfree(hdl->buckets); + hdl->buckets = NULL; + hdl->cached = NULL; + hdl->error = 0; + mutex_unlock(hdl->lock); + mutex_destroy(&hdl->_lock); +} +EXPORT_SYMBOL(v4l2_ctrl_handler_free); + +/* For backwards compatibility: V4L2_CID_PRIVATE_BASE should no longer + be used except in G_CTRL, S_CTRL, QUERYCTRL and QUERYMENU when dealing + with applications that do not use the NEXT_CTRL flag. + + We just find the n-th private user control. It's O(N), but that should not + be an issue in this particular case. */ +static struct v4l2_ctrl_ref *find_private_ref( + struct v4l2_ctrl_handler *hdl, u32 id) +{ + struct v4l2_ctrl_ref *ref; + + id -= V4L2_CID_PRIVATE_BASE; + list_for_each_entry(ref, &hdl->ctrl_refs, node) { + /* Search for private user controls that are compatible with + VIDIOC_G/S_CTRL. */ + if (V4L2_CTRL_ID2WHICH(ref->ctrl->id) == V4L2_CTRL_CLASS_USER && + V4L2_CTRL_DRIVER_PRIV(ref->ctrl->id)) { + if (!ref->ctrl->is_int) + continue; + if (id == 0) + return ref; + id--; + } + } + return NULL; +} + +/* Find a control with the given ID. */ +struct v4l2_ctrl_ref *find_ref(struct v4l2_ctrl_handler *hdl, u32 id) +{ + struct v4l2_ctrl_ref *ref; + int bucket; + + id &= V4L2_CTRL_ID_MASK; + + /* Old-style private controls need special handling */ + if (id >= V4L2_CID_PRIVATE_BASE) + return find_private_ref(hdl, id); + bucket = id % hdl->nr_of_buckets; + + /* Simple optimization: cache the last control found */ + if (hdl->cached && hdl->cached->ctrl->id == id) + return hdl->cached; + + /* Not in cache, search the hash */ + ref = hdl->buckets ? hdl->buckets[bucket] : NULL; + while (ref && ref->ctrl->id != id) + ref = ref->next; + + if (ref) + hdl->cached = ref; /* cache it! */ + return ref; +} + +/* Find a control with the given ID. Take the handler's lock first. */ +struct v4l2_ctrl_ref *find_ref_lock(struct v4l2_ctrl_handler *hdl, u32 id) +{ + struct v4l2_ctrl_ref *ref = NULL; + + if (hdl) { + mutex_lock(hdl->lock); + ref = find_ref(hdl, id); + mutex_unlock(hdl->lock); + } + return ref; +} + +/* Find a control with the given ID. */ +struct v4l2_ctrl *v4l2_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id) +{ + struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id); + + return ref ? ref->ctrl : NULL; +} +EXPORT_SYMBOL(v4l2_ctrl_find); + +/* Allocate a new v4l2_ctrl_ref and hook it into the handler. */ +int handler_new_ref(struct v4l2_ctrl_handler *hdl, + struct v4l2_ctrl *ctrl, + struct v4l2_ctrl_ref **ctrl_ref, + bool from_other_dev, bool allocate_req) +{ + struct v4l2_ctrl_ref *ref; + struct v4l2_ctrl_ref *new_ref; + u32 id = ctrl->id; + u32 class_ctrl = V4L2_CTRL_ID2WHICH(id) | 1; + int bucket = id % hdl->nr_of_buckets; /* which bucket to use */ + unsigned int size_extra_req = 0; + + if (ctrl_ref) + *ctrl_ref = NULL; + + /* + * Automatically add the control class if it is not yet present and + * the new control is not a compound control. + */ + if (ctrl->type < V4L2_CTRL_COMPOUND_TYPES && + id != class_ctrl && find_ref_lock(hdl, class_ctrl) == NULL) + if (!v4l2_ctrl_new_std(hdl, NULL, class_ctrl, 0, 0, 0, 0)) + return hdl->error; + + if (hdl->error) + return hdl->error; + + if (allocate_req) + size_extra_req = ctrl->elems * ctrl->elem_size; + new_ref = kzalloc(sizeof(*new_ref) + size_extra_req, GFP_KERNEL); + if (!new_ref) + return handler_set_err(hdl, -ENOMEM); + new_ref->ctrl = ctrl; + new_ref->from_other_dev = from_other_dev; + if (size_extra_req) + new_ref->p_req.p = &new_ref[1]; + + INIT_LIST_HEAD(&new_ref->node); + + mutex_lock(hdl->lock); + + /* Add immediately at the end of the list if the list is empty, or if + the last element in the list has a lower ID. + This ensures that when elements are added in ascending order the + insertion is an O(1) operation. */ + if (list_empty(&hdl->ctrl_refs) || id > node2id(hdl->ctrl_refs.prev)) { + list_add_tail(&new_ref->node, &hdl->ctrl_refs); + goto insert_in_hash; + } + + /* Find insert position in sorted list */ + list_for_each_entry(ref, &hdl->ctrl_refs, node) { + if (ref->ctrl->id < id) + continue; + /* Don't add duplicates */ + if (ref->ctrl->id == id) { + kfree(new_ref); + goto unlock; + } + list_add(&new_ref->node, ref->node.prev); + break; + } + +insert_in_hash: + /* Insert the control node in the hash */ + new_ref->next = hdl->buckets[bucket]; + hdl->buckets[bucket] = new_ref; + if (ctrl_ref) + *ctrl_ref = new_ref; + if (ctrl->handler == hdl) { + /* By default each control starts in a cluster of its own. + * new_ref->ctrl is basically a cluster array with one + * element, so that's perfect to use as the cluster pointer. + * But only do this for the handler that owns the control. + */ + ctrl->cluster = &new_ref->ctrl; + ctrl->ncontrols = 1; + } + +unlock: + mutex_unlock(hdl->lock); + return 0; +} + +/* Add a new control */ +static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, + const struct v4l2_ctrl_type_ops *type_ops, + u32 id, const char *name, enum v4l2_ctrl_type type, + s64 min, s64 max, u64 step, s64 def, + const u32 dims[V4L2_CTRL_MAX_DIMS], u32 elem_size, + u32 flags, const char * const *qmenu, + const s64 *qmenu_int, const union v4l2_ctrl_ptr p_def, + void *priv) +{ + struct v4l2_ctrl *ctrl; + unsigned sz_extra; + unsigned nr_of_dims = 0; + unsigned elems = 1; + bool is_array; + unsigned tot_ctrl_size; + unsigned idx; + void *data; + int err; + + if (hdl->error) + return NULL; + + while (dims && dims[nr_of_dims]) { + elems *= dims[nr_of_dims]; + nr_of_dims++; + if (nr_of_dims == V4L2_CTRL_MAX_DIMS) + break; + } + is_array = nr_of_dims > 0; + + /* Prefill elem_size for all types handled by std_type_ops */ + switch ((u32)type) { + case V4L2_CTRL_TYPE_INTEGER64: + elem_size = sizeof(s64); + break; + case V4L2_CTRL_TYPE_STRING: + elem_size = max + 1; + break; + case V4L2_CTRL_TYPE_U8: + elem_size = sizeof(u8); + break; + case V4L2_CTRL_TYPE_U16: + elem_size = sizeof(u16); + break; + case V4L2_CTRL_TYPE_U32: + elem_size = sizeof(u32); + break; + case V4L2_CTRL_TYPE_MPEG2_SEQUENCE: + elem_size = sizeof(struct v4l2_ctrl_mpeg2_sequence); + break; + case V4L2_CTRL_TYPE_MPEG2_PICTURE: + elem_size = sizeof(struct v4l2_ctrl_mpeg2_picture); + break; + case V4L2_CTRL_TYPE_MPEG2_QUANTISATION: + elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantisation); + break; + case V4L2_CTRL_TYPE_FWHT_PARAMS: + elem_size = sizeof(struct v4l2_ctrl_fwht_params); + break; + case V4L2_CTRL_TYPE_H264_SPS: + elem_size = sizeof(struct v4l2_ctrl_h264_sps); + break; + case V4L2_CTRL_TYPE_H264_PPS: + elem_size = sizeof(struct v4l2_ctrl_h264_pps); + break; + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: + elem_size = sizeof(struct v4l2_ctrl_h264_scaling_matrix); + break; + case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: + elem_size = sizeof(struct v4l2_ctrl_h264_slice_params); + break; + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: + elem_size = sizeof(struct v4l2_ctrl_h264_decode_params); + break; + case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: + elem_size = sizeof(struct v4l2_ctrl_h264_pred_weights); + break; + case V4L2_CTRL_TYPE_VP8_FRAME: + elem_size = sizeof(struct v4l2_ctrl_vp8_frame); + break; + case V4L2_CTRL_TYPE_HEVC_SPS: + elem_size = sizeof(struct v4l2_ctrl_hevc_sps); + break; + case V4L2_CTRL_TYPE_HEVC_PPS: + elem_size = sizeof(struct v4l2_ctrl_hevc_pps); + break; + case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: + elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params); + break; + case V4L2_CTRL_TYPE_HDR10_CLL_INFO: + elem_size = sizeof(struct v4l2_ctrl_hdr10_cll_info); + break; + case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY: + elem_size = sizeof(struct v4l2_ctrl_hdr10_mastering_display); + break; + case V4L2_CTRL_TYPE_AREA: + elem_size = sizeof(struct v4l2_area); + break; + default: + if (type < V4L2_CTRL_COMPOUND_TYPES) + elem_size = sizeof(s32); + break; + } + tot_ctrl_size = elem_size * elems; + + /* Sanity checks */ + if (id == 0 || name == NULL || !elem_size || + id >= V4L2_CID_PRIVATE_BASE || + (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) || + (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL)) { + handler_set_err(hdl, -ERANGE); + return NULL; + } + err = check_range(type, min, max, step, def); + if (err) { + handler_set_err(hdl, err); + return NULL; + } + if (is_array && + (type == V4L2_CTRL_TYPE_BUTTON || + type == V4L2_CTRL_TYPE_CTRL_CLASS)) { + handler_set_err(hdl, -EINVAL); + return NULL; + } + + sz_extra = 0; + if (type == V4L2_CTRL_TYPE_BUTTON) + flags |= V4L2_CTRL_FLAG_WRITE_ONLY | + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + else if (type == V4L2_CTRL_TYPE_CTRL_CLASS) + flags |= V4L2_CTRL_FLAG_READ_ONLY; + else if (type == V4L2_CTRL_TYPE_INTEGER64 || + type == V4L2_CTRL_TYPE_STRING || + type >= V4L2_CTRL_COMPOUND_TYPES || + is_array) + sz_extra += 2 * tot_ctrl_size; + + if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) + sz_extra += elem_size; + + ctrl = kvzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL); + if (ctrl == NULL) { + handler_set_err(hdl, -ENOMEM); + return NULL; + } + + INIT_LIST_HEAD(&ctrl->node); + INIT_LIST_HEAD(&ctrl->ev_subs); + ctrl->handler = hdl; + ctrl->ops = ops; + ctrl->type_ops = type_ops ? type_ops : &std_type_ops; + ctrl->id = id; + ctrl->name = name; + ctrl->type = type; + ctrl->flags = flags; + ctrl->minimum = min; + ctrl->maximum = max; + ctrl->step = step; + ctrl->default_value = def; + ctrl->is_string = !is_array && type == V4L2_CTRL_TYPE_STRING; + ctrl->is_ptr = is_array || type >= V4L2_CTRL_COMPOUND_TYPES || ctrl->is_string; + ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64; + ctrl->is_array = is_array; + ctrl->elems = elems; + ctrl->nr_of_dims = nr_of_dims; + if (nr_of_dims) + memcpy(ctrl->dims, dims, nr_of_dims * sizeof(dims[0])); + ctrl->elem_size = elem_size; + if (type == V4L2_CTRL_TYPE_MENU) + ctrl->qmenu = qmenu; + else if (type == V4L2_CTRL_TYPE_INTEGER_MENU) + ctrl->qmenu_int = qmenu_int; + ctrl->priv = priv; + ctrl->cur.val = ctrl->val = def; + data = &ctrl[1]; + + if (!ctrl->is_int) { + ctrl->p_new.p = data; + ctrl->p_cur.p = data + tot_ctrl_size; + } else { + ctrl->p_new.p = &ctrl->val; + ctrl->p_cur.p = &ctrl->cur.val; + } + + if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) { + ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size; + memcpy(ctrl->p_def.p, p_def.p_const, elem_size); + } + + for (idx = 0; idx < elems; idx++) { + ctrl->type_ops->init(ctrl, idx, ctrl->p_cur); + ctrl->type_ops->init(ctrl, idx, ctrl->p_new); + } + + if (handler_new_ref(hdl, ctrl, NULL, false, false)) { + kvfree(ctrl); + return NULL; + } + mutex_lock(hdl->lock); + list_add_tail(&ctrl->node, &hdl->ctrls); + mutex_unlock(hdl->lock); + return ctrl; +} + +struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_config *cfg, void *priv) +{ + bool is_menu; + struct v4l2_ctrl *ctrl; + const char *name = cfg->name; + const char * const *qmenu = cfg->qmenu; + const s64 *qmenu_int = cfg->qmenu_int; + enum v4l2_ctrl_type type = cfg->type; + u32 flags = cfg->flags; + s64 min = cfg->min; + s64 max = cfg->max; + u64 step = cfg->step; + s64 def = cfg->def; + + if (name == NULL) + v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step, + &def, &flags); + + is_menu = (type == V4L2_CTRL_TYPE_MENU || + type == V4L2_CTRL_TYPE_INTEGER_MENU); + if (is_menu) + WARN_ON(step); + else + WARN_ON(cfg->menu_skip_mask); + if (type == V4L2_CTRL_TYPE_MENU && !qmenu) { + qmenu = v4l2_ctrl_get_menu(cfg->id); + } else if (type == V4L2_CTRL_TYPE_INTEGER_MENU && !qmenu_int) { + handler_set_err(hdl, -EINVAL); + return NULL; + } + + ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->type_ops, cfg->id, name, + type, min, max, + is_menu ? cfg->menu_skip_mask : step, def, + cfg->dims, cfg->elem_size, + flags, qmenu, qmenu_int, cfg->p_def, priv); + if (ctrl) + ctrl->is_private = cfg->is_private; + return ctrl; +} +EXPORT_SYMBOL(v4l2_ctrl_new_custom); + +/* Helper function for standard non-menu controls */ +struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, + u32 id, s64 min, s64 max, u64 step, s64 def) +{ + const char *name; + enum v4l2_ctrl_type type; + u32 flags; + + v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); + if (type == V4L2_CTRL_TYPE_MENU || + type == V4L2_CTRL_TYPE_INTEGER_MENU || + type >= V4L2_CTRL_COMPOUND_TYPES) { + handler_set_err(hdl, -EINVAL); + return NULL; + } + return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, + min, max, step, def, NULL, 0, + flags, NULL, NULL, ptr_null, NULL); +} +EXPORT_SYMBOL(v4l2_ctrl_new_std); + +/* Helper function for standard menu controls */ +struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, + u32 id, u8 _max, u64 mask, u8 _def) +{ + const char * const *qmenu = NULL; + const s64 *qmenu_int = NULL; + unsigned int qmenu_int_len = 0; + const char *name; + enum v4l2_ctrl_type type; + s64 min; + s64 max = _max; + s64 def = _def; + u64 step; + u32 flags; + + v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); + + if (type == V4L2_CTRL_TYPE_MENU) + qmenu = v4l2_ctrl_get_menu(id); + else if (type == V4L2_CTRL_TYPE_INTEGER_MENU) + qmenu_int = v4l2_ctrl_get_int_menu(id, &qmenu_int_len); + + if ((!qmenu && !qmenu_int) || (qmenu_int && max > qmenu_int_len)) { + handler_set_err(hdl, -EINVAL); + return NULL; + } + return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, + 0, max, mask, def, NULL, 0, + flags, qmenu, qmenu_int, ptr_null, NULL); +} +EXPORT_SYMBOL(v4l2_ctrl_new_std_menu); + +/* Helper function for standard menu controls with driver defined menu */ +struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, u32 id, u8 _max, + u64 mask, u8 _def, const char * const *qmenu) +{ + enum v4l2_ctrl_type type; + const char *name; + u32 flags; + u64 step; + s64 min; + s64 max = _max; + s64 def = _def; + + /* v4l2_ctrl_new_std_menu_items() should only be called for + * standard controls without a standard menu. + */ + if (v4l2_ctrl_get_menu(id)) { + handler_set_err(hdl, -EINVAL); + return NULL; + } + + v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); + if (type != V4L2_CTRL_TYPE_MENU || qmenu == NULL) { + handler_set_err(hdl, -EINVAL); + return NULL; + } + return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, + 0, max, mask, def, NULL, 0, + flags, qmenu, NULL, ptr_null, NULL); + +} +EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items); + +/* Helper function for standard compound controls */ +struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, u32 id, + const union v4l2_ctrl_ptr p_def) +{ + const char *name; + enum v4l2_ctrl_type type; + u32 flags; + s64 min, max, step, def; + + v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); + if (type < V4L2_CTRL_COMPOUND_TYPES) { + handler_set_err(hdl, -EINVAL); + return NULL; + } + return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, + min, max, step, def, NULL, 0, + flags, NULL, NULL, p_def, NULL); +} +EXPORT_SYMBOL(v4l2_ctrl_new_std_compound); + +/* Helper function for standard integer menu controls */ +struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, + u32 id, u8 _max, u8 _def, const s64 *qmenu_int) +{ + const char *name; + enum v4l2_ctrl_type type; + s64 min; + u64 step; + s64 max = _max; + s64 def = _def; + u32 flags; + + v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); + if (type != V4L2_CTRL_TYPE_INTEGER_MENU) { + handler_set_err(hdl, -EINVAL); + return NULL; + } + return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, + 0, max, 0, def, NULL, 0, + flags, NULL, qmenu_int, ptr_null, NULL); +} +EXPORT_SYMBOL(v4l2_ctrl_new_int_menu); + +/* Add the controls from another handler to our own. */ +int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl, + struct v4l2_ctrl_handler *add, + bool (*filter)(const struct v4l2_ctrl *ctrl), + bool from_other_dev) +{ + struct v4l2_ctrl_ref *ref; + int ret = 0; + + /* Do nothing if either handler is NULL or if they are the same */ + if (!hdl || !add || hdl == add) + return 0; + if (hdl->error) + return hdl->error; + mutex_lock(add->lock); + list_for_each_entry(ref, &add->ctrl_refs, node) { + struct v4l2_ctrl *ctrl = ref->ctrl; + + /* Skip handler-private controls. */ + if (ctrl->is_private) + continue; + /* And control classes */ + if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS) + continue; + /* Filter any unwanted controls */ + if (filter && !filter(ctrl)) + continue; + ret = handler_new_ref(hdl, ctrl, NULL, from_other_dev, false); + if (ret) + break; + } + mutex_unlock(add->lock); + return ret; +} +EXPORT_SYMBOL(v4l2_ctrl_add_handler); + +bool v4l2_ctrl_radio_filter(const struct v4l2_ctrl *ctrl) +{ + if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_TX) + return true; + if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_RX) + return true; + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_LOUDNESS: + return true; + default: + break; + } + return false; +} +EXPORT_SYMBOL(v4l2_ctrl_radio_filter); + +/* Cluster controls */ +void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls) +{ + bool has_volatiles = false; + int i; + + /* The first control is the master control and it must not be NULL */ + if (WARN_ON(ncontrols == 0 || controls[0] == NULL)) + return; + + for (i = 0; i < ncontrols; i++) { + if (controls[i]) { + controls[i]->cluster = controls; + controls[i]->ncontrols = ncontrols; + if (controls[i]->flags & V4L2_CTRL_FLAG_VOLATILE) + has_volatiles = true; + } + } + controls[0]->has_volatiles = has_volatiles; +} +EXPORT_SYMBOL(v4l2_ctrl_cluster); + +void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls, + u8 manual_val, bool set_volatile) +{ + struct v4l2_ctrl *master = controls[0]; + u32 flag = 0; + int i; + + v4l2_ctrl_cluster(ncontrols, controls); + WARN_ON(ncontrols <= 1); + WARN_ON(manual_val < master->minimum || manual_val > master->maximum); + WARN_ON(set_volatile && !has_op(master, g_volatile_ctrl)); + master->is_auto = true; + master->has_volatiles = set_volatile; + master->manual_mode_value = manual_val; + master->flags |= V4L2_CTRL_FLAG_UPDATE; + + if (!is_cur_manual(master)) + flag = V4L2_CTRL_FLAG_INACTIVE | + (set_volatile ? V4L2_CTRL_FLAG_VOLATILE : 0); + + for (i = 1; i < ncontrols; i++) + if (controls[i]) + controls[i]->flags |= flag; +} +EXPORT_SYMBOL(v4l2_ctrl_auto_cluster); + +/* + * Obtain the current volatile values of an autocluster and mark them + * as new. + */ +void update_from_auto_cluster(struct v4l2_ctrl *master) +{ + int i; + + for (i = 1; i < master->ncontrols; i++) + cur_to_new(master->cluster[i]); + if (!call_op(master, g_volatile_ctrl)) + for (i = 1; i < master->ncontrols; i++) + if (master->cluster[i]) + master->cluster[i]->is_new = 1; +} + +/* + * Return non-zero if one or more of the controls in the cluster has a new + * value that differs from the current value. + */ +static int cluster_changed(struct v4l2_ctrl *master) +{ + bool changed = false; + unsigned int idx; + int i; + + for (i = 0; i < master->ncontrols; i++) { + struct v4l2_ctrl *ctrl = master->cluster[i]; + bool ctrl_changed = false; + + if (!ctrl) + continue; + + if (ctrl->flags & V4L2_CTRL_FLAG_EXECUTE_ON_WRITE) { + changed = true; + ctrl_changed = true; + } + + /* + * Set has_changed to false to avoid generating + * the event V4L2_EVENT_CTRL_CH_VALUE + */ + if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) { + ctrl->has_changed = false; + continue; + } + + for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++) + ctrl_changed = !ctrl->type_ops->equal(ctrl, idx, + ctrl->p_cur, ctrl->p_new); + ctrl->has_changed = ctrl_changed; + changed |= ctrl->has_changed; + } + return changed; +} + +/* + * Core function that calls try/s_ctrl and ensures that the new value is + * copied to the current value on a set. + * Must be called with ctrl->handler->lock held. + */ +int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master, + bool set, u32 ch_flags) +{ + bool update_flag; + int ret; + int i; + + /* + * Go through the cluster and either validate the new value or + * (if no new value was set), copy the current value to the new + * value, ensuring a consistent view for the control ops when + * called. + */ + for (i = 0; i < master->ncontrols; i++) { + struct v4l2_ctrl *ctrl = master->cluster[i]; + + if (!ctrl) + continue; + + if (!ctrl->is_new) { + cur_to_new(ctrl); + continue; + } + /* + * Check again: it may have changed since the + * previous check in try_or_set_ext_ctrls(). + */ + if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) + return -EBUSY; + } + + ret = call_op(master, try_ctrl); + + /* Don't set if there is no change */ + if (ret || !set || !cluster_changed(master)) + return ret; + ret = call_op(master, s_ctrl); + if (ret) + return ret; + + /* If OK, then make the new values permanent. */ + update_flag = is_cur_manual(master) != is_new_manual(master); + + for (i = 0; i < master->ncontrols; i++) { + /* + * If we switch from auto to manual mode, and this cluster + * contains volatile controls, then all non-master controls + * have to be marked as changed. The 'new' value contains + * the volatile value (obtained by update_from_auto_cluster), + * which now has to become the current value. + */ + if (i && update_flag && is_new_manual(master) && + master->has_volatiles && master->cluster[i]) + master->cluster[i]->has_changed = true; + + new_to_cur(fh, master->cluster[i], ch_flags | + ((update_flag && i > 0) ? V4L2_EVENT_CTRL_CH_FLAGS : 0)); + } + return 0; +} + +/* Activate/deactivate a control. */ +void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active) +{ + /* invert since the actual flag is called 'inactive' */ + bool inactive = !active; + bool old; + + if (ctrl == NULL) + return; + + if (inactive) + /* set V4L2_CTRL_FLAG_INACTIVE */ + old = test_and_set_bit(4, &ctrl->flags); + else + /* clear V4L2_CTRL_FLAG_INACTIVE */ + old = test_and_clear_bit(4, &ctrl->flags); + if (old != inactive) + send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS); +} +EXPORT_SYMBOL(v4l2_ctrl_activate); + +void __v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed) +{ + bool old; + + if (ctrl == NULL) + return; + + lockdep_assert_held(ctrl->handler->lock); + + if (grabbed) + /* set V4L2_CTRL_FLAG_GRABBED */ + old = test_and_set_bit(1, &ctrl->flags); + else + /* clear V4L2_CTRL_FLAG_GRABBED */ + old = test_and_clear_bit(1, &ctrl->flags); + if (old != grabbed) + send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS); +} +EXPORT_SYMBOL(__v4l2_ctrl_grab); + +/* Call s_ctrl for all controls owned by the handler */ +int __v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl) +{ + struct v4l2_ctrl *ctrl; + int ret = 0; + + if (hdl == NULL) + return 0; + + lockdep_assert_held(hdl->lock); + + list_for_each_entry(ctrl, &hdl->ctrls, node) + ctrl->done = false; + + list_for_each_entry(ctrl, &hdl->ctrls, node) { + struct v4l2_ctrl *master = ctrl->cluster[0]; + int i; + + /* Skip if this control was already handled by a cluster. */ + /* Skip button controls and read-only controls. */ + if (ctrl->done || ctrl->type == V4L2_CTRL_TYPE_BUTTON || + (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)) + continue; + + for (i = 0; i < master->ncontrols; i++) { + if (master->cluster[i]) { + cur_to_new(master->cluster[i]); + master->cluster[i]->is_new = 1; + master->cluster[i]->done = true; + } + } + ret = call_op(master, s_ctrl); + if (ret) + break; + } + + return ret; +} +EXPORT_SYMBOL_GPL(__v4l2_ctrl_handler_setup); + +int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl) +{ + int ret; + + if (hdl == NULL) + return 0; + + mutex_lock(hdl->lock); + ret = __v4l2_ctrl_handler_setup(hdl); + mutex_unlock(hdl->lock); + + return ret; +} +EXPORT_SYMBOL(v4l2_ctrl_handler_setup); + +/* Log the control name and value */ +static void log_ctrl(const struct v4l2_ctrl *ctrl, + const char *prefix, const char *colon) +{ + if (ctrl->flags & (V4L2_CTRL_FLAG_DISABLED | V4L2_CTRL_FLAG_WRITE_ONLY)) + return; + if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS) + return; + + pr_info("%s%s%s: ", prefix, colon, ctrl->name); + + ctrl->type_ops->log(ctrl); + + if (ctrl->flags & (V4L2_CTRL_FLAG_INACTIVE | + V4L2_CTRL_FLAG_GRABBED | + V4L2_CTRL_FLAG_VOLATILE)) { + if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) + pr_cont(" inactive"); + if (ctrl->flags & V4L2_CTRL_FLAG_GRABBED) + pr_cont(" grabbed"); + if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) + pr_cont(" volatile"); + } + pr_cont("\n"); +} + +/* Log all controls owned by the handler */ +void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl, + const char *prefix) +{ + struct v4l2_ctrl *ctrl; + const char *colon = ""; + int len; + + if (!hdl) + return; + if (!prefix) + prefix = ""; + len = strlen(prefix); + if (len && prefix[len - 1] != ' ') + colon = ": "; + mutex_lock(hdl->lock); + list_for_each_entry(ctrl, &hdl->ctrls, node) + if (!(ctrl->flags & V4L2_CTRL_FLAG_DISABLED)) + log_ctrl(ctrl, prefix, colon); + mutex_unlock(hdl->lock); +} +EXPORT_SYMBOL(v4l2_ctrl_handler_log_status); + +int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ctrl_ops, + const struct v4l2_fwnode_device_properties *p) +{ + if (p->orientation != V4L2_FWNODE_PROPERTY_UNSET) { + u32 orientation_ctrl; + + switch (p->orientation) { + case V4L2_FWNODE_ORIENTATION_FRONT: + orientation_ctrl = V4L2_CAMERA_ORIENTATION_FRONT; + break; + case V4L2_FWNODE_ORIENTATION_BACK: + orientation_ctrl = V4L2_CAMERA_ORIENTATION_BACK; + break; + case V4L2_FWNODE_ORIENTATION_EXTERNAL: + orientation_ctrl = V4L2_CAMERA_ORIENTATION_EXTERNAL; + break; + default: + return -EINVAL; + } + if (!v4l2_ctrl_new_std_menu(hdl, ctrl_ops, + V4L2_CID_CAMERA_ORIENTATION, + V4L2_CAMERA_ORIENTATION_EXTERNAL, 0, + orientation_ctrl)) + return hdl->error; + } + + if (p->rotation != V4L2_FWNODE_PROPERTY_UNSET) { + if (!v4l2_ctrl_new_std(hdl, ctrl_ops, + V4L2_CID_CAMERA_SENSOR_ROTATION, + p->rotation, p->rotation, 1, + p->rotation)) + return hdl->error; + } + + return hdl->error; +} +EXPORT_SYMBOL(v4l2_ctrl_new_fwnode_properties); diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c new file mode 100644 index 000000000000..7963c7b43450 --- /dev/null +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c @@ -0,0 +1,1575 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * V4L2 controls framework control definitions. + * + * Copyright (C) 2010-2021 Hans Verkuil + */ + +#include +#include + +/* + * Returns NULL or a character pointer array containing the menu for + * the given control ID. The pointer array ends with a NULL pointer. + * An empty string signifies a menu entry that is invalid. This allows + * drivers to disable certain options if it is not supported. + */ +const char * const *v4l2_ctrl_get_menu(u32 id) +{ + static const char * const mpeg_audio_sampling_freq[] = { + "44.1 kHz", + "48 kHz", + "32 kHz", + NULL + }; + static const char * const mpeg_audio_encoding[] = { + "MPEG-1/2 Layer I", + "MPEG-1/2 Layer II", + "MPEG-1/2 Layer III", + "MPEG-2/4 AAC", + "AC-3", + NULL + }; + static const char * const mpeg_audio_l1_bitrate[] = { + "32 kbps", + "64 kbps", + "96 kbps", + "128 kbps", + "160 kbps", + "192 kbps", + "224 kbps", + "256 kbps", + "288 kbps", + "320 kbps", + "352 kbps", + "384 kbps", + "416 kbps", + "448 kbps", + NULL + }; + static const char * const mpeg_audio_l2_bitrate[] = { + "32 kbps", + "48 kbps", + "56 kbps", + "64 kbps", + "80 kbps", + "96 kbps", + "112 kbps", + "128 kbps", + "160 kbps", + "192 kbps", + "224 kbps", + "256 kbps", + "320 kbps", + "384 kbps", + NULL + }; + static const char * const mpeg_audio_l3_bitrate[] = { + "32 kbps", + "40 kbps", + "48 kbps", + "56 kbps", + "64 kbps", + "80 kbps", + "96 kbps", + "112 kbps", + "128 kbps", + "160 kbps", + "192 kbps", + "224 kbps", + "256 kbps", + "320 kbps", + NULL + }; + static const char * const mpeg_audio_ac3_bitrate[] = { + "32 kbps", + "40 kbps", + "48 kbps", + "56 kbps", + "64 kbps", + "80 kbps", + "96 kbps", + "112 kbps", + "128 kbps", + "160 kbps", + "192 kbps", + "224 kbps", + "256 kbps", + "320 kbps", + "384 kbps", + "448 kbps", + "512 kbps", + "576 kbps", + "640 kbps", + NULL + }; + static const char * const mpeg_audio_mode[] = { + "Stereo", + "Joint Stereo", + "Dual", + "Mono", + NULL + }; + static const char * const mpeg_audio_mode_extension[] = { + "Bound 4", + "Bound 8", + "Bound 12", + "Bound 16", + NULL + }; + static const char * const mpeg_audio_emphasis[] = { + "No Emphasis", + "50/15 us", + "CCITT J17", + NULL + }; + static const char * const mpeg_audio_crc[] = { + "No CRC", + "16-bit CRC", + NULL + }; + static const char * const mpeg_audio_dec_playback[] = { + "Auto", + "Stereo", + "Left", + "Right", + "Mono", + "Swapped Stereo", + NULL + }; + static const char * const mpeg_video_encoding[] = { + "MPEG-1", + "MPEG-2", + "MPEG-4 AVC", + NULL + }; + static const char * const mpeg_video_aspect[] = { + "1x1", + "4x3", + "16x9", + "2.21x1", + NULL + }; + static const char * const mpeg_video_bitrate_mode[] = { + "Variable Bitrate", + "Constant Bitrate", + "Constant Quality", + NULL + }; + static const char * const mpeg_stream_type[] = { + "MPEG-2 Program Stream", + "MPEG-2 Transport Stream", + "MPEG-1 System Stream", + "MPEG-2 DVD-compatible Stream", + "MPEG-1 VCD-compatible Stream", + "MPEG-2 SVCD-compatible Stream", + NULL + }; + static const char * const mpeg_stream_vbi_fmt[] = { + "No VBI", + "Private Packet, IVTV Format", + NULL + }; + static const char * const camera_power_line_frequency[] = { + "Disabled", + "50 Hz", + "60 Hz", + "Auto", + NULL + }; + static const char * const camera_exposure_auto[] = { + "Auto Mode", + "Manual Mode", + "Shutter Priority Mode", + "Aperture Priority Mode", + NULL + }; + static const char * const camera_exposure_metering[] = { + "Average", + "Center Weighted", + "Spot", + "Matrix", + NULL + }; + static const char * const camera_auto_focus_range[] = { + "Auto", + "Normal", + "Macro", + "Infinity", + NULL + }; + static const char * const colorfx[] = { + "None", + "Black & White", + "Sepia", + "Negative", + "Emboss", + "Sketch", + "Sky Blue", + "Grass Green", + "Skin Whiten", + "Vivid", + "Aqua", + "Art Freeze", + "Silhouette", + "Solarization", + "Antique", + "Set Cb/Cr", + NULL + }; + static const char * const auto_n_preset_white_balance[] = { + "Manual", + "Auto", + "Incandescent", + "Fluorescent", + "Fluorescent H", + "Horizon", + "Daylight", + "Flash", + "Cloudy", + "Shade", + NULL, + }; + static const char * const camera_iso_sensitivity_auto[] = { + "Manual", + "Auto", + NULL + }; + static const char * const scene_mode[] = { + "None", + "Backlight", + "Beach/Snow", + "Candle Light", + "Dusk/Dawn", + "Fall Colors", + "Fireworks", + "Landscape", + "Night", + "Party/Indoor", + "Portrait", + "Sports", + "Sunset", + "Text", + NULL + }; + static const char * const tune_emphasis[] = { + "None", + "50 Microseconds", + "75 Microseconds", + NULL, + }; + static const char * const header_mode[] = { + "Separate Buffer", + "Joined With 1st Frame", + NULL, + }; + static const char * const multi_slice[] = { + "Single", + "Max Macroblocks", + "Max Bytes", + NULL, + }; + static const char * const entropy_mode[] = { + "CAVLC", + "CABAC", + NULL, + }; + static const char * const mpeg_h264_level[] = { + "1", + "1b", + "1.1", + "1.2", + "1.3", + "2", + "2.1", + "2.2", + "3", + "3.1", + "3.2", + "4", + "4.1", + "4.2", + "5", + "5.1", + "5.2", + "6.0", + "6.1", + "6.2", + NULL, + }; + static const char * const h264_loop_filter[] = { + "Enabled", + "Disabled", + "Disabled at Slice Boundary", + NULL, + }; + static const char * const h264_profile[] = { + "Baseline", + "Constrained Baseline", + "Main", + "Extended", + "High", + "High 10", + "High 422", + "High 444 Predictive", + "High 10 Intra", + "High 422 Intra", + "High 444 Intra", + "CAVLC 444 Intra", + "Scalable Baseline", + "Scalable High", + "Scalable High Intra", + "Stereo High", + "Multiview High", + "Constrained High", + NULL, + }; + static const char * const vui_sar_idc[] = { + "Unspecified", + "1:1", + "12:11", + "10:11", + "16:11", + "40:33", + "24:11", + "20:11", + "32:11", + "80:33", + "18:11", + "15:11", + "64:33", + "160:99", + "4:3", + "3:2", + "2:1", + "Extended SAR", + NULL, + }; + static const char * const h264_fp_arrangement_type[] = { + "Checkerboard", + "Column", + "Row", + "Side by Side", + "Top Bottom", + "Temporal", + NULL, + }; + static const char * const h264_fmo_map_type[] = { + "Interleaved Slices", + "Scattered Slices", + "Foreground with Leftover", + "Box Out", + "Raster Scan", + "Wipe Scan", + "Explicit", + NULL, + }; + static const char * const h264_decode_mode[] = { + "Slice-Based", + "Frame-Based", + NULL, + }; + static const char * const h264_start_code[] = { + "No Start Code", + "Annex B Start Code", + NULL, + }; + static const char * const h264_hierarchical_coding_type[] = { + "Hier Coding B", + "Hier Coding P", + NULL, + }; + static const char * const mpeg_mpeg2_level[] = { + "Low", + "Main", + "High 1440", + "High", + NULL, + }; + static const char * const mpeg2_profile[] = { + "Simple", + "Main", + "SNR Scalable", + "Spatially Scalable", + "High", + NULL, + }; + static const char * const mpeg_mpeg4_level[] = { + "0", + "0b", + "1", + "2", + "3", + "3b", + "4", + "5", + NULL, + }; + static const char * const mpeg4_profile[] = { + "Simple", + "Advanced Simple", + "Core", + "Simple Scalable", + "Advanced Coding Efficiency", + NULL, + }; + + static const char * const vpx_golden_frame_sel[] = { + "Use Previous Frame", + "Use Previous Specific Frame", + NULL, + }; + static const char * const vp8_profile[] = { + "0", + "1", + "2", + "3", + NULL, + }; + static const char * const vp9_profile[] = { + "0", + "1", + "2", + "3", + NULL, + }; + static const char * const vp9_level[] = { + "1", + "1.1", + "2", + "2.1", + "3", + "3.1", + "4", + "4.1", + "5", + "5.1", + "5.2", + "6", + "6.1", + "6.2", + NULL, + }; + + static const char * const flash_led_mode[] = { + "Off", + "Flash", + "Torch", + NULL, + }; + static const char * const flash_strobe_source[] = { + "Software", + "External", + NULL, + }; + + static const char * const jpeg_chroma_subsampling[] = { + "4:4:4", + "4:2:2", + "4:2:0", + "4:1:1", + "4:1:0", + "Gray", + NULL, + }; + static const char * const dv_tx_mode[] = { + "DVI-D", + "HDMI", + NULL, + }; + static const char * const dv_rgb_range[] = { + "Automatic", + "RGB Limited Range (16-235)", + "RGB Full Range (0-255)", + NULL, + }; + static const char * const dv_it_content_type[] = { + "Graphics", + "Photo", + "Cinema", + "Game", + "No IT Content", + NULL, + }; + static const char * const detect_md_mode[] = { + "Disabled", + "Global", + "Threshold Grid", + "Region Grid", + NULL, + }; + + static const char * const hevc_profile[] = { + "Main", + "Main Still Picture", + "Main 10", + NULL, + }; + static const char * const hevc_level[] = { + "1", + "2", + "2.1", + "3", + "3.1", + "4", + "4.1", + "5", + "5.1", + "5.2", + "6", + "6.1", + "6.2", + NULL, + }; + static const char * const hevc_hierarchial_coding_type[] = { + "B", + "P", + NULL, + }; + static const char * const hevc_refresh_type[] = { + "None", + "CRA", + "IDR", + NULL, + }; + static const char * const hevc_size_of_length_field[] = { + "0", + "1", + "2", + "4", + NULL, + }; + static const char * const hevc_tier[] = { + "Main", + "High", + NULL, + }; + static const char * const hevc_loop_filter_mode[] = { + "Disabled", + "Enabled", + "Disabled at slice boundary", + "NULL", + }; + static const char * const hevc_decode_mode[] = { + "Slice-Based", + "Frame-Based", + NULL, + }; + static const char * const hevc_start_code[] = { + "No Start Code", + "Annex B Start Code", + NULL, + }; + static const char * const camera_orientation[] = { + "Front", + "Back", + "External", + NULL, + }; + static const char * const mpeg_video_frame_skip[] = { + "Disabled", + "Level Limit", + "VBV/CPB Limit", + NULL, + }; + + switch (id) { + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + return mpeg_audio_sampling_freq; + case V4L2_CID_MPEG_AUDIO_ENCODING: + return mpeg_audio_encoding; + case V4L2_CID_MPEG_AUDIO_L1_BITRATE: + return mpeg_audio_l1_bitrate; + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + return mpeg_audio_l2_bitrate; + case V4L2_CID_MPEG_AUDIO_L3_BITRATE: + return mpeg_audio_l3_bitrate; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + return mpeg_audio_ac3_bitrate; + case V4L2_CID_MPEG_AUDIO_MODE: + return mpeg_audio_mode; + case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: + return mpeg_audio_mode_extension; + case V4L2_CID_MPEG_AUDIO_EMPHASIS: + return mpeg_audio_emphasis; + case V4L2_CID_MPEG_AUDIO_CRC: + return mpeg_audio_crc; + case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: + case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: + return mpeg_audio_dec_playback; + case V4L2_CID_MPEG_VIDEO_ENCODING: + return mpeg_video_encoding; + case V4L2_CID_MPEG_VIDEO_ASPECT: + return mpeg_video_aspect; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + return mpeg_video_bitrate_mode; + case V4L2_CID_MPEG_STREAM_TYPE: + return mpeg_stream_type; + case V4L2_CID_MPEG_STREAM_VBI_FMT: + return mpeg_stream_vbi_fmt; + case V4L2_CID_POWER_LINE_FREQUENCY: + return camera_power_line_frequency; + case V4L2_CID_EXPOSURE_AUTO: + return camera_exposure_auto; + case V4L2_CID_EXPOSURE_METERING: + return camera_exposure_metering; + case V4L2_CID_AUTO_FOCUS_RANGE: + return camera_auto_focus_range; + case V4L2_CID_COLORFX: + return colorfx; + case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: + return auto_n_preset_white_balance; + case V4L2_CID_ISO_SENSITIVITY_AUTO: + return camera_iso_sensitivity_auto; + case V4L2_CID_SCENE_MODE: + return scene_mode; + case V4L2_CID_TUNE_PREEMPHASIS: + return tune_emphasis; + case V4L2_CID_TUNE_DEEMPHASIS: + return tune_emphasis; + case V4L2_CID_FLASH_LED_MODE: + return flash_led_mode; + case V4L2_CID_FLASH_STROBE_SOURCE: + return flash_strobe_source; + case V4L2_CID_MPEG_VIDEO_HEADER_MODE: + return header_mode; + case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: + return mpeg_video_frame_skip; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: + return multi_slice; + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + return entropy_mode; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + return mpeg_h264_level; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: + return h264_loop_filter; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + return h264_profile; + case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: + return vui_sar_idc; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: + return h264_fp_arrangement_type; + case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: + return h264_fmo_map_type; + case V4L2_CID_STATELESS_H264_DECODE_MODE: + return h264_decode_mode; + case V4L2_CID_STATELESS_H264_START_CODE: + return h264_start_code; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: + return h264_hierarchical_coding_type; + case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: + return mpeg_mpeg2_level; + case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: + return mpeg2_profile; + case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: + return mpeg_mpeg4_level; + case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: + return mpeg4_profile; + case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: + return vpx_golden_frame_sel; + case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: + return vp8_profile; + case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: + return vp9_profile; + case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: + return vp9_level; + case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: + return jpeg_chroma_subsampling; + case V4L2_CID_DV_TX_MODE: + return dv_tx_mode; + case V4L2_CID_DV_TX_RGB_RANGE: + case V4L2_CID_DV_RX_RGB_RANGE: + return dv_rgb_range; + case V4L2_CID_DV_TX_IT_CONTENT_TYPE: + case V4L2_CID_DV_RX_IT_CONTENT_TYPE: + return dv_it_content_type; + case V4L2_CID_DETECT_MD_MODE: + return detect_md_mode; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + return hevc_profile; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + return hevc_level; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: + return hevc_hierarchial_coding_type; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: + return hevc_refresh_type; + case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: + return hevc_size_of_length_field; + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: + return hevc_tier; + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: + return hevc_loop_filter_mode; + case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: + return hevc_decode_mode; + case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: + return hevc_start_code; + case V4L2_CID_CAMERA_ORIENTATION: + return camera_orientation; + default: + return NULL; + } +} +EXPORT_SYMBOL(v4l2_ctrl_get_menu); + +#define __v4l2_qmenu_int_len(arr, len) ({ *(len) = ARRAY_SIZE(arr); (arr); }) +/* + * Returns NULL or an s64 type array containing the menu for given + * control ID. The total number of the menu items is returned in @len. + */ +const s64 *v4l2_ctrl_get_int_menu(u32 id, u32 *len) +{ + static const s64 qmenu_int_vpx_num_partitions[] = { + 1, 2, 4, 8, + }; + + static const s64 qmenu_int_vpx_num_ref_frames[] = { + 1, 2, 3, + }; + + switch (id) { + case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: + return __v4l2_qmenu_int_len(qmenu_int_vpx_num_partitions, len); + case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES: + return __v4l2_qmenu_int_len(qmenu_int_vpx_num_ref_frames, len); + default: + *len = 0; + return NULL; + } +} +EXPORT_SYMBOL(v4l2_ctrl_get_int_menu); + +/* Return the control name. */ +const char *v4l2_ctrl_get_name(u32 id) +{ + switch (id) { + /* USER controls */ + /* Keep the order of the 'case's the same as in v4l2-controls.h! */ + case V4L2_CID_USER_CLASS: return "User Controls"; + case V4L2_CID_BRIGHTNESS: return "Brightness"; + case V4L2_CID_CONTRAST: return "Contrast"; + case V4L2_CID_SATURATION: return "Saturation"; + case V4L2_CID_HUE: return "Hue"; + case V4L2_CID_AUDIO_VOLUME: return "Volume"; + case V4L2_CID_AUDIO_BALANCE: return "Balance"; + case V4L2_CID_AUDIO_BASS: return "Bass"; + case V4L2_CID_AUDIO_TREBLE: return "Treble"; + case V4L2_CID_AUDIO_MUTE: return "Mute"; + case V4L2_CID_AUDIO_LOUDNESS: return "Loudness"; + case V4L2_CID_BLACK_LEVEL: return "Black Level"; + case V4L2_CID_AUTO_WHITE_BALANCE: return "White Balance, Automatic"; + case V4L2_CID_DO_WHITE_BALANCE: return "Do White Balance"; + case V4L2_CID_RED_BALANCE: return "Red Balance"; + case V4L2_CID_BLUE_BALANCE: return "Blue Balance"; + case V4L2_CID_GAMMA: return "Gamma"; + case V4L2_CID_EXPOSURE: return "Exposure"; + case V4L2_CID_AUTOGAIN: return "Gain, Automatic"; + case V4L2_CID_GAIN: return "Gain"; + case V4L2_CID_HFLIP: return "Horizontal Flip"; + case V4L2_CID_VFLIP: return "Vertical Flip"; + case V4L2_CID_POWER_LINE_FREQUENCY: return "Power Line Frequency"; + case V4L2_CID_HUE_AUTO: return "Hue, Automatic"; + case V4L2_CID_WHITE_BALANCE_TEMPERATURE: return "White Balance Temperature"; + case V4L2_CID_SHARPNESS: return "Sharpness"; + case V4L2_CID_BACKLIGHT_COMPENSATION: return "Backlight Compensation"; + case V4L2_CID_CHROMA_AGC: return "Chroma AGC"; + case V4L2_CID_COLOR_KILLER: return "Color Killer"; + case V4L2_CID_COLORFX: return "Color Effects"; + case V4L2_CID_AUTOBRIGHTNESS: return "Brightness, Automatic"; + case V4L2_CID_BAND_STOP_FILTER: return "Band-Stop Filter"; + case V4L2_CID_ROTATE: return "Rotate"; + case V4L2_CID_BG_COLOR: return "Background Color"; + case V4L2_CID_CHROMA_GAIN: return "Chroma Gain"; + case V4L2_CID_ILLUMINATORS_1: return "Illuminator 1"; + case V4L2_CID_ILLUMINATORS_2: return "Illuminator 2"; + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: return "Min Number of Capture Buffers"; + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: return "Min Number of Output Buffers"; + case V4L2_CID_ALPHA_COMPONENT: return "Alpha Component"; + case V4L2_CID_COLORFX_CBCR: return "Color Effects, CbCr"; + + /* + * Codec controls + * + * The MPEG controls are applicable to all codec controls + * and the 'MPEG' part of the define is historical. + * + * Keep the order of the 'case's the same as in videodev2.h! + */ + case V4L2_CID_CODEC_CLASS: return "Codec Controls"; + case V4L2_CID_MPEG_STREAM_TYPE: return "Stream Type"; + case V4L2_CID_MPEG_STREAM_PID_PMT: return "Stream PMT Program ID"; + case V4L2_CID_MPEG_STREAM_PID_AUDIO: return "Stream Audio Program ID"; + case V4L2_CID_MPEG_STREAM_PID_VIDEO: return "Stream Video Program ID"; + case V4L2_CID_MPEG_STREAM_PID_PCR: return "Stream PCR Program ID"; + case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio ID"; + case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID"; + case V4L2_CID_MPEG_STREAM_VBI_FMT: return "Stream VBI Format"; + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency"; + case V4L2_CID_MPEG_AUDIO_ENCODING: return "Audio Encoding"; + case V4L2_CID_MPEG_AUDIO_L1_BITRATE: return "Audio Layer I Bitrate"; + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return "Audio Layer II Bitrate"; + case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return "Audio Layer III Bitrate"; + case V4L2_CID_MPEG_AUDIO_MODE: return "Audio Stereo Mode"; + case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension"; + case V4L2_CID_MPEG_AUDIO_EMPHASIS: return "Audio Emphasis"; + case V4L2_CID_MPEG_AUDIO_CRC: return "Audio CRC"; + case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute"; + case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate"; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate"; + case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: return "Audio Playback"; + case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: return "Audio Multilingual Playback"; + case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding"; + case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect"; + case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames"; + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: return "Video GOP Size"; + case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: return "Video GOP Closure"; + case V4L2_CID_MPEG_VIDEO_PULLDOWN: return "Video Pulldown"; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: return "Video Bitrate Mode"; + case V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY: return "Constant Quality"; + case V4L2_CID_MPEG_VIDEO_BITRATE: return "Video Bitrate"; + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: return "Video Peak Bitrate"; + case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation"; + case V4L2_CID_MPEG_VIDEO_MUTE: return "Video Mute"; + case V4L2_CID_MPEG_VIDEO_MUTE_YUV: return "Video Mute YUV"; + case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: return "Decoder Slice Interface"; + case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: return "MPEG4 Loop Filter Enable"; + case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: return "Number of Intra Refresh MBs"; + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: return "Frame Level Rate Control Enable"; + case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: return "H264 MB Level Rate Control"; + case V4L2_CID_MPEG_VIDEO_HEADER_MODE: return "Sequence Header Mode"; + case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC: return "Max Number of Reference Pics"; + case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: return "Frame Skip Mode"; + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: return "Display Delay"; + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: return "Display Delay Enable"; + case V4L2_CID_MPEG_VIDEO_AU_DELIMITER: return "Generate Access Unit Delimiters"; + case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP: return "H263 I-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: return "H263 P-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: return "H263 B-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_H263_MIN_QP: return "H263 Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_H263_MAX_QP: return "H263 Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: return "H264 I-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: return "H264 P-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: return "H264 B-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: return "H264 Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: return "H264 Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: return "H264 8x8 Transform Enable"; + case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: return "H264 CPB Buffer Size"; + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: return "H264 Entropy Mode"; + case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: return "H264 I-Frame Period"; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: return "H264 Level"; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: return "H264 Loop Filter Alpha Offset"; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: return "H264 Loop Filter Beta Offset"; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: return "H264 Loop Filter Mode"; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: return "H264 Profile"; + case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT: return "Vertical Size of SAR"; + case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH: return "Horizontal Size of SAR"; + case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: return "Aspect Ratio VUI Enable"; + case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: return "VUI Aspect Ratio IDC"; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING: return "H264 Enable Frame Packing SEI"; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0: return "H264 Set Curr. Frame as Frame0"; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: return "H264 FP Arrangement Type"; + case V4L2_CID_MPEG_VIDEO_H264_FMO: return "H264 Flexible MB Ordering"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: return "H264 Map Type for FMO"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP: return "H264 FMO Number of Slice Groups"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION: return "H264 FMO Direction of Change"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE: return "H264 FMO Size of 1st Slice Grp"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH: return "H264 FMO No. of Consecutive MBs"; + case V4L2_CID_MPEG_VIDEO_H264_ASO: return "H264 Arbitrary Slice Ordering"; + case V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER: return "H264 ASO Slice Order"; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING: return "Enable H264 Hierarchical Coding"; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: return "H264 Hierarchical Coding Type"; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER:return "H264 Number of HC Layers"; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP: + return "H264 Set QP Value for HC Layers"; + case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: + return "H264 Constrained Intra Pred"; + case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: return "H264 Chroma QP Index Offset"; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP: return "H264 I-Frame Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP: return "H264 I-Frame Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP: return "H264 P-Frame Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP: return "H264 P-Frame Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP: return "H264 B-Frame Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP: return "H264 B-Frame Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR: return "H264 Hierarchical Lay 0 Bitrate"; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR: return "H264 Hierarchical Lay 1 Bitrate"; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR: return "H264 Hierarchical Lay 2 Bitrate"; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR: return "H264 Hierarchical Lay 3 Bitrate"; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR: return "H264 Hierarchical Lay 4 Bitrate"; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR: return "H264 Hierarchical Lay 5 Bitrate"; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L6_BR: return "H264 Hierarchical Lay 6 Bitrate"; + case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: return "MPEG2 Level"; + case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: return "MPEG2 Profile"; + case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: return "MPEG4 P-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: return "MPEG4 B-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP: return "MPEG4 Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP: return "MPEG4 Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: return "MPEG4 Level"; + case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: return "MPEG4 Profile"; + case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL: return "Quarter Pixel Search Enable"; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: return "Maximum Bytes in a Slice"; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: return "Number of MBs in a Slice"; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: return "Slice Partitioning Method"; + case V4L2_CID_MPEG_VIDEO_VBV_SIZE: return "VBV Buffer Size"; + case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS"; + case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count"; + case V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR: return "Video Decoder Conceal Color"; + case V4L2_CID_MPEG_VIDEO_VBV_DELAY: return "Initial Delay for VBV Control"; + case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: return "Horizontal MV Search Range"; + case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: return "Vertical MV Search Range"; + case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: return "Repeat Sequence Header"; + case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: return "Force Key Frame"; + case V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID: return "Base Layer Priority ID"; + case V4L2_CID_MPEG_VIDEO_LTR_COUNT: return "LTR Count"; + case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX: return "Frame LTR Index"; + case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES: return "Use LTR Frames"; + case V4L2_CID_FWHT_I_FRAME_QP: return "FWHT I-Frame QP Value"; + case V4L2_CID_FWHT_P_FRAME_QP: return "FWHT P-Frame QP Value"; + + /* VPX controls */ + case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: return "VPX Number of Partitions"; + case V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4: return "VPX Intra Mode Decision Disable"; + case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES: return "VPX No. of Refs for P Frame"; + case V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL: return "VPX Loop Filter Level Range"; + case V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS: return "VPX Deblocking Effect Control"; + case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD: return "VPX Golden Frame Refresh Period"; + case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: return "VPX Golden Frame Indicator"; + case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP: return "VPX Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP: return "VPX Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP: return "VPX I-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: return "VPX P-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: return "VP8 Profile"; + case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: return "VP9 Profile"; + case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: return "VP9 Level"; + + /* HEVC controls */ + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: return "HEVC I-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: return "HEVC P-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: return "HEVC B-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: return "HEVC Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: return "HEVC Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP: return "HEVC I-Frame Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP: return "HEVC I-Frame Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP: return "HEVC P-Frame Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP: return "HEVC P-Frame Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP: return "HEVC B-Frame Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP: return "HEVC B-Frame Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: return "HEVC Profile"; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: return "HEVC Level"; + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: return "HEVC Tier"; + case V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION: return "HEVC Frame Rate Resolution"; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH: return "HEVC Maximum Coding Unit Depth"; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: return "HEVC Refresh Type"; + case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: return "HEVC Constant Intra Prediction"; + case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU: return "HEVC Lossless Encoding"; + case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT: return "HEVC Wavefront"; + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: return "HEVC Loop Filter"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP: return "HEVC QP Values"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: return "HEVC Hierarchical Coding Type"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER: return "HEVC Hierarchical Coding Layer"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP: return "HEVC Hierarchical Layer 0 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP: return "HEVC Hierarchical Layer 1 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP: return "HEVC Hierarchical Layer 2 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP: return "HEVC Hierarchical Layer 3 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP: return "HEVC Hierarchical Layer 4 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP: return "HEVC Hierarchical Layer 5 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP: return "HEVC Hierarchical Layer 6 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR: return "HEVC Hierarchical Lay 0 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR: return "HEVC Hierarchical Lay 1 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR: return "HEVC Hierarchical Lay 2 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR: return "HEVC Hierarchical Lay 3 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR: return "HEVC Hierarchical Lay 4 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: return "HEVC Hierarchical Lay 5 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR: return "HEVC Hierarchical Lay 6 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB: return "HEVC General PB"; + case V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID: return "HEVC Temporal ID"; + case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: return "HEVC Strong Intra Smoothing"; + case V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT: return "HEVC Intra PU Split"; + case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: return "HEVC TMV Prediction"; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1: return "HEVC Max Num of Candidate MVs"; + case V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE: return "HEVC ENC Without Startcode"; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: return "HEVC Num of I-Frame b/w 2 IDR"; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: return "HEVC Loop Filter Beta Offset"; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: return "HEVC Loop Filter TC Offset"; + case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: return "HEVC Size of Length Field"; + case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES: return "Reference Frames for a P-Frame"; + case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: return "Prepend SPS and PPS to IDR"; + case V4L2_CID_MPEG_VIDEO_HEVC_SPS: return "HEVC Sequence Parameter Set"; + case V4L2_CID_MPEG_VIDEO_HEVC_PPS: return "HEVC Picture Parameter Set"; + case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: return "HEVC Slice Parameters"; + case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: return "HEVC Decode Mode"; + case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: return "HEVC Start Code"; + + /* CAMERA controls */ + /* Keep the order of the 'case's the same as in v4l2-controls.h! */ + case V4L2_CID_CAMERA_CLASS: return "Camera Controls"; + case V4L2_CID_EXPOSURE_AUTO: return "Auto Exposure"; + case V4L2_CID_EXPOSURE_ABSOLUTE: return "Exposure Time, Absolute"; + case V4L2_CID_EXPOSURE_AUTO_PRIORITY: return "Exposure, Dynamic Framerate"; + case V4L2_CID_PAN_RELATIVE: return "Pan, Relative"; + case V4L2_CID_TILT_RELATIVE: return "Tilt, Relative"; + case V4L2_CID_PAN_RESET: return "Pan, Reset"; + case V4L2_CID_TILT_RESET: return "Tilt, Reset"; + case V4L2_CID_PAN_ABSOLUTE: return "Pan, Absolute"; + case V4L2_CID_TILT_ABSOLUTE: return "Tilt, Absolute"; + case V4L2_CID_FOCUS_ABSOLUTE: return "Focus, Absolute"; + case V4L2_CID_FOCUS_RELATIVE: return "Focus, Relative"; + case V4L2_CID_FOCUS_AUTO: return "Focus, Automatic Continuous"; + case V4L2_CID_ZOOM_ABSOLUTE: return "Zoom, Absolute"; + case V4L2_CID_ZOOM_RELATIVE: return "Zoom, Relative"; + case V4L2_CID_ZOOM_CONTINUOUS: return "Zoom, Continuous"; + case V4L2_CID_PRIVACY: return "Privacy"; + case V4L2_CID_IRIS_ABSOLUTE: return "Iris, Absolute"; + case V4L2_CID_IRIS_RELATIVE: return "Iris, Relative"; + case V4L2_CID_AUTO_EXPOSURE_BIAS: return "Auto Exposure, Bias"; + case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: return "White Balance, Auto & Preset"; + case V4L2_CID_WIDE_DYNAMIC_RANGE: return "Wide Dynamic Range"; + case V4L2_CID_IMAGE_STABILIZATION: return "Image Stabilization"; + case V4L2_CID_ISO_SENSITIVITY: return "ISO Sensitivity"; + case V4L2_CID_ISO_SENSITIVITY_AUTO: return "ISO Sensitivity, Auto"; + case V4L2_CID_EXPOSURE_METERING: return "Exposure, Metering Mode"; + case V4L2_CID_SCENE_MODE: return "Scene Mode"; + case V4L2_CID_3A_LOCK: return "3A Lock"; + case V4L2_CID_AUTO_FOCUS_START: return "Auto Focus, Start"; + case V4L2_CID_AUTO_FOCUS_STOP: return "Auto Focus, Stop"; + case V4L2_CID_AUTO_FOCUS_STATUS: return "Auto Focus, Status"; + case V4L2_CID_AUTO_FOCUS_RANGE: return "Auto Focus, Range"; + case V4L2_CID_PAN_SPEED: return "Pan, Speed"; + case V4L2_CID_TILT_SPEED: return "Tilt, Speed"; + case V4L2_CID_UNIT_CELL_SIZE: return "Unit Cell Size"; + case V4L2_CID_CAMERA_ORIENTATION: return "Camera Orientation"; + case V4L2_CID_CAMERA_SENSOR_ROTATION: return "Camera Sensor Rotation"; + + /* FM Radio Modulator controls */ + /* Keep the order of the 'case's the same as in v4l2-controls.h! */ + case V4L2_CID_FM_TX_CLASS: return "FM Radio Modulator Controls"; + case V4L2_CID_RDS_TX_DEVIATION: return "RDS Signal Deviation"; + case V4L2_CID_RDS_TX_PI: return "RDS Program ID"; + case V4L2_CID_RDS_TX_PTY: return "RDS Program Type"; + case V4L2_CID_RDS_TX_PS_NAME: return "RDS PS Name"; + case V4L2_CID_RDS_TX_RADIO_TEXT: return "RDS Radio Text"; + case V4L2_CID_RDS_TX_MONO_STEREO: return "RDS Stereo"; + case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD: return "RDS Artificial Head"; + case V4L2_CID_RDS_TX_COMPRESSED: return "RDS Compressed"; + case V4L2_CID_RDS_TX_DYNAMIC_PTY: return "RDS Dynamic PTY"; + case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT: return "RDS Traffic Announcement"; + case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM: return "RDS Traffic Program"; + case V4L2_CID_RDS_TX_MUSIC_SPEECH: return "RDS Music"; + case V4L2_CID_RDS_TX_ALT_FREQS_ENABLE: return "RDS Enable Alt Frequencies"; + case V4L2_CID_RDS_TX_ALT_FREQS: return "RDS Alternate Frequencies"; + case V4L2_CID_AUDIO_LIMITER_ENABLED: return "Audio Limiter Feature Enabled"; + case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time"; + case V4L2_CID_AUDIO_LIMITER_DEVIATION: return "Audio Limiter Deviation"; + case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Enabled"; + case V4L2_CID_AUDIO_COMPRESSION_GAIN: return "Audio Compression Gain"; + case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold"; + case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time"; + case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: return "Audio Compression Release Time"; + case V4L2_CID_PILOT_TONE_ENABLED: return "Pilot Tone Feature Enabled"; + case V4L2_CID_PILOT_TONE_DEVIATION: return "Pilot Tone Deviation"; + case V4L2_CID_PILOT_TONE_FREQUENCY: return "Pilot Tone Frequency"; + case V4L2_CID_TUNE_PREEMPHASIS: return "Pre-Emphasis"; + case V4L2_CID_TUNE_POWER_LEVEL: return "Tune Power Level"; + case V4L2_CID_TUNE_ANTENNA_CAPACITOR: return "Tune Antenna Capacitor"; + + /* Flash controls */ + /* Keep the order of the 'case's the same as in v4l2-controls.h! */ + case V4L2_CID_FLASH_CLASS: return "Flash Controls"; + case V4L2_CID_FLASH_LED_MODE: return "LED Mode"; + case V4L2_CID_FLASH_STROBE_SOURCE: return "Strobe Source"; + case V4L2_CID_FLASH_STROBE: return "Strobe"; + case V4L2_CID_FLASH_STROBE_STOP: return "Stop Strobe"; + case V4L2_CID_FLASH_STROBE_STATUS: return "Strobe Status"; + case V4L2_CID_FLASH_TIMEOUT: return "Strobe Timeout"; + case V4L2_CID_FLASH_INTENSITY: return "Intensity, Flash Mode"; + case V4L2_CID_FLASH_TORCH_INTENSITY: return "Intensity, Torch Mode"; + case V4L2_CID_FLASH_INDICATOR_INTENSITY: return "Intensity, Indicator"; + case V4L2_CID_FLASH_FAULT: return "Faults"; + case V4L2_CID_FLASH_CHARGE: return "Charge"; + case V4L2_CID_FLASH_READY: return "Ready to Strobe"; + + /* JPEG encoder controls */ + /* Keep the order of the 'case's the same as in v4l2-controls.h! */ + case V4L2_CID_JPEG_CLASS: return "JPEG Compression Controls"; + case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: return "Chroma Subsampling"; + case V4L2_CID_JPEG_RESTART_INTERVAL: return "Restart Interval"; + case V4L2_CID_JPEG_COMPRESSION_QUALITY: return "Compression Quality"; + case V4L2_CID_JPEG_ACTIVE_MARKER: return "Active Markers"; + + /* Image source controls */ + /* Keep the order of the 'case's the same as in v4l2-controls.h! */ + case V4L2_CID_IMAGE_SOURCE_CLASS: return "Image Source Controls"; + case V4L2_CID_VBLANK: return "Vertical Blanking"; + case V4L2_CID_HBLANK: return "Horizontal Blanking"; + case V4L2_CID_ANALOGUE_GAIN: return "Analogue Gain"; + case V4L2_CID_TEST_PATTERN_RED: return "Red Pixel Value"; + case V4L2_CID_TEST_PATTERN_GREENR: return "Green (Red) Pixel Value"; + case V4L2_CID_TEST_PATTERN_BLUE: return "Blue Pixel Value"; + case V4L2_CID_TEST_PATTERN_GREENB: return "Green (Blue) Pixel Value"; + + /* Image processing controls */ + /* Keep the order of the 'case's the same as in v4l2-controls.h! */ + case V4L2_CID_IMAGE_PROC_CLASS: return "Image Processing Controls"; + case V4L2_CID_LINK_FREQ: return "Link Frequency"; + case V4L2_CID_PIXEL_RATE: return "Pixel Rate"; + case V4L2_CID_TEST_PATTERN: return "Test Pattern"; + case V4L2_CID_DEINTERLACING_MODE: return "Deinterlacing Mode"; + case V4L2_CID_DIGITAL_GAIN: return "Digital Gain"; + + /* DV controls */ + /* Keep the order of the 'case's the same as in v4l2-controls.h! */ + case V4L2_CID_DV_CLASS: return "Digital Video Controls"; + case V4L2_CID_DV_TX_HOTPLUG: return "Hotplug Present"; + case V4L2_CID_DV_TX_RXSENSE: return "RxSense Present"; + case V4L2_CID_DV_TX_EDID_PRESENT: return "EDID Present"; + case V4L2_CID_DV_TX_MODE: return "Transmit Mode"; + case V4L2_CID_DV_TX_RGB_RANGE: return "Tx RGB Quantization Range"; + case V4L2_CID_DV_TX_IT_CONTENT_TYPE: return "Tx IT Content Type"; + case V4L2_CID_DV_RX_POWER_PRESENT: return "Power Present"; + case V4L2_CID_DV_RX_RGB_RANGE: return "Rx RGB Quantization Range"; + case V4L2_CID_DV_RX_IT_CONTENT_TYPE: return "Rx IT Content Type"; + + case V4L2_CID_FM_RX_CLASS: return "FM Radio Receiver Controls"; + case V4L2_CID_TUNE_DEEMPHASIS: return "De-Emphasis"; + case V4L2_CID_RDS_RECEPTION: return "RDS Reception"; + case V4L2_CID_RF_TUNER_CLASS: return "RF Tuner Controls"; + case V4L2_CID_RF_TUNER_RF_GAIN: return "RF Gain"; + case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: return "LNA Gain, Auto"; + case V4L2_CID_RF_TUNER_LNA_GAIN: return "LNA Gain"; + case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: return "Mixer Gain, Auto"; + case V4L2_CID_RF_TUNER_MIXER_GAIN: return "Mixer Gain"; + case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: return "IF Gain, Auto"; + case V4L2_CID_RF_TUNER_IF_GAIN: return "IF Gain"; + case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: return "Bandwidth, Auto"; + case V4L2_CID_RF_TUNER_BANDWIDTH: return "Bandwidth"; + case V4L2_CID_RF_TUNER_PLL_LOCK: return "PLL Lock"; + case V4L2_CID_RDS_RX_PTY: return "RDS Program Type"; + case V4L2_CID_RDS_RX_PS_NAME: return "RDS PS Name"; + case V4L2_CID_RDS_RX_RADIO_TEXT: return "RDS Radio Text"; + case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT: return "RDS Traffic Announcement"; + case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM: return "RDS Traffic Program"; + case V4L2_CID_RDS_RX_MUSIC_SPEECH: return "RDS Music"; + + /* Detection controls */ + /* Keep the order of the 'case's the same as in v4l2-controls.h! */ + case V4L2_CID_DETECT_CLASS: return "Detection Controls"; + case V4L2_CID_DETECT_MD_MODE: return "Motion Detection Mode"; + case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD: return "MD Global Threshold"; + case V4L2_CID_DETECT_MD_THRESHOLD_GRID: return "MD Threshold Grid"; + case V4L2_CID_DETECT_MD_REGION_GRID: return "MD Region Grid"; + + /* Stateless Codec controls */ + /* Keep the order of the 'case's the same as in v4l2-controls.h! */ + case V4L2_CID_CODEC_STATELESS_CLASS: return "Stateless Codec Controls"; + case V4L2_CID_STATELESS_H264_DECODE_MODE: return "H264 Decode Mode"; + case V4L2_CID_STATELESS_H264_START_CODE: return "H264 Start Code"; + case V4L2_CID_STATELESS_H264_SPS: return "H264 Sequence Parameter Set"; + case V4L2_CID_STATELESS_H264_PPS: return "H264 Picture Parameter Set"; + case V4L2_CID_STATELESS_H264_SCALING_MATRIX: return "H264 Scaling Matrix"; + case V4L2_CID_STATELESS_H264_PRED_WEIGHTS: return "H264 Prediction Weight Table"; + case V4L2_CID_STATELESS_H264_SLICE_PARAMS: return "H264 Slice Parameters"; + case V4L2_CID_STATELESS_H264_DECODE_PARAMS: return "H264 Decode Parameters"; + case V4L2_CID_STATELESS_FWHT_PARAMS: return "FWHT Stateless Parameters"; + case V4L2_CID_STATELESS_VP8_FRAME: return "VP8 Frame Parameters"; + case V4L2_CID_STATELESS_MPEG2_SEQUENCE: return "MPEG-2 Sequence Header"; + case V4L2_CID_STATELESS_MPEG2_PICTURE: return "MPEG-2 Picture Header"; + case V4L2_CID_STATELESS_MPEG2_QUANTISATION: return "MPEG-2 Quantisation Matrices"; + + /* Colorimetry controls */ + /* Keep the order of the 'case's the same as in v4l2-controls.h! */ + case V4L2_CID_COLORIMETRY_CLASS: return "Colorimetry Controls"; + case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO: return "HDR10 Content Light Info"; + case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY: return "HDR10 Mastering Display"; + default: + return NULL; + } +} +EXPORT_SYMBOL(v4l2_ctrl_get_name); + +void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, + s64 *min, s64 *max, u64 *step, s64 *def, u32 *flags) +{ + *name = v4l2_ctrl_get_name(id); + *flags = 0; + + switch (id) { + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_LOUDNESS: + case V4L2_CID_AUTO_WHITE_BALANCE: + case V4L2_CID_AUTOGAIN: + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + case V4L2_CID_HUE_AUTO: + case V4L2_CID_CHROMA_AGC: + case V4L2_CID_COLOR_KILLER: + case V4L2_CID_AUTOBRIGHTNESS: + case V4L2_CID_MPEG_AUDIO_MUTE: + case V4L2_CID_MPEG_VIDEO_MUTE: + case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: + case V4L2_CID_MPEG_VIDEO_PULLDOWN: + case V4L2_CID_EXPOSURE_AUTO_PRIORITY: + case V4L2_CID_FOCUS_AUTO: + case V4L2_CID_PRIVACY: + case V4L2_CID_AUDIO_LIMITER_ENABLED: + case V4L2_CID_AUDIO_COMPRESSION_ENABLED: + case V4L2_CID_PILOT_TONE_ENABLED: + case V4L2_CID_ILLUMINATORS_1: + case V4L2_CID_ILLUMINATORS_2: + case V4L2_CID_FLASH_STROBE_STATUS: + case V4L2_CID_FLASH_CHARGE: + case V4L2_CID_FLASH_READY: + case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: + case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: + case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: + case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: + case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: + case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL: + case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: + case V4L2_CID_MPEG_VIDEO_AU_DELIMITER: + case V4L2_CID_WIDE_DYNAMIC_RANGE: + case V4L2_CID_IMAGE_STABILIZATION: + case V4L2_CID_RDS_RECEPTION: + case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: + case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: + case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: + case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: + case V4L2_CID_RF_TUNER_PLL_LOCK: + case V4L2_CID_RDS_TX_MONO_STEREO: + case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD: + case V4L2_CID_RDS_TX_COMPRESSED: + case V4L2_CID_RDS_TX_DYNAMIC_PTY: + case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT: + case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM: + case V4L2_CID_RDS_TX_MUSIC_SPEECH: + case V4L2_CID_RDS_TX_ALT_FREQS_ENABLE: + case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT: + case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM: + case V4L2_CID_RDS_RX_MUSIC_SPEECH: + *type = V4L2_CTRL_TYPE_BOOLEAN; + *min = 0; + *max = *step = 1; + break; + case V4L2_CID_ROTATE: + *type = V4L2_CTRL_TYPE_INTEGER; + *flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + break; + case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: + case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: + *type = V4L2_CTRL_TYPE_INTEGER; + break; + case V4L2_CID_MPEG_VIDEO_LTR_COUNT: + *type = V4L2_CTRL_TYPE_INTEGER; + break; + case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX: + *type = V4L2_CTRL_TYPE_INTEGER; + *flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + break; + case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES: + *type = V4L2_CTRL_TYPE_BITMASK; + *flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + break; + case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: + case V4L2_CID_PAN_RESET: + case V4L2_CID_TILT_RESET: + case V4L2_CID_FLASH_STROBE: + case V4L2_CID_FLASH_STROBE_STOP: + case V4L2_CID_AUTO_FOCUS_START: + case V4L2_CID_AUTO_FOCUS_STOP: + case V4L2_CID_DO_WHITE_BALANCE: + *type = V4L2_CTRL_TYPE_BUTTON; + *flags |= V4L2_CTRL_FLAG_WRITE_ONLY | + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + *min = *max = *step = *def = 0; + break; + case V4L2_CID_POWER_LINE_FREQUENCY: + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + case V4L2_CID_MPEG_AUDIO_ENCODING: + case V4L2_CID_MPEG_AUDIO_L1_BITRATE: + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + case V4L2_CID_MPEG_AUDIO_L3_BITRATE: + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + case V4L2_CID_MPEG_AUDIO_MODE: + case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: + case V4L2_CID_MPEG_AUDIO_EMPHASIS: + case V4L2_CID_MPEG_AUDIO_CRC: + case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: + case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: + case V4L2_CID_MPEG_VIDEO_ENCODING: + case V4L2_CID_MPEG_VIDEO_ASPECT: + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + case V4L2_CID_MPEG_STREAM_TYPE: + case V4L2_CID_MPEG_STREAM_VBI_FMT: + case V4L2_CID_EXPOSURE_AUTO: + case V4L2_CID_AUTO_FOCUS_RANGE: + case V4L2_CID_COLORFX: + case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: + case V4L2_CID_TUNE_PREEMPHASIS: + case V4L2_CID_FLASH_LED_MODE: + case V4L2_CID_FLASH_STROBE_SOURCE: + case V4L2_CID_MPEG_VIDEO_HEADER_MODE: + case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: + case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: + case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: + case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: + case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: + case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: + case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: + case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: + case V4L2_CID_ISO_SENSITIVITY_AUTO: + case V4L2_CID_EXPOSURE_METERING: + case V4L2_CID_SCENE_MODE: + case V4L2_CID_DV_TX_MODE: + case V4L2_CID_DV_TX_RGB_RANGE: + case V4L2_CID_DV_TX_IT_CONTENT_TYPE: + case V4L2_CID_DV_RX_RGB_RANGE: + case V4L2_CID_DV_RX_IT_CONTENT_TYPE: + case V4L2_CID_TEST_PATTERN: + case V4L2_CID_DEINTERLACING_MODE: + case V4L2_CID_TUNE_DEEMPHASIS: + case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: + case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: + case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: + case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: + case V4L2_CID_DETECT_MD_MODE: + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: + case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: + case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: + case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: + case V4L2_CID_STATELESS_H264_DECODE_MODE: + case V4L2_CID_STATELESS_H264_START_CODE: + case V4L2_CID_CAMERA_ORIENTATION: + *type = V4L2_CTRL_TYPE_MENU; + break; + case V4L2_CID_LINK_FREQ: + *type = V4L2_CTRL_TYPE_INTEGER_MENU; + break; + case V4L2_CID_RDS_TX_PS_NAME: + case V4L2_CID_RDS_TX_RADIO_TEXT: + case V4L2_CID_RDS_RX_PS_NAME: + case V4L2_CID_RDS_RX_RADIO_TEXT: + *type = V4L2_CTRL_TYPE_STRING; + break; + case V4L2_CID_ISO_SENSITIVITY: + case V4L2_CID_AUTO_EXPOSURE_BIAS: + case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: + case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES: + *type = V4L2_CTRL_TYPE_INTEGER_MENU; + break; + case V4L2_CID_USER_CLASS: + case V4L2_CID_CAMERA_CLASS: + case V4L2_CID_CODEC_CLASS: + case V4L2_CID_FM_TX_CLASS: + case V4L2_CID_FLASH_CLASS: + case V4L2_CID_JPEG_CLASS: + case V4L2_CID_IMAGE_SOURCE_CLASS: + case V4L2_CID_IMAGE_PROC_CLASS: + case V4L2_CID_DV_CLASS: + case V4L2_CID_FM_RX_CLASS: + case V4L2_CID_RF_TUNER_CLASS: + case V4L2_CID_DETECT_CLASS: + case V4L2_CID_CODEC_STATELESS_CLASS: + case V4L2_CID_COLORIMETRY_CLASS: + *type = V4L2_CTRL_TYPE_CTRL_CLASS; + /* You can neither read nor write these */ + *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY; + *min = *max = *step = *def = 0; + break; + case V4L2_CID_BG_COLOR: + *type = V4L2_CTRL_TYPE_INTEGER; + *step = 1; + *min = 0; + /* Max is calculated as RGB888 that is 2^24 */ + *max = 0xFFFFFF; + break; + case V4L2_CID_FLASH_FAULT: + case V4L2_CID_JPEG_ACTIVE_MARKER: + case V4L2_CID_3A_LOCK: + case V4L2_CID_AUTO_FOCUS_STATUS: + case V4L2_CID_DV_TX_HOTPLUG: + case V4L2_CID_DV_TX_RXSENSE: + case V4L2_CID_DV_TX_EDID_PRESENT: + case V4L2_CID_DV_RX_POWER_PRESENT: + *type = V4L2_CTRL_TYPE_BITMASK; + break; + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: + *type = V4L2_CTRL_TYPE_INTEGER; + *flags |= V4L2_CTRL_FLAG_READ_ONLY; + break; + case V4L2_CID_MPEG_VIDEO_DEC_PTS: + *type = V4L2_CTRL_TYPE_INTEGER64; + *flags |= V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY; + *min = *def = 0; + *max = 0x1ffffffffLL; + *step = 1; + break; + case V4L2_CID_MPEG_VIDEO_DEC_FRAME: + *type = V4L2_CTRL_TYPE_INTEGER64; + *flags |= V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY; + *min = *def = 0; + *max = 0x7fffffffffffffffLL; + *step = 1; + break; + case V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR: + *type = V4L2_CTRL_TYPE_INTEGER64; + *min = 0; + /* default for 8 bit black, luma is 16, chroma is 128 */ + *def = 0x8000800010LL; + *max = 0xffffffffffffLL; + *step = 1; + break; + case V4L2_CID_PIXEL_RATE: + *type = V4L2_CTRL_TYPE_INTEGER64; + *flags |= V4L2_CTRL_FLAG_READ_ONLY; + break; + case V4L2_CID_DETECT_MD_REGION_GRID: + *type = V4L2_CTRL_TYPE_U8; + break; + case V4L2_CID_DETECT_MD_THRESHOLD_GRID: + *type = V4L2_CTRL_TYPE_U16; + break; + case V4L2_CID_RDS_TX_ALT_FREQS: + *type = V4L2_CTRL_TYPE_U32; + break; + case V4L2_CID_STATELESS_MPEG2_SEQUENCE: + *type = V4L2_CTRL_TYPE_MPEG2_SEQUENCE; + break; + case V4L2_CID_STATELESS_MPEG2_PICTURE: + *type = V4L2_CTRL_TYPE_MPEG2_PICTURE; + break; + case V4L2_CID_STATELESS_MPEG2_QUANTISATION: + *type = V4L2_CTRL_TYPE_MPEG2_QUANTISATION; + break; + case V4L2_CID_STATELESS_FWHT_PARAMS: + *type = V4L2_CTRL_TYPE_FWHT_PARAMS; + break; + case V4L2_CID_STATELESS_H264_SPS: + *type = V4L2_CTRL_TYPE_H264_SPS; + break; + case V4L2_CID_STATELESS_H264_PPS: + *type = V4L2_CTRL_TYPE_H264_PPS; + break; + case V4L2_CID_STATELESS_H264_SCALING_MATRIX: + *type = V4L2_CTRL_TYPE_H264_SCALING_MATRIX; + break; + case V4L2_CID_STATELESS_H264_SLICE_PARAMS: + *type = V4L2_CTRL_TYPE_H264_SLICE_PARAMS; + break; + case V4L2_CID_STATELESS_H264_DECODE_PARAMS: + *type = V4L2_CTRL_TYPE_H264_DECODE_PARAMS; + break; + case V4L2_CID_STATELESS_H264_PRED_WEIGHTS: + *type = V4L2_CTRL_TYPE_H264_PRED_WEIGHTS; + break; + case V4L2_CID_STATELESS_VP8_FRAME: + *type = V4L2_CTRL_TYPE_VP8_FRAME; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_SPS: + *type = V4L2_CTRL_TYPE_HEVC_SPS; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_PPS: + *type = V4L2_CTRL_TYPE_HEVC_PPS; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: + *type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS; + break; + case V4L2_CID_UNIT_CELL_SIZE: + *type = V4L2_CTRL_TYPE_AREA; + *flags |= V4L2_CTRL_FLAG_READ_ONLY; + break; + case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO: + *type = V4L2_CTRL_TYPE_HDR10_CLL_INFO; + break; + case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY: + *type = V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY; + break; + default: + *type = V4L2_CTRL_TYPE_INTEGER; + break; + } + switch (id) { + case V4L2_CID_MPEG_AUDIO_ENCODING: + case V4L2_CID_MPEG_AUDIO_MODE: + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + case V4L2_CID_MPEG_VIDEO_B_FRAMES: + case V4L2_CID_MPEG_STREAM_TYPE: + *flags |= V4L2_CTRL_FLAG_UPDATE; + break; + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_CONTRAST: + case V4L2_CID_SATURATION: + case V4L2_CID_HUE: + case V4L2_CID_RED_BALANCE: + case V4L2_CID_BLUE_BALANCE: + case V4L2_CID_GAMMA: + case V4L2_CID_SHARPNESS: + case V4L2_CID_CHROMA_GAIN: + case V4L2_CID_RDS_TX_DEVIATION: + case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: + case V4L2_CID_AUDIO_LIMITER_DEVIATION: + case V4L2_CID_AUDIO_COMPRESSION_GAIN: + case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: + case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: + case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: + case V4L2_CID_PILOT_TONE_DEVIATION: + case V4L2_CID_PILOT_TONE_FREQUENCY: + case V4L2_CID_TUNE_POWER_LEVEL: + case V4L2_CID_TUNE_ANTENNA_CAPACITOR: + case V4L2_CID_RF_TUNER_RF_GAIN: + case V4L2_CID_RF_TUNER_LNA_GAIN: + case V4L2_CID_RF_TUNER_MIXER_GAIN: + case V4L2_CID_RF_TUNER_IF_GAIN: + case V4L2_CID_RF_TUNER_BANDWIDTH: + case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD: + *flags |= V4L2_CTRL_FLAG_SLIDER; + break; + case V4L2_CID_PAN_RELATIVE: + case V4L2_CID_TILT_RELATIVE: + case V4L2_CID_FOCUS_RELATIVE: + case V4L2_CID_IRIS_RELATIVE: + case V4L2_CID_ZOOM_RELATIVE: + *flags |= V4L2_CTRL_FLAG_WRITE_ONLY | + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + break; + case V4L2_CID_FLASH_STROBE_STATUS: + case V4L2_CID_AUTO_FOCUS_STATUS: + case V4L2_CID_FLASH_READY: + case V4L2_CID_DV_TX_HOTPLUG: + case V4L2_CID_DV_TX_RXSENSE: + case V4L2_CID_DV_TX_EDID_PRESENT: + case V4L2_CID_DV_RX_POWER_PRESENT: + case V4L2_CID_DV_RX_IT_CONTENT_TYPE: + case V4L2_CID_RDS_RX_PTY: + case V4L2_CID_RDS_RX_PS_NAME: + case V4L2_CID_RDS_RX_RADIO_TEXT: + case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT: + case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM: + case V4L2_CID_RDS_RX_MUSIC_SPEECH: + case V4L2_CID_CAMERA_ORIENTATION: + case V4L2_CID_CAMERA_SENSOR_ROTATION: + *flags |= V4L2_CTRL_FLAG_READ_ONLY; + break; + case V4L2_CID_RF_TUNER_PLL_LOCK: + *flags |= V4L2_CTRL_FLAG_VOLATILE; + break; + } +} +EXPORT_SYMBOL(v4l2_ctrl_fill); diff --git a/drivers/media/v4l2-core/v4l2-ctrls-priv.h b/drivers/media/v4l2-core/v4l2-ctrls-priv.h new file mode 100644 index 000000000000..d4bf2c716f97 --- /dev/null +++ b/drivers/media/v4l2-core/v4l2-ctrls-priv.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * V4L2 controls framework private header. + * + * Copyright (C) 2010-2021 Hans Verkuil + */ + +#ifndef _V4L2_CTRLS_PRIV_H_ +#define _V4L2_CTRLS_PRIV_H_ + +#define dprintk(vdev, fmt, arg...) do { \ + if (!WARN_ON(!(vdev)) && ((vdev)->dev_debug & V4L2_DEV_DEBUG_CTRL)) \ + printk(KERN_DEBUG pr_fmt("%s: %s: " fmt), \ + __func__, video_device_node_name(vdev), ##arg); \ +} while (0) + +#define has_op(master, op) \ + ((master)->ops && (master)->ops->op) +#define call_op(master, op) \ + (has_op(master, op) ? (master)->ops->op(master) : 0) + +static inline u32 node2id(struct list_head *node) +{ + return list_entry(node, struct v4l2_ctrl_ref, node)->ctrl->id; +} + +/* + * Small helper function to determine if the autocluster is set to manual + * mode. + */ +static inline bool is_cur_manual(const struct v4l2_ctrl *master) +{ + return master->is_auto && master->cur.val == master->manual_mode_value; +} + +/* + * Small helper function to determine if the autocluster will be set to manual + * mode. + */ +static inline bool is_new_manual(const struct v4l2_ctrl *master) +{ + return master->is_auto && master->val == master->manual_mode_value; +} + +static inline u32 user_flags(const struct v4l2_ctrl *ctrl) +{ + u32 flags = ctrl->flags; + + if (ctrl->is_ptr) + flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD; + + return flags; +} + +/* v4l2-ctrls-core.c */ +void cur_to_new(struct v4l2_ctrl *ctrl); +void cur_to_req(struct v4l2_ctrl_ref *ref); +void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags); +void new_to_req(struct v4l2_ctrl_ref *ref); +void req_to_new(struct v4l2_ctrl_ref *ref); +void send_initial_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl); +void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes); +int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new); +int handler_new_ref(struct v4l2_ctrl_handler *hdl, + struct v4l2_ctrl *ctrl, + struct v4l2_ctrl_ref **ctrl_ref, + bool from_other_dev, bool allocate_req); +struct v4l2_ctrl_ref *find_ref(struct v4l2_ctrl_handler *hdl, u32 id); +struct v4l2_ctrl_ref *find_ref_lock(struct v4l2_ctrl_handler *hdl, u32 id); +int check_range(enum v4l2_ctrl_type type, + s64 min, s64 max, u64 step, s64 def); +void update_from_auto_cluster(struct v4l2_ctrl *master); +int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master, + bool set, u32 ch_flags); + +/* v4l2-ctrls-api.c */ +int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl, + struct v4l2_ext_controls *cs, + struct video_device *vdev); +int try_set_ext_ctrls_common(struct v4l2_fh *fh, + struct v4l2_ctrl_handler *hdl, + struct v4l2_ext_controls *cs, + struct video_device *vdev, bool set); + +/* v4l2-ctrls-request.c */ +void v4l2_ctrl_handler_init_request(struct v4l2_ctrl_handler *hdl); +void v4l2_ctrl_handler_free_request(struct v4l2_ctrl_handler *hdl); +int v4l2_g_ext_ctrls_request(struct v4l2_ctrl_handler *hdl, struct video_device *vdev, + struct media_device *mdev, struct v4l2_ext_controls *cs); +int try_set_ext_ctrls_request(struct v4l2_fh *fh, + struct v4l2_ctrl_handler *hdl, + struct video_device *vdev, + struct media_device *mdev, + struct v4l2_ext_controls *cs, bool set); + +#endif diff --git a/drivers/media/v4l2-core/v4l2-ctrls-request.c b/drivers/media/v4l2-core/v4l2-ctrls-request.c new file mode 100644 index 000000000000..7d098f287fd9 --- /dev/null +++ b/drivers/media/v4l2-core/v4l2-ctrls-request.c @@ -0,0 +1,496 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * V4L2 controls framework Request API implementation. + * + * Copyright (C) 2018-2021 Hans Verkuil + */ + +#define pr_fmt(fmt) "v4l2-ctrls: " fmt + +#include +#include +#include +#include +#include + +#include "v4l2-ctrls-priv.h" + +/* Initialize the request-related fields in a control handler */ +void v4l2_ctrl_handler_init_request(struct v4l2_ctrl_handler *hdl) +{ + INIT_LIST_HEAD(&hdl->requests); + INIT_LIST_HEAD(&hdl->requests_queued); + hdl->request_is_queued = false; + media_request_object_init(&hdl->req_obj); +} + +/* Free the request-related fields in a control handler */ +void v4l2_ctrl_handler_free_request(struct v4l2_ctrl_handler *hdl) +{ + struct v4l2_ctrl_handler *req, *next_req; + + /* + * Do nothing if this isn't the main handler or the main + * handler is not used in any request. + * + * The main handler can be identified by having a NULL ops pointer in + * the request object. + */ + if (hdl->req_obj.ops || list_empty(&hdl->requests)) + return; + + /* + * If the main handler is freed and it is used by handler objects in + * outstanding requests, then unbind and put those objects before + * freeing the main handler. + */ + list_for_each_entry_safe(req, next_req, &hdl->requests, requests) { + media_request_object_unbind(&req->req_obj); + media_request_object_put(&req->req_obj); + } +} + +static int v4l2_ctrl_request_clone(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_handler *from) +{ + struct v4l2_ctrl_ref *ref; + int err = 0; + + if (WARN_ON(!hdl || hdl == from)) + return -EINVAL; + + if (hdl->error) + return hdl->error; + + WARN_ON(hdl->lock != &hdl->_lock); + + mutex_lock(from->lock); + list_for_each_entry(ref, &from->ctrl_refs, node) { + struct v4l2_ctrl *ctrl = ref->ctrl; + struct v4l2_ctrl_ref *new_ref; + + /* Skip refs inherited from other devices */ + if (ref->from_other_dev) + continue; + err = handler_new_ref(hdl, ctrl, &new_ref, false, true); + if (err) + break; + } + mutex_unlock(from->lock); + return err; +} + +static void v4l2_ctrl_request_queue(struct media_request_object *obj) +{ + struct v4l2_ctrl_handler *hdl = + container_of(obj, struct v4l2_ctrl_handler, req_obj); + struct v4l2_ctrl_handler *main_hdl = obj->priv; + + mutex_lock(main_hdl->lock); + list_add_tail(&hdl->requests_queued, &main_hdl->requests_queued); + hdl->request_is_queued = true; + mutex_unlock(main_hdl->lock); +} + +static void v4l2_ctrl_request_unbind(struct media_request_object *obj) +{ + struct v4l2_ctrl_handler *hdl = + container_of(obj, struct v4l2_ctrl_handler, req_obj); + struct v4l2_ctrl_handler *main_hdl = obj->priv; + + mutex_lock(main_hdl->lock); + list_del_init(&hdl->requests); + if (hdl->request_is_queued) { + list_del_init(&hdl->requests_queued); + hdl->request_is_queued = false; + } + mutex_unlock(main_hdl->lock); +} + +static void v4l2_ctrl_request_release(struct media_request_object *obj) +{ + struct v4l2_ctrl_handler *hdl = + container_of(obj, struct v4l2_ctrl_handler, req_obj); + + v4l2_ctrl_handler_free(hdl); + kfree(hdl); +} + +static const struct media_request_object_ops req_ops = { + .queue = v4l2_ctrl_request_queue, + .unbind = v4l2_ctrl_request_unbind, + .release = v4l2_ctrl_request_release, +}; + +struct v4l2_ctrl_handler *v4l2_ctrl_request_hdl_find(struct media_request *req, + struct v4l2_ctrl_handler *parent) +{ + struct media_request_object *obj; + + if (WARN_ON(req->state != MEDIA_REQUEST_STATE_VALIDATING && + req->state != MEDIA_REQUEST_STATE_QUEUED)) + return NULL; + + obj = media_request_object_find(req, &req_ops, parent); + if (obj) + return container_of(obj, struct v4l2_ctrl_handler, req_obj); + return NULL; +} +EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_find); + +struct v4l2_ctrl * +v4l2_ctrl_request_hdl_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id) +{ + struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id); + + return (ref && ref->valid_p_req) ? ref->ctrl : NULL; +} +EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_ctrl_find); + +static int v4l2_ctrl_request_bind(struct media_request *req, + struct v4l2_ctrl_handler *hdl, + struct v4l2_ctrl_handler *from) +{ + int ret; + + ret = v4l2_ctrl_request_clone(hdl, from); + + if (!ret) { + ret = media_request_object_bind(req, &req_ops, + from, false, &hdl->req_obj); + if (!ret) { + mutex_lock(from->lock); + list_add_tail(&hdl->requests, &from->requests); + mutex_unlock(from->lock); + } + } + return ret; +} + +static struct media_request_object * +v4l2_ctrls_find_req_obj(struct v4l2_ctrl_handler *hdl, + struct media_request *req, bool set) +{ + struct media_request_object *obj; + struct v4l2_ctrl_handler *new_hdl; + int ret; + + if (IS_ERR(req)) + return ERR_CAST(req); + + if (set && WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING)) + return ERR_PTR(-EBUSY); + + obj = media_request_object_find(req, &req_ops, hdl); + if (obj) + return obj; + /* + * If there are no controls in this completed request, + * then that can only happen if: + * + * 1) no controls were present in the queued request, and + * 2) v4l2_ctrl_request_complete() could not allocate a + * control handler object to store the completed state in. + * + * So return ENOMEM to indicate that there was an out-of-memory + * error. + */ + if (!set) + return ERR_PTR(-ENOMEM); + + new_hdl = kzalloc(sizeof(*new_hdl), GFP_KERNEL); + if (!new_hdl) + return ERR_PTR(-ENOMEM); + + obj = &new_hdl->req_obj; + ret = v4l2_ctrl_handler_init(new_hdl, (hdl->nr_of_buckets - 1) * 8); + if (!ret) + ret = v4l2_ctrl_request_bind(req, new_hdl, hdl); + if (ret) { + v4l2_ctrl_handler_free(new_hdl); + kfree(new_hdl); + return ERR_PTR(ret); + } + + media_request_object_get(obj); + return obj; +} + +int v4l2_g_ext_ctrls_request(struct v4l2_ctrl_handler *hdl, struct video_device *vdev, + struct media_device *mdev, struct v4l2_ext_controls *cs) +{ + struct media_request_object *obj = NULL; + struct media_request *req = NULL; + int ret; + + if (!mdev || cs->request_fd < 0) + return -EINVAL; + + req = media_request_get_by_fd(mdev, cs->request_fd); + if (IS_ERR(req)) + return PTR_ERR(req); + + if (req->state != MEDIA_REQUEST_STATE_COMPLETE) { + media_request_put(req); + return -EACCES; + } + + ret = media_request_lock_for_access(req); + if (ret) { + media_request_put(req); + return ret; + } + + obj = v4l2_ctrls_find_req_obj(hdl, req, false); + if (IS_ERR(obj)) { + media_request_unlock_for_access(req); + media_request_put(req); + return PTR_ERR(obj); + } + + hdl = container_of(obj, struct v4l2_ctrl_handler, + req_obj); + ret = v4l2_g_ext_ctrls_common(hdl, cs, vdev); + + media_request_unlock_for_access(req); + media_request_object_put(obj); + media_request_put(req); + return ret; +} + +int try_set_ext_ctrls_request(struct v4l2_fh *fh, + struct v4l2_ctrl_handler *hdl, + struct video_device *vdev, + struct media_device *mdev, + struct v4l2_ext_controls *cs, bool set) +{ + struct media_request_object *obj = NULL; + struct media_request *req = NULL; + int ret; + + if (!mdev) { + dprintk(vdev, "%s: missing media device\n", + video_device_node_name(vdev)); + return -EINVAL; + } + + if (cs->request_fd < 0) { + dprintk(vdev, "%s: invalid request fd %d\n", + video_device_node_name(vdev), cs->request_fd); + return -EINVAL; + } + + req = media_request_get_by_fd(mdev, cs->request_fd); + if (IS_ERR(req)) { + dprintk(vdev, "%s: cannot find request fd %d\n", + video_device_node_name(vdev), cs->request_fd); + return PTR_ERR(req); + } + + ret = media_request_lock_for_update(req); + if (ret) { + dprintk(vdev, "%s: cannot lock request fd %d\n", + video_device_node_name(vdev), cs->request_fd); + media_request_put(req); + return ret; + } + + obj = v4l2_ctrls_find_req_obj(hdl, req, set); + if (IS_ERR(obj)) { + dprintk(vdev, + "%s: cannot find request object for request fd %d\n", + video_device_node_name(vdev), + cs->request_fd); + media_request_unlock_for_update(req); + media_request_put(req); + return PTR_ERR(obj); + } + + hdl = container_of(obj, struct v4l2_ctrl_handler, + req_obj); + ret = try_set_ext_ctrls_common(fh, hdl, cs, vdev, set); + if (ret) + dprintk(vdev, + "%s: try_set_ext_ctrls_common failed (%d)\n", + video_device_node_name(vdev), ret); + + media_request_unlock_for_update(req); + media_request_object_put(obj); + media_request_put(req); + + return ret; +} + +void v4l2_ctrl_request_complete(struct media_request *req, + struct v4l2_ctrl_handler *main_hdl) +{ + struct media_request_object *obj; + struct v4l2_ctrl_handler *hdl; + struct v4l2_ctrl_ref *ref; + + if (!req || !main_hdl) + return; + + /* + * Note that it is valid if nothing was found. It means + * that this request doesn't have any controls and so just + * wants to leave the controls unchanged. + */ + obj = media_request_object_find(req, &req_ops, main_hdl); + if (!obj) { + int ret; + + /* Create a new request so the driver can return controls */ + hdl = kzalloc(sizeof(*hdl), GFP_KERNEL); + if (!hdl) + return; + + ret = v4l2_ctrl_handler_init(hdl, (main_hdl->nr_of_buckets - 1) * 8); + if (!ret) + ret = v4l2_ctrl_request_bind(req, hdl, main_hdl); + if (ret) { + v4l2_ctrl_handler_free(hdl); + kfree(hdl); + return; + } + hdl->request_is_queued = true; + obj = media_request_object_find(req, &req_ops, main_hdl); + } + hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj); + + list_for_each_entry(ref, &hdl->ctrl_refs, node) { + struct v4l2_ctrl *ctrl = ref->ctrl; + struct v4l2_ctrl *master = ctrl->cluster[0]; + unsigned int i; + + if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) { + v4l2_ctrl_lock(master); + /* g_volatile_ctrl will update the current control values */ + for (i = 0; i < master->ncontrols; i++) + cur_to_new(master->cluster[i]); + call_op(master, g_volatile_ctrl); + new_to_req(ref); + v4l2_ctrl_unlock(master); + continue; + } + if (ref->valid_p_req) + continue; + + /* Copy the current control value into the request */ + v4l2_ctrl_lock(ctrl); + cur_to_req(ref); + v4l2_ctrl_unlock(ctrl); + } + + mutex_lock(main_hdl->lock); + WARN_ON(!hdl->request_is_queued); + list_del_init(&hdl->requests_queued); + hdl->request_is_queued = false; + mutex_unlock(main_hdl->lock); + media_request_object_complete(obj); + media_request_object_put(obj); +} +EXPORT_SYMBOL(v4l2_ctrl_request_complete); + +int v4l2_ctrl_request_setup(struct media_request *req, + struct v4l2_ctrl_handler *main_hdl) +{ + struct media_request_object *obj; + struct v4l2_ctrl_handler *hdl; + struct v4l2_ctrl_ref *ref; + int ret = 0; + + if (!req || !main_hdl) + return 0; + + if (WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED)) + return -EBUSY; + + /* + * Note that it is valid if nothing was found. It means + * that this request doesn't have any controls and so just + * wants to leave the controls unchanged. + */ + obj = media_request_object_find(req, &req_ops, main_hdl); + if (!obj) + return 0; + if (obj->completed) { + media_request_object_put(obj); + return -EBUSY; + } + hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj); + + list_for_each_entry(ref, &hdl->ctrl_refs, node) + ref->req_done = false; + + list_for_each_entry(ref, &hdl->ctrl_refs, node) { + struct v4l2_ctrl *ctrl = ref->ctrl; + struct v4l2_ctrl *master = ctrl->cluster[0]; + bool have_new_data = false; + int i; + + /* + * Skip if this control was already handled by a cluster. + * Skip button controls and read-only controls. + */ + if (ref->req_done || (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)) + continue; + + v4l2_ctrl_lock(master); + for (i = 0; i < master->ncontrols; i++) { + if (master->cluster[i]) { + struct v4l2_ctrl_ref *r = + find_ref(hdl, master->cluster[i]->id); + + if (r->valid_p_req) { + have_new_data = true; + break; + } + } + } + if (!have_new_data) { + v4l2_ctrl_unlock(master); + continue; + } + + for (i = 0; i < master->ncontrols; i++) { + if (master->cluster[i]) { + struct v4l2_ctrl_ref *r = + find_ref(hdl, master->cluster[i]->id); + + req_to_new(r); + master->cluster[i]->is_new = 1; + r->req_done = true; + } + } + /* + * For volatile autoclusters that are currently in auto mode + * we need to discover if it will be set to manual mode. + * If so, then we have to copy the current volatile values + * first since those will become the new manual values (which + * may be overwritten by explicit new values from this set + * of controls). + */ + if (master->is_auto && master->has_volatiles && + !is_cur_manual(master)) { + s32 new_auto_val = *master->p_new.p_s32; + + /* + * If the new value == the manual value, then copy + * the current volatile values. + */ + if (new_auto_val == master->manual_mode_value) + update_from_auto_cluster(master); + } + + ret = try_or_set_cluster(NULL, master, true, 0); + v4l2_ctrl_unlock(master); + + if (ret) + break; + } + + media_request_object_put(obj); + return ret; +} +EXPORT_SYMBOL(v4l2_ctrl_request_setup); diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c deleted file mode 100644 index 09992e76bad6..000000000000 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ /dev/null @@ -1,5111 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - V4L2 controls framework implementation. - - Copyright (C) 2010 Hans Verkuil - - */ - -#define pr_fmt(fmt) "v4l2-ctrls: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define dprintk(vdev, fmt, arg...) do { \ - if (!WARN_ON(!(vdev)) && ((vdev)->dev_debug & V4L2_DEV_DEBUG_CTRL)) \ - printk(KERN_DEBUG pr_fmt("%s: %s: " fmt), \ - __func__, video_device_node_name(vdev), ##arg); \ -} while (0) - -#define has_op(master, op) \ - (master->ops && master->ops->op) -#define call_op(master, op) \ - (has_op(master, op) ? master->ops->op(master) : 0) - -static const union v4l2_ctrl_ptr ptr_null; - -/* Internal temporary helper struct, one for each v4l2_ext_control */ -struct v4l2_ctrl_helper { - /* Pointer to the control reference of the master control */ - struct v4l2_ctrl_ref *mref; - /* The control ref corresponding to the v4l2_ext_control ID field. */ - struct v4l2_ctrl_ref *ref; - /* v4l2_ext_control index of the next control belonging to the - same cluster, or 0 if there isn't any. */ - u32 next; -}; - -/* Small helper function to determine if the autocluster is set to manual - mode. */ -static bool is_cur_manual(const struct v4l2_ctrl *master) -{ - return master->is_auto && master->cur.val == master->manual_mode_value; -} - -/* Same as above, but this checks the against the new value instead of the - current value. */ -static bool is_new_manual(const struct v4l2_ctrl *master) -{ - return master->is_auto && master->val == master->manual_mode_value; -} - -/* Default intra MPEG-2 quantisation coefficients, from the specification. */ -static const u8 mpeg2_intra_quant_matrix[64] = { - 8, 16, 16, 19, 16, 19, 22, 22, - 22, 22, 22, 22, 26, 24, 26, 27, - 27, 27, 26, 26, 26, 26, 27, 27, - 27, 29, 29, 29, 34, 34, 34, 29, - 29, 29, 27, 27, 29, 29, 32, 32, - 34, 34, 37, 38, 37, 35, 35, 34, - 35, 38, 38, 40, 40, 40, 48, 48, - 46, 46, 56, 56, 58, 69, 69, 83 -}; - -/* Returns NULL or a character pointer array containing the menu for - the given control ID. The pointer array ends with a NULL pointer. - An empty string signifies a menu entry that is invalid. This allows - drivers to disable certain options if it is not supported. */ -const char * const *v4l2_ctrl_get_menu(u32 id) -{ - static const char * const mpeg_audio_sampling_freq[] = { - "44.1 kHz", - "48 kHz", - "32 kHz", - NULL - }; - static const char * const mpeg_audio_encoding[] = { - "MPEG-1/2 Layer I", - "MPEG-1/2 Layer II", - "MPEG-1/2 Layer III", - "MPEG-2/4 AAC", - "AC-3", - NULL - }; - static const char * const mpeg_audio_l1_bitrate[] = { - "32 kbps", - "64 kbps", - "96 kbps", - "128 kbps", - "160 kbps", - "192 kbps", - "224 kbps", - "256 kbps", - "288 kbps", - "320 kbps", - "352 kbps", - "384 kbps", - "416 kbps", - "448 kbps", - NULL - }; - static const char * const mpeg_audio_l2_bitrate[] = { - "32 kbps", - "48 kbps", - "56 kbps", - "64 kbps", - "80 kbps", - "96 kbps", - "112 kbps", - "128 kbps", - "160 kbps", - "192 kbps", - "224 kbps", - "256 kbps", - "320 kbps", - "384 kbps", - NULL - }; - static const char * const mpeg_audio_l3_bitrate[] = { - "32 kbps", - "40 kbps", - "48 kbps", - "56 kbps", - "64 kbps", - "80 kbps", - "96 kbps", - "112 kbps", - "128 kbps", - "160 kbps", - "192 kbps", - "224 kbps", - "256 kbps", - "320 kbps", - NULL - }; - static const char * const mpeg_audio_ac3_bitrate[] = { - "32 kbps", - "40 kbps", - "48 kbps", - "56 kbps", - "64 kbps", - "80 kbps", - "96 kbps", - "112 kbps", - "128 kbps", - "160 kbps", - "192 kbps", - "224 kbps", - "256 kbps", - "320 kbps", - "384 kbps", - "448 kbps", - "512 kbps", - "576 kbps", - "640 kbps", - NULL - }; - static const char * const mpeg_audio_mode[] = { - "Stereo", - "Joint Stereo", - "Dual", - "Mono", - NULL - }; - static const char * const mpeg_audio_mode_extension[] = { - "Bound 4", - "Bound 8", - "Bound 12", - "Bound 16", - NULL - }; - static const char * const mpeg_audio_emphasis[] = { - "No Emphasis", - "50/15 us", - "CCITT J17", - NULL - }; - static const char * const mpeg_audio_crc[] = { - "No CRC", - "16-bit CRC", - NULL - }; - static const char * const mpeg_audio_dec_playback[] = { - "Auto", - "Stereo", - "Left", - "Right", - "Mono", - "Swapped Stereo", - NULL - }; - static const char * const mpeg_video_encoding[] = { - "MPEG-1", - "MPEG-2", - "MPEG-4 AVC", - NULL - }; - static const char * const mpeg_video_aspect[] = { - "1x1", - "4x3", - "16x9", - "2.21x1", - NULL - }; - static const char * const mpeg_video_bitrate_mode[] = { - "Variable Bitrate", - "Constant Bitrate", - "Constant Quality", - NULL - }; - static const char * const mpeg_stream_type[] = { - "MPEG-2 Program Stream", - "MPEG-2 Transport Stream", - "MPEG-1 System Stream", - "MPEG-2 DVD-compatible Stream", - "MPEG-1 VCD-compatible Stream", - "MPEG-2 SVCD-compatible Stream", - NULL - }; - static const char * const mpeg_stream_vbi_fmt[] = { - "No VBI", - "Private Packet, IVTV Format", - NULL - }; - static const char * const camera_power_line_frequency[] = { - "Disabled", - "50 Hz", - "60 Hz", - "Auto", - NULL - }; - static const char * const camera_exposure_auto[] = { - "Auto Mode", - "Manual Mode", - "Shutter Priority Mode", - "Aperture Priority Mode", - NULL - }; - static const char * const camera_exposure_metering[] = { - "Average", - "Center Weighted", - "Spot", - "Matrix", - NULL - }; - static const char * const camera_auto_focus_range[] = { - "Auto", - "Normal", - "Macro", - "Infinity", - NULL - }; - static const char * const colorfx[] = { - "None", - "Black & White", - "Sepia", - "Negative", - "Emboss", - "Sketch", - "Sky Blue", - "Grass Green", - "Skin Whiten", - "Vivid", - "Aqua", - "Art Freeze", - "Silhouette", - "Solarization", - "Antique", - "Set Cb/Cr", - NULL - }; - static const char * const auto_n_preset_white_balance[] = { - "Manual", - "Auto", - "Incandescent", - "Fluorescent", - "Fluorescent H", - "Horizon", - "Daylight", - "Flash", - "Cloudy", - "Shade", - NULL, - }; - static const char * const camera_iso_sensitivity_auto[] = { - "Manual", - "Auto", - NULL - }; - static const char * const scene_mode[] = { - "None", - "Backlight", - "Beach/Snow", - "Candle Light", - "Dusk/Dawn", - "Fall Colors", - "Fireworks", - "Landscape", - "Night", - "Party/Indoor", - "Portrait", - "Sports", - "Sunset", - "Text", - NULL - }; - static const char * const tune_emphasis[] = { - "None", - "50 Microseconds", - "75 Microseconds", - NULL, - }; - static const char * const header_mode[] = { - "Separate Buffer", - "Joined With 1st Frame", - NULL, - }; - static const char * const multi_slice[] = { - "Single", - "Max Macroblocks", - "Max Bytes", - NULL, - }; - static const char * const entropy_mode[] = { - "CAVLC", - "CABAC", - NULL, - }; - static const char * const mpeg_h264_level[] = { - "1", - "1b", - "1.1", - "1.2", - "1.3", - "2", - "2.1", - "2.2", - "3", - "3.1", - "3.2", - "4", - "4.1", - "4.2", - "5", - "5.1", - "5.2", - "6.0", - "6.1", - "6.2", - NULL, - }; - static const char * const h264_loop_filter[] = { - "Enabled", - "Disabled", - "Disabled at Slice Boundary", - NULL, - }; - static const char * const h264_profile[] = { - "Baseline", - "Constrained Baseline", - "Main", - "Extended", - "High", - "High 10", - "High 422", - "High 444 Predictive", - "High 10 Intra", - "High 422 Intra", - "High 444 Intra", - "CAVLC 444 Intra", - "Scalable Baseline", - "Scalable High", - "Scalable High Intra", - "Stereo High", - "Multiview High", - "Constrained High", - NULL, - }; - static const char * const vui_sar_idc[] = { - "Unspecified", - "1:1", - "12:11", - "10:11", - "16:11", - "40:33", - "24:11", - "20:11", - "32:11", - "80:33", - "18:11", - "15:11", - "64:33", - "160:99", - "4:3", - "3:2", - "2:1", - "Extended SAR", - NULL, - }; - static const char * const h264_fp_arrangement_type[] = { - "Checkerboard", - "Column", - "Row", - "Side by Side", - "Top Bottom", - "Temporal", - NULL, - }; - static const char * const h264_fmo_map_type[] = { - "Interleaved Slices", - "Scattered Slices", - "Foreground with Leftover", - "Box Out", - "Raster Scan", - "Wipe Scan", - "Explicit", - NULL, - }; - static const char * const h264_decode_mode[] = { - "Slice-Based", - "Frame-Based", - NULL, - }; - static const char * const h264_start_code[] = { - "No Start Code", - "Annex B Start Code", - NULL, - }; - static const char * const h264_hierarchical_coding_type[] = { - "Hier Coding B", - "Hier Coding P", - NULL, - }; - static const char * const mpeg_mpeg2_level[] = { - "Low", - "Main", - "High 1440", - "High", - NULL, - }; - static const char * const mpeg2_profile[] = { - "Simple", - "Main", - "SNR Scalable", - "Spatially Scalable", - "High", - NULL, - }; - static const char * const mpeg_mpeg4_level[] = { - "0", - "0b", - "1", - "2", - "3", - "3b", - "4", - "5", - NULL, - }; - static const char * const mpeg4_profile[] = { - "Simple", - "Advanced Simple", - "Core", - "Simple Scalable", - "Advanced Coding Efficiency", - NULL, - }; - - static const char * const vpx_golden_frame_sel[] = { - "Use Previous Frame", - "Use Previous Specific Frame", - NULL, - }; - static const char * const vp8_profile[] = { - "0", - "1", - "2", - "3", - NULL, - }; - static const char * const vp9_profile[] = { - "0", - "1", - "2", - "3", - NULL, - }; - static const char * const vp9_level[] = { - "1", - "1.1", - "2", - "2.1", - "3", - "3.1", - "4", - "4.1", - "5", - "5.1", - "5.2", - "6", - "6.1", - "6.2", - NULL, - }; - - static const char * const flash_led_mode[] = { - "Off", - "Flash", - "Torch", - NULL, - }; - static const char * const flash_strobe_source[] = { - "Software", - "External", - NULL, - }; - - static const char * const jpeg_chroma_subsampling[] = { - "4:4:4", - "4:2:2", - "4:2:0", - "4:1:1", - "4:1:0", - "Gray", - NULL, - }; - static const char * const dv_tx_mode[] = { - "DVI-D", - "HDMI", - NULL, - }; - static const char * const dv_rgb_range[] = { - "Automatic", - "RGB Limited Range (16-235)", - "RGB Full Range (0-255)", - NULL, - }; - static const char * const dv_it_content_type[] = { - "Graphics", - "Photo", - "Cinema", - "Game", - "No IT Content", - NULL, - }; - static const char * const detect_md_mode[] = { - "Disabled", - "Global", - "Threshold Grid", - "Region Grid", - NULL, - }; - - static const char * const hevc_profile[] = { - "Main", - "Main Still Picture", - "Main 10", - NULL, - }; - static const char * const hevc_level[] = { - "1", - "2", - "2.1", - "3", - "3.1", - "4", - "4.1", - "5", - "5.1", - "5.2", - "6", - "6.1", - "6.2", - NULL, - }; - static const char * const hevc_hierarchial_coding_type[] = { - "B", - "P", - NULL, - }; - static const char * const hevc_refresh_type[] = { - "None", - "CRA", - "IDR", - NULL, - }; - static const char * const hevc_size_of_length_field[] = { - "0", - "1", - "2", - "4", - NULL, - }; - static const char * const hevc_tier[] = { - "Main", - "High", - NULL, - }; - static const char * const hevc_loop_filter_mode[] = { - "Disabled", - "Enabled", - "Disabled at slice boundary", - "NULL", - }; - static const char * const hevc_decode_mode[] = { - "Slice-Based", - "Frame-Based", - NULL, - }; - static const char * const hevc_start_code[] = { - "No Start Code", - "Annex B Start Code", - NULL, - }; - static const char * const camera_orientation[] = { - "Front", - "Back", - "External", - NULL, - }; - static const char * const mpeg_video_frame_skip[] = { - "Disabled", - "Level Limit", - "VBV/CPB Limit", - NULL, - }; - - switch (id) { - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: - return mpeg_audio_sampling_freq; - case V4L2_CID_MPEG_AUDIO_ENCODING: - return mpeg_audio_encoding; - case V4L2_CID_MPEG_AUDIO_L1_BITRATE: - return mpeg_audio_l1_bitrate; - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: - return mpeg_audio_l2_bitrate; - case V4L2_CID_MPEG_AUDIO_L3_BITRATE: - return mpeg_audio_l3_bitrate; - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: - return mpeg_audio_ac3_bitrate; - case V4L2_CID_MPEG_AUDIO_MODE: - return mpeg_audio_mode; - case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: - return mpeg_audio_mode_extension; - case V4L2_CID_MPEG_AUDIO_EMPHASIS: - return mpeg_audio_emphasis; - case V4L2_CID_MPEG_AUDIO_CRC: - return mpeg_audio_crc; - case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: - case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: - return mpeg_audio_dec_playback; - case V4L2_CID_MPEG_VIDEO_ENCODING: - return mpeg_video_encoding; - case V4L2_CID_MPEG_VIDEO_ASPECT: - return mpeg_video_aspect; - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - return mpeg_video_bitrate_mode; - case V4L2_CID_MPEG_STREAM_TYPE: - return mpeg_stream_type; - case V4L2_CID_MPEG_STREAM_VBI_FMT: - return mpeg_stream_vbi_fmt; - case V4L2_CID_POWER_LINE_FREQUENCY: - return camera_power_line_frequency; - case V4L2_CID_EXPOSURE_AUTO: - return camera_exposure_auto; - case V4L2_CID_EXPOSURE_METERING: - return camera_exposure_metering; - case V4L2_CID_AUTO_FOCUS_RANGE: - return camera_auto_focus_range; - case V4L2_CID_COLORFX: - return colorfx; - case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: - return auto_n_preset_white_balance; - case V4L2_CID_ISO_SENSITIVITY_AUTO: - return camera_iso_sensitivity_auto; - case V4L2_CID_SCENE_MODE: - return scene_mode; - case V4L2_CID_TUNE_PREEMPHASIS: - return tune_emphasis; - case V4L2_CID_TUNE_DEEMPHASIS: - return tune_emphasis; - case V4L2_CID_FLASH_LED_MODE: - return flash_led_mode; - case V4L2_CID_FLASH_STROBE_SOURCE: - return flash_strobe_source; - case V4L2_CID_MPEG_VIDEO_HEADER_MODE: - return header_mode; - case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: - return mpeg_video_frame_skip; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: - return multi_slice; - case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: - return entropy_mode; - case V4L2_CID_MPEG_VIDEO_H264_LEVEL: - return mpeg_h264_level; - case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: - return h264_loop_filter; - case V4L2_CID_MPEG_VIDEO_H264_PROFILE: - return h264_profile; - case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: - return vui_sar_idc; - case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: - return h264_fp_arrangement_type; - case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: - return h264_fmo_map_type; - case V4L2_CID_STATELESS_H264_DECODE_MODE: - return h264_decode_mode; - case V4L2_CID_STATELESS_H264_START_CODE: - return h264_start_code; - case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: - return h264_hierarchical_coding_type; - case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: - return mpeg_mpeg2_level; - case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: - return mpeg2_profile; - case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: - return mpeg_mpeg4_level; - case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: - return mpeg4_profile; - case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: - return vpx_golden_frame_sel; - case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: - return vp8_profile; - case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: - return vp9_profile; - case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: - return vp9_level; - case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: - return jpeg_chroma_subsampling; - case V4L2_CID_DV_TX_MODE: - return dv_tx_mode; - case V4L2_CID_DV_TX_RGB_RANGE: - case V4L2_CID_DV_RX_RGB_RANGE: - return dv_rgb_range; - case V4L2_CID_DV_TX_IT_CONTENT_TYPE: - case V4L2_CID_DV_RX_IT_CONTENT_TYPE: - return dv_it_content_type; - case V4L2_CID_DETECT_MD_MODE: - return detect_md_mode; - case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: - return hevc_profile; - case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: - return hevc_level; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: - return hevc_hierarchial_coding_type; - case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: - return hevc_refresh_type; - case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: - return hevc_size_of_length_field; - case V4L2_CID_MPEG_VIDEO_HEVC_TIER: - return hevc_tier; - case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: - return hevc_loop_filter_mode; - case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: - return hevc_decode_mode; - case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: - return hevc_start_code; - case V4L2_CID_CAMERA_ORIENTATION: - return camera_orientation; - default: - return NULL; - } -} -EXPORT_SYMBOL(v4l2_ctrl_get_menu); - -#define __v4l2_qmenu_int_len(arr, len) ({ *(len) = ARRAY_SIZE(arr); arr; }) -/* - * Returns NULL or an s64 type array containing the menu for given - * control ID. The total number of the menu items is returned in @len. - */ -const s64 *v4l2_ctrl_get_int_menu(u32 id, u32 *len) -{ - static const s64 qmenu_int_vpx_num_partitions[] = { - 1, 2, 4, 8, - }; - - static const s64 qmenu_int_vpx_num_ref_frames[] = { - 1, 2, 3, - }; - - switch (id) { - case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: - return __v4l2_qmenu_int_len(qmenu_int_vpx_num_partitions, len); - case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES: - return __v4l2_qmenu_int_len(qmenu_int_vpx_num_ref_frames, len); - default: - *len = 0; - return NULL; - } -} -EXPORT_SYMBOL(v4l2_ctrl_get_int_menu); - -/* Return the control name. */ -const char *v4l2_ctrl_get_name(u32 id) -{ - switch (id) { - /* USER controls */ - /* Keep the order of the 'case's the same as in v4l2-controls.h! */ - case V4L2_CID_USER_CLASS: return "User Controls"; - case V4L2_CID_BRIGHTNESS: return "Brightness"; - case V4L2_CID_CONTRAST: return "Contrast"; - case V4L2_CID_SATURATION: return "Saturation"; - case V4L2_CID_HUE: return "Hue"; - case V4L2_CID_AUDIO_VOLUME: return "Volume"; - case V4L2_CID_AUDIO_BALANCE: return "Balance"; - case V4L2_CID_AUDIO_BASS: return "Bass"; - case V4L2_CID_AUDIO_TREBLE: return "Treble"; - case V4L2_CID_AUDIO_MUTE: return "Mute"; - case V4L2_CID_AUDIO_LOUDNESS: return "Loudness"; - case V4L2_CID_BLACK_LEVEL: return "Black Level"; - case V4L2_CID_AUTO_WHITE_BALANCE: return "White Balance, Automatic"; - case V4L2_CID_DO_WHITE_BALANCE: return "Do White Balance"; - case V4L2_CID_RED_BALANCE: return "Red Balance"; - case V4L2_CID_BLUE_BALANCE: return "Blue Balance"; - case V4L2_CID_GAMMA: return "Gamma"; - case V4L2_CID_EXPOSURE: return "Exposure"; - case V4L2_CID_AUTOGAIN: return "Gain, Automatic"; - case V4L2_CID_GAIN: return "Gain"; - case V4L2_CID_HFLIP: return "Horizontal Flip"; - case V4L2_CID_VFLIP: return "Vertical Flip"; - case V4L2_CID_POWER_LINE_FREQUENCY: return "Power Line Frequency"; - case V4L2_CID_HUE_AUTO: return "Hue, Automatic"; - case V4L2_CID_WHITE_BALANCE_TEMPERATURE: return "White Balance Temperature"; - case V4L2_CID_SHARPNESS: return "Sharpness"; - case V4L2_CID_BACKLIGHT_COMPENSATION: return "Backlight Compensation"; - case V4L2_CID_CHROMA_AGC: return "Chroma AGC"; - case V4L2_CID_COLOR_KILLER: return "Color Killer"; - case V4L2_CID_COLORFX: return "Color Effects"; - case V4L2_CID_AUTOBRIGHTNESS: return "Brightness, Automatic"; - case V4L2_CID_BAND_STOP_FILTER: return "Band-Stop Filter"; - case V4L2_CID_ROTATE: return "Rotate"; - case V4L2_CID_BG_COLOR: return "Background Color"; - case V4L2_CID_CHROMA_GAIN: return "Chroma Gain"; - case V4L2_CID_ILLUMINATORS_1: return "Illuminator 1"; - case V4L2_CID_ILLUMINATORS_2: return "Illuminator 2"; - case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: return "Min Number of Capture Buffers"; - case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: return "Min Number of Output Buffers"; - case V4L2_CID_ALPHA_COMPONENT: return "Alpha Component"; - case V4L2_CID_COLORFX_CBCR: return "Color Effects, CbCr"; - - /* Codec controls */ - /* The MPEG controls are applicable to all codec controls - * and the 'MPEG' part of the define is historical */ - /* Keep the order of the 'case's the same as in videodev2.h! */ - case V4L2_CID_CODEC_CLASS: return "Codec Controls"; - case V4L2_CID_MPEG_STREAM_TYPE: return "Stream Type"; - case V4L2_CID_MPEG_STREAM_PID_PMT: return "Stream PMT Program ID"; - case V4L2_CID_MPEG_STREAM_PID_AUDIO: return "Stream Audio Program ID"; - case V4L2_CID_MPEG_STREAM_PID_VIDEO: return "Stream Video Program ID"; - case V4L2_CID_MPEG_STREAM_PID_PCR: return "Stream PCR Program ID"; - case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio ID"; - case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID"; - case V4L2_CID_MPEG_STREAM_VBI_FMT: return "Stream VBI Format"; - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency"; - case V4L2_CID_MPEG_AUDIO_ENCODING: return "Audio Encoding"; - case V4L2_CID_MPEG_AUDIO_L1_BITRATE: return "Audio Layer I Bitrate"; - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return "Audio Layer II Bitrate"; - case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return "Audio Layer III Bitrate"; - case V4L2_CID_MPEG_AUDIO_MODE: return "Audio Stereo Mode"; - case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension"; - case V4L2_CID_MPEG_AUDIO_EMPHASIS: return "Audio Emphasis"; - case V4L2_CID_MPEG_AUDIO_CRC: return "Audio CRC"; - case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute"; - case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate"; - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate"; - case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: return "Audio Playback"; - case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: return "Audio Multilingual Playback"; - case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding"; - case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect"; - case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames"; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: return "Video GOP Size"; - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: return "Video GOP Closure"; - case V4L2_CID_MPEG_VIDEO_PULLDOWN: return "Video Pulldown"; - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: return "Video Bitrate Mode"; - case V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY: return "Constant Quality"; - case V4L2_CID_MPEG_VIDEO_BITRATE: return "Video Bitrate"; - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: return "Video Peak Bitrate"; - case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation"; - case V4L2_CID_MPEG_VIDEO_MUTE: return "Video Mute"; - case V4L2_CID_MPEG_VIDEO_MUTE_YUV: return "Video Mute YUV"; - case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: return "Decoder Slice Interface"; - case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: return "MPEG4 Loop Filter Enable"; - case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: return "Number of Intra Refresh MBs"; - case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: return "Frame Level Rate Control Enable"; - case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: return "H264 MB Level Rate Control"; - case V4L2_CID_MPEG_VIDEO_HEADER_MODE: return "Sequence Header Mode"; - case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC: return "Max Number of Reference Pics"; - case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: return "Frame Skip Mode"; - case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: return "Display Delay"; - case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: return "Display Delay Enable"; - case V4L2_CID_MPEG_VIDEO_AU_DELIMITER: return "Generate Access Unit Delimiters"; - case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP: return "H263 I-Frame QP Value"; - case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: return "H263 P-Frame QP Value"; - case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: return "H263 B-Frame QP Value"; - case V4L2_CID_MPEG_VIDEO_H263_MIN_QP: return "H263 Minimum QP Value"; - case V4L2_CID_MPEG_VIDEO_H263_MAX_QP: return "H263 Maximum QP Value"; - case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: return "H264 I-Frame QP Value"; - case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: return "H264 P-Frame QP Value"; - case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: return "H264 B-Frame QP Value"; - case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: return "H264 Maximum QP Value"; - case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: return "H264 Minimum QP Value"; - case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: return "H264 8x8 Transform Enable"; - case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: return "H264 CPB Buffer Size"; - case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: return "H264 Entropy Mode"; - case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: return "H264 I-Frame Period"; - case V4L2_CID_MPEG_VIDEO_H264_LEVEL: return "H264 Level"; - case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: return "H264 Loop Filter Alpha Offset"; - case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: return "H264 Loop Filter Beta Offset"; - case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: return "H264 Loop Filter Mode"; - case V4L2_CID_MPEG_VIDEO_H264_PROFILE: return "H264 Profile"; - case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT: return "Vertical Size of SAR"; - case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH: return "Horizontal Size of SAR"; - case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: return "Aspect Ratio VUI Enable"; - case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: return "VUI Aspect Ratio IDC"; - case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING: return "H264 Enable Frame Packing SEI"; - case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0: return "H264 Set Curr. Frame as Frame0"; - case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: return "H264 FP Arrangement Type"; - case V4L2_CID_MPEG_VIDEO_H264_FMO: return "H264 Flexible MB Ordering"; - case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: return "H264 Map Type for FMO"; - case V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP: return "H264 FMO Number of Slice Groups"; - case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION: return "H264 FMO Direction of Change"; - case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE: return "H264 FMO Size of 1st Slice Grp"; - case V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH: return "H264 FMO No. of Consecutive MBs"; - case V4L2_CID_MPEG_VIDEO_H264_ASO: return "H264 Arbitrary Slice Ordering"; - case V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER: return "H264 ASO Slice Order"; - case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING: return "Enable H264 Hierarchical Coding"; - case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: return "H264 Hierarchical Coding Type"; - case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER:return "H264 Number of HC Layers"; - case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP: - return "H264 Set QP Value for HC Layers"; - case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: - return "H264 Constrained Intra Pred"; - case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: return "H264 Chroma QP Index Offset"; - case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP: return "H264 I-Frame Minimum QP Value"; - case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP: return "H264 I-Frame Maximum QP Value"; - case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP: return "H264 P-Frame Minimum QP Value"; - case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP: return "H264 P-Frame Maximum QP Value"; - case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP: return "H264 B-Frame Minimum QP Value"; - case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP: return "H264 B-Frame Maximum QP Value"; - case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR: return "H264 Hierarchical Lay 0 Bitrate"; - case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR: return "H264 Hierarchical Lay 1 Bitrate"; - case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR: return "H264 Hierarchical Lay 2 Bitrate"; - case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR: return "H264 Hierarchical Lay 3 Bitrate"; - case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR: return "H264 Hierarchical Lay 4 Bitrate"; - case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR: return "H264 Hierarchical Lay 5 Bitrate"; - case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L6_BR: return "H264 Hierarchical Lay 6 Bitrate"; - case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: return "MPEG2 Level"; - case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: return "MPEG2 Profile"; - case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; - case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: return "MPEG4 P-Frame QP Value"; - case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: return "MPEG4 B-Frame QP Value"; - case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP: return "MPEG4 Minimum QP Value"; - case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP: return "MPEG4 Maximum QP Value"; - case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: return "MPEG4 Level"; - case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: return "MPEG4 Profile"; - case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL: return "Quarter Pixel Search Enable"; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: return "Maximum Bytes in a Slice"; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: return "Number of MBs in a Slice"; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: return "Slice Partitioning Method"; - case V4L2_CID_MPEG_VIDEO_VBV_SIZE: return "VBV Buffer Size"; - case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS"; - case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count"; - case V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR: return "Video Decoder Conceal Color"; - case V4L2_CID_MPEG_VIDEO_VBV_DELAY: return "Initial Delay for VBV Control"; - case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: return "Horizontal MV Search Range"; - case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: return "Vertical MV Search Range"; - case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: return "Repeat Sequence Header"; - case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: return "Force Key Frame"; - case V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID: return "Base Layer Priority ID"; - case V4L2_CID_MPEG_VIDEO_LTR_COUNT: return "LTR Count"; - case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX: return "Frame LTR Index"; - case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES: return "Use LTR Frames"; - case V4L2_CID_FWHT_I_FRAME_QP: return "FWHT I-Frame QP Value"; - case V4L2_CID_FWHT_P_FRAME_QP: return "FWHT P-Frame QP Value"; - - /* VPX controls */ - case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: return "VPX Number of Partitions"; - case V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4: return "VPX Intra Mode Decision Disable"; - case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES: return "VPX No. of Refs for P Frame"; - case V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL: return "VPX Loop Filter Level Range"; - case V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS: return "VPX Deblocking Effect Control"; - case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD: return "VPX Golden Frame Refresh Period"; - case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: return "VPX Golden Frame Indicator"; - case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP: return "VPX Minimum QP Value"; - case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP: return "VPX Maximum QP Value"; - case V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP: return "VPX I-Frame QP Value"; - case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: return "VPX P-Frame QP Value"; - case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: return "VP8 Profile"; - case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: return "VP9 Profile"; - case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: return "VP9 Level"; - - /* HEVC controls */ - case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: return "HEVC I-Frame QP Value"; - case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: return "HEVC P-Frame QP Value"; - case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: return "HEVC B-Frame QP Value"; - case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: return "HEVC Minimum QP Value"; - case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: return "HEVC Maximum QP Value"; - case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP: return "HEVC I-Frame Minimum QP Value"; - case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP: return "HEVC I-Frame Maximum QP Value"; - case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP: return "HEVC P-Frame Minimum QP Value"; - case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP: return "HEVC P-Frame Maximum QP Value"; - case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP: return "HEVC B-Frame Minimum QP Value"; - case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP: return "HEVC B-Frame Maximum QP Value"; - case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: return "HEVC Profile"; - case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: return "HEVC Level"; - case V4L2_CID_MPEG_VIDEO_HEVC_TIER: return "HEVC Tier"; - case V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION: return "HEVC Frame Rate Resolution"; - case V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH: return "HEVC Maximum Coding Unit Depth"; - case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: return "HEVC Refresh Type"; - case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: return "HEVC Constant Intra Prediction"; - case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU: return "HEVC Lossless Encoding"; - case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT: return "HEVC Wavefront"; - case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: return "HEVC Loop Filter"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP: return "HEVC QP Values"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: return "HEVC Hierarchical Coding Type"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER: return "HEVC Hierarchical Coding Layer"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP: return "HEVC Hierarchical Layer 0 QP"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP: return "HEVC Hierarchical Layer 1 QP"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP: return "HEVC Hierarchical Layer 2 QP"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP: return "HEVC Hierarchical Layer 3 QP"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP: return "HEVC Hierarchical Layer 4 QP"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP: return "HEVC Hierarchical Layer 5 QP"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP: return "HEVC Hierarchical Layer 6 QP"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR: return "HEVC Hierarchical Lay 0 BitRate"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR: return "HEVC Hierarchical Lay 1 BitRate"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR: return "HEVC Hierarchical Lay 2 BitRate"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR: return "HEVC Hierarchical Lay 3 BitRate"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR: return "HEVC Hierarchical Lay 4 BitRate"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: return "HEVC Hierarchical Lay 5 BitRate"; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR: return "HEVC Hierarchical Lay 6 BitRate"; - case V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB: return "HEVC General PB"; - case V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID: return "HEVC Temporal ID"; - case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: return "HEVC Strong Intra Smoothing"; - case V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT: return "HEVC Intra PU Split"; - case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: return "HEVC TMV Prediction"; - case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1: return "HEVC Max Num of Candidate MVs"; - case V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE: return "HEVC ENC Without Startcode"; - case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: return "HEVC Num of I-Frame b/w 2 IDR"; - case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: return "HEVC Loop Filter Beta Offset"; - case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: return "HEVC Loop Filter TC Offset"; - case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: return "HEVC Size of Length Field"; - case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES: return "Reference Frames for a P-Frame"; - case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: return "Prepend SPS and PPS to IDR"; - case V4L2_CID_MPEG_VIDEO_HEVC_SPS: return "HEVC Sequence Parameter Set"; - case V4L2_CID_MPEG_VIDEO_HEVC_PPS: return "HEVC Picture Parameter Set"; - case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: return "HEVC Slice Parameters"; - case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: return "HEVC Decode Mode"; - case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: return "HEVC Start Code"; - - /* CAMERA controls */ - /* Keep the order of the 'case's the same as in v4l2-controls.h! */ - case V4L2_CID_CAMERA_CLASS: return "Camera Controls"; - case V4L2_CID_EXPOSURE_AUTO: return "Auto Exposure"; - case V4L2_CID_EXPOSURE_ABSOLUTE: return "Exposure Time, Absolute"; - case V4L2_CID_EXPOSURE_AUTO_PRIORITY: return "Exposure, Dynamic Framerate"; - case V4L2_CID_PAN_RELATIVE: return "Pan, Relative"; - case V4L2_CID_TILT_RELATIVE: return "Tilt, Relative"; - case V4L2_CID_PAN_RESET: return "Pan, Reset"; - case V4L2_CID_TILT_RESET: return "Tilt, Reset"; - case V4L2_CID_PAN_ABSOLUTE: return "Pan, Absolute"; - case V4L2_CID_TILT_ABSOLUTE: return "Tilt, Absolute"; - case V4L2_CID_FOCUS_ABSOLUTE: return "Focus, Absolute"; - case V4L2_CID_FOCUS_RELATIVE: return "Focus, Relative"; - case V4L2_CID_FOCUS_AUTO: return "Focus, Automatic Continuous"; - case V4L2_CID_ZOOM_ABSOLUTE: return "Zoom, Absolute"; - case V4L2_CID_ZOOM_RELATIVE: return "Zoom, Relative"; - case V4L2_CID_ZOOM_CONTINUOUS: return "Zoom, Continuous"; - case V4L2_CID_PRIVACY: return "Privacy"; - case V4L2_CID_IRIS_ABSOLUTE: return "Iris, Absolute"; - case V4L2_CID_IRIS_RELATIVE: return "Iris, Relative"; - case V4L2_CID_AUTO_EXPOSURE_BIAS: return "Auto Exposure, Bias"; - case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: return "White Balance, Auto & Preset"; - case V4L2_CID_WIDE_DYNAMIC_RANGE: return "Wide Dynamic Range"; - case V4L2_CID_IMAGE_STABILIZATION: return "Image Stabilization"; - case V4L2_CID_ISO_SENSITIVITY: return "ISO Sensitivity"; - case V4L2_CID_ISO_SENSITIVITY_AUTO: return "ISO Sensitivity, Auto"; - case V4L2_CID_EXPOSURE_METERING: return "Exposure, Metering Mode"; - case V4L2_CID_SCENE_MODE: return "Scene Mode"; - case V4L2_CID_3A_LOCK: return "3A Lock"; - case V4L2_CID_AUTO_FOCUS_START: return "Auto Focus, Start"; - case V4L2_CID_AUTO_FOCUS_STOP: return "Auto Focus, Stop"; - case V4L2_CID_AUTO_FOCUS_STATUS: return "Auto Focus, Status"; - case V4L2_CID_AUTO_FOCUS_RANGE: return "Auto Focus, Range"; - case V4L2_CID_PAN_SPEED: return "Pan, Speed"; - case V4L2_CID_TILT_SPEED: return "Tilt, Speed"; - case V4L2_CID_UNIT_CELL_SIZE: return "Unit Cell Size"; - case V4L2_CID_CAMERA_ORIENTATION: return "Camera Orientation"; - case V4L2_CID_CAMERA_SENSOR_ROTATION: return "Camera Sensor Rotation"; - - /* FM Radio Modulator controls */ - /* Keep the order of the 'case's the same as in v4l2-controls.h! */ - case V4L2_CID_FM_TX_CLASS: return "FM Radio Modulator Controls"; - case V4L2_CID_RDS_TX_DEVIATION: return "RDS Signal Deviation"; - case V4L2_CID_RDS_TX_PI: return "RDS Program ID"; - case V4L2_CID_RDS_TX_PTY: return "RDS Program Type"; - case V4L2_CID_RDS_TX_PS_NAME: return "RDS PS Name"; - case V4L2_CID_RDS_TX_RADIO_TEXT: return "RDS Radio Text"; - case V4L2_CID_RDS_TX_MONO_STEREO: return "RDS Stereo"; - case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD: return "RDS Artificial Head"; - case V4L2_CID_RDS_TX_COMPRESSED: return "RDS Compressed"; - case V4L2_CID_RDS_TX_DYNAMIC_PTY: return "RDS Dynamic PTY"; - case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT: return "RDS Traffic Announcement"; - case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM: return "RDS Traffic Program"; - case V4L2_CID_RDS_TX_MUSIC_SPEECH: return "RDS Music"; - case V4L2_CID_RDS_TX_ALT_FREQS_ENABLE: return "RDS Enable Alt Frequencies"; - case V4L2_CID_RDS_TX_ALT_FREQS: return "RDS Alternate Frequencies"; - case V4L2_CID_AUDIO_LIMITER_ENABLED: return "Audio Limiter Feature Enabled"; - case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time"; - case V4L2_CID_AUDIO_LIMITER_DEVIATION: return "Audio Limiter Deviation"; - case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Enabled"; - case V4L2_CID_AUDIO_COMPRESSION_GAIN: return "Audio Compression Gain"; - case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold"; - case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time"; - case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: return "Audio Compression Release Time"; - case V4L2_CID_PILOT_TONE_ENABLED: return "Pilot Tone Feature Enabled"; - case V4L2_CID_PILOT_TONE_DEVIATION: return "Pilot Tone Deviation"; - case V4L2_CID_PILOT_TONE_FREQUENCY: return "Pilot Tone Frequency"; - case V4L2_CID_TUNE_PREEMPHASIS: return "Pre-Emphasis"; - case V4L2_CID_TUNE_POWER_LEVEL: return "Tune Power Level"; - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: return "Tune Antenna Capacitor"; - - /* Flash controls */ - /* Keep the order of the 'case's the same as in v4l2-controls.h! */ - case V4L2_CID_FLASH_CLASS: return "Flash Controls"; - case V4L2_CID_FLASH_LED_MODE: return "LED Mode"; - case V4L2_CID_FLASH_STROBE_SOURCE: return "Strobe Source"; - case V4L2_CID_FLASH_STROBE: return "Strobe"; - case V4L2_CID_FLASH_STROBE_STOP: return "Stop Strobe"; - case V4L2_CID_FLASH_STROBE_STATUS: return "Strobe Status"; - case V4L2_CID_FLASH_TIMEOUT: return "Strobe Timeout"; - case V4L2_CID_FLASH_INTENSITY: return "Intensity, Flash Mode"; - case V4L2_CID_FLASH_TORCH_INTENSITY: return "Intensity, Torch Mode"; - case V4L2_CID_FLASH_INDICATOR_INTENSITY: return "Intensity, Indicator"; - case V4L2_CID_FLASH_FAULT: return "Faults"; - case V4L2_CID_FLASH_CHARGE: return "Charge"; - case V4L2_CID_FLASH_READY: return "Ready to Strobe"; - - /* JPEG encoder controls */ - /* Keep the order of the 'case's the same as in v4l2-controls.h! */ - case V4L2_CID_JPEG_CLASS: return "JPEG Compression Controls"; - case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: return "Chroma Subsampling"; - case V4L2_CID_JPEG_RESTART_INTERVAL: return "Restart Interval"; - case V4L2_CID_JPEG_COMPRESSION_QUALITY: return "Compression Quality"; - case V4L2_CID_JPEG_ACTIVE_MARKER: return "Active Markers"; - - /* Image source controls */ - /* Keep the order of the 'case's the same as in v4l2-controls.h! */ - case V4L2_CID_IMAGE_SOURCE_CLASS: return "Image Source Controls"; - case V4L2_CID_VBLANK: return "Vertical Blanking"; - case V4L2_CID_HBLANK: return "Horizontal Blanking"; - case V4L2_CID_ANALOGUE_GAIN: return "Analogue Gain"; - case V4L2_CID_TEST_PATTERN_RED: return "Red Pixel Value"; - case V4L2_CID_TEST_PATTERN_GREENR: return "Green (Red) Pixel Value"; - case V4L2_CID_TEST_PATTERN_BLUE: return "Blue Pixel Value"; - case V4L2_CID_TEST_PATTERN_GREENB: return "Green (Blue) Pixel Value"; - - /* Image processing controls */ - /* Keep the order of the 'case's the same as in v4l2-controls.h! */ - case V4L2_CID_IMAGE_PROC_CLASS: return "Image Processing Controls"; - case V4L2_CID_LINK_FREQ: return "Link Frequency"; - case V4L2_CID_PIXEL_RATE: return "Pixel Rate"; - case V4L2_CID_TEST_PATTERN: return "Test Pattern"; - case V4L2_CID_DEINTERLACING_MODE: return "Deinterlacing Mode"; - case V4L2_CID_DIGITAL_GAIN: return "Digital Gain"; - - /* DV controls */ - /* Keep the order of the 'case's the same as in v4l2-controls.h! */ - case V4L2_CID_DV_CLASS: return "Digital Video Controls"; - case V4L2_CID_DV_TX_HOTPLUG: return "Hotplug Present"; - case V4L2_CID_DV_TX_RXSENSE: return "RxSense Present"; - case V4L2_CID_DV_TX_EDID_PRESENT: return "EDID Present"; - case V4L2_CID_DV_TX_MODE: return "Transmit Mode"; - case V4L2_CID_DV_TX_RGB_RANGE: return "Tx RGB Quantization Range"; - case V4L2_CID_DV_TX_IT_CONTENT_TYPE: return "Tx IT Content Type"; - case V4L2_CID_DV_RX_POWER_PRESENT: return "Power Present"; - case V4L2_CID_DV_RX_RGB_RANGE: return "Rx RGB Quantization Range"; - case V4L2_CID_DV_RX_IT_CONTENT_TYPE: return "Rx IT Content Type"; - - case V4L2_CID_FM_RX_CLASS: return "FM Radio Receiver Controls"; - case V4L2_CID_TUNE_DEEMPHASIS: return "De-Emphasis"; - case V4L2_CID_RDS_RECEPTION: return "RDS Reception"; - case V4L2_CID_RF_TUNER_CLASS: return "RF Tuner Controls"; - case V4L2_CID_RF_TUNER_RF_GAIN: return "RF Gain"; - case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: return "LNA Gain, Auto"; - case V4L2_CID_RF_TUNER_LNA_GAIN: return "LNA Gain"; - case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: return "Mixer Gain, Auto"; - case V4L2_CID_RF_TUNER_MIXER_GAIN: return "Mixer Gain"; - case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: return "IF Gain, Auto"; - case V4L2_CID_RF_TUNER_IF_GAIN: return "IF Gain"; - case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: return "Bandwidth, Auto"; - case V4L2_CID_RF_TUNER_BANDWIDTH: return "Bandwidth"; - case V4L2_CID_RF_TUNER_PLL_LOCK: return "PLL Lock"; - case V4L2_CID_RDS_RX_PTY: return "RDS Program Type"; - case V4L2_CID_RDS_RX_PS_NAME: return "RDS PS Name"; - case V4L2_CID_RDS_RX_RADIO_TEXT: return "RDS Radio Text"; - case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT: return "RDS Traffic Announcement"; - case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM: return "RDS Traffic Program"; - case V4L2_CID_RDS_RX_MUSIC_SPEECH: return "RDS Music"; - - /* Detection controls */ - /* Keep the order of the 'case's the same as in v4l2-controls.h! */ - case V4L2_CID_DETECT_CLASS: return "Detection Controls"; - case V4L2_CID_DETECT_MD_MODE: return "Motion Detection Mode"; - case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD: return "MD Global Threshold"; - case V4L2_CID_DETECT_MD_THRESHOLD_GRID: return "MD Threshold Grid"; - case V4L2_CID_DETECT_MD_REGION_GRID: return "MD Region Grid"; - - /* Stateless Codec controls */ - /* Keep the order of the 'case's the same as in v4l2-controls.h! */ - case V4L2_CID_CODEC_STATELESS_CLASS: return "Stateless Codec Controls"; - case V4L2_CID_STATELESS_H264_DECODE_MODE: return "H264 Decode Mode"; - case V4L2_CID_STATELESS_H264_START_CODE: return "H264 Start Code"; - case V4L2_CID_STATELESS_H264_SPS: return "H264 Sequence Parameter Set"; - case V4L2_CID_STATELESS_H264_PPS: return "H264 Picture Parameter Set"; - case V4L2_CID_STATELESS_H264_SCALING_MATRIX: return "H264 Scaling Matrix"; - case V4L2_CID_STATELESS_H264_PRED_WEIGHTS: return "H264 Prediction Weight Table"; - case V4L2_CID_STATELESS_H264_SLICE_PARAMS: return "H264 Slice Parameters"; - case V4L2_CID_STATELESS_H264_DECODE_PARAMS: return "H264 Decode Parameters"; - case V4L2_CID_STATELESS_FWHT_PARAMS: return "FWHT Stateless Parameters"; - case V4L2_CID_STATELESS_VP8_FRAME: return "VP8 Frame Parameters"; - case V4L2_CID_STATELESS_MPEG2_SEQUENCE: return "MPEG-2 Sequence Header"; - case V4L2_CID_STATELESS_MPEG2_PICTURE: return "MPEG-2 Picture Header"; - case V4L2_CID_STATELESS_MPEG2_QUANTISATION: return "MPEG-2 Quantisation Matrices"; - - /* Colorimetry controls */ - /* Keep the order of the 'case's the same as in v4l2-controls.h! */ - case V4L2_CID_COLORIMETRY_CLASS: return "Colorimetry Controls"; - case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO: return "HDR10 Content Light Info"; - case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY: return "HDR10 Mastering Display"; - default: - return NULL; - } -} -EXPORT_SYMBOL(v4l2_ctrl_get_name); - -void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, - s64 *min, s64 *max, u64 *step, s64 *def, u32 *flags) -{ - *name = v4l2_ctrl_get_name(id); - *flags = 0; - - switch (id) { - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_LOUDNESS: - case V4L2_CID_AUTO_WHITE_BALANCE: - case V4L2_CID_AUTOGAIN: - case V4L2_CID_HFLIP: - case V4L2_CID_VFLIP: - case V4L2_CID_HUE_AUTO: - case V4L2_CID_CHROMA_AGC: - case V4L2_CID_COLOR_KILLER: - case V4L2_CID_AUTOBRIGHTNESS: - case V4L2_CID_MPEG_AUDIO_MUTE: - case V4L2_CID_MPEG_VIDEO_MUTE: - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: - case V4L2_CID_MPEG_VIDEO_PULLDOWN: - case V4L2_CID_EXPOSURE_AUTO_PRIORITY: - case V4L2_CID_FOCUS_AUTO: - case V4L2_CID_PRIVACY: - case V4L2_CID_AUDIO_LIMITER_ENABLED: - case V4L2_CID_AUDIO_COMPRESSION_ENABLED: - case V4L2_CID_PILOT_TONE_ENABLED: - case V4L2_CID_ILLUMINATORS_1: - case V4L2_CID_ILLUMINATORS_2: - case V4L2_CID_FLASH_STROBE_STATUS: - case V4L2_CID_FLASH_CHARGE: - case V4L2_CID_FLASH_READY: - case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: - case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: - case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: - case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: - case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: - case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: - case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: - case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL: - case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: - case V4L2_CID_MPEG_VIDEO_AU_DELIMITER: - case V4L2_CID_WIDE_DYNAMIC_RANGE: - case V4L2_CID_IMAGE_STABILIZATION: - case V4L2_CID_RDS_RECEPTION: - case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: - case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: - case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: - case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: - case V4L2_CID_RF_TUNER_PLL_LOCK: - case V4L2_CID_RDS_TX_MONO_STEREO: - case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD: - case V4L2_CID_RDS_TX_COMPRESSED: - case V4L2_CID_RDS_TX_DYNAMIC_PTY: - case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT: - case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM: - case V4L2_CID_RDS_TX_MUSIC_SPEECH: - case V4L2_CID_RDS_TX_ALT_FREQS_ENABLE: - case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT: - case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM: - case V4L2_CID_RDS_RX_MUSIC_SPEECH: - *type = V4L2_CTRL_TYPE_BOOLEAN; - *min = 0; - *max = *step = 1; - break; - case V4L2_CID_ROTATE: - *type = V4L2_CTRL_TYPE_INTEGER; - *flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; - break; - case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: - case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: - case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: - *type = V4L2_CTRL_TYPE_INTEGER; - break; - case V4L2_CID_MPEG_VIDEO_LTR_COUNT: - *type = V4L2_CTRL_TYPE_INTEGER; - break; - case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX: - *type = V4L2_CTRL_TYPE_INTEGER; - *flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; - break; - case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES: - *type = V4L2_CTRL_TYPE_BITMASK; - *flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; - break; - case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: - case V4L2_CID_PAN_RESET: - case V4L2_CID_TILT_RESET: - case V4L2_CID_FLASH_STROBE: - case V4L2_CID_FLASH_STROBE_STOP: - case V4L2_CID_AUTO_FOCUS_START: - case V4L2_CID_AUTO_FOCUS_STOP: - case V4L2_CID_DO_WHITE_BALANCE: - *type = V4L2_CTRL_TYPE_BUTTON; - *flags |= V4L2_CTRL_FLAG_WRITE_ONLY | - V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; - *min = *max = *step = *def = 0; - break; - case V4L2_CID_POWER_LINE_FREQUENCY: - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: - case V4L2_CID_MPEG_AUDIO_ENCODING: - case V4L2_CID_MPEG_AUDIO_L1_BITRATE: - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: - case V4L2_CID_MPEG_AUDIO_L3_BITRATE: - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: - case V4L2_CID_MPEG_AUDIO_MODE: - case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: - case V4L2_CID_MPEG_AUDIO_EMPHASIS: - case V4L2_CID_MPEG_AUDIO_CRC: - case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: - case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: - case V4L2_CID_MPEG_VIDEO_ENCODING: - case V4L2_CID_MPEG_VIDEO_ASPECT: - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - case V4L2_CID_MPEG_STREAM_TYPE: - case V4L2_CID_MPEG_STREAM_VBI_FMT: - case V4L2_CID_EXPOSURE_AUTO: - case V4L2_CID_AUTO_FOCUS_RANGE: - case V4L2_CID_COLORFX: - case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: - case V4L2_CID_TUNE_PREEMPHASIS: - case V4L2_CID_FLASH_LED_MODE: - case V4L2_CID_FLASH_STROBE_SOURCE: - case V4L2_CID_MPEG_VIDEO_HEADER_MODE: - case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: - case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: - case V4L2_CID_MPEG_VIDEO_H264_LEVEL: - case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: - case V4L2_CID_MPEG_VIDEO_H264_PROFILE: - case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: - case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: - case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: - case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: - case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: - case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: - case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: - case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: - case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: - case V4L2_CID_ISO_SENSITIVITY_AUTO: - case V4L2_CID_EXPOSURE_METERING: - case V4L2_CID_SCENE_MODE: - case V4L2_CID_DV_TX_MODE: - case V4L2_CID_DV_TX_RGB_RANGE: - case V4L2_CID_DV_TX_IT_CONTENT_TYPE: - case V4L2_CID_DV_RX_RGB_RANGE: - case V4L2_CID_DV_RX_IT_CONTENT_TYPE: - case V4L2_CID_TEST_PATTERN: - case V4L2_CID_DEINTERLACING_MODE: - case V4L2_CID_TUNE_DEEMPHASIS: - case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: - case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: - case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: - case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: - case V4L2_CID_DETECT_MD_MODE: - case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: - case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: - case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: - case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: - case V4L2_CID_MPEG_VIDEO_HEVC_TIER: - case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: - case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: - case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: - case V4L2_CID_STATELESS_H264_DECODE_MODE: - case V4L2_CID_STATELESS_H264_START_CODE: - case V4L2_CID_CAMERA_ORIENTATION: - *type = V4L2_CTRL_TYPE_MENU; - break; - case V4L2_CID_LINK_FREQ: - *type = V4L2_CTRL_TYPE_INTEGER_MENU; - break; - case V4L2_CID_RDS_TX_PS_NAME: - case V4L2_CID_RDS_TX_RADIO_TEXT: - case V4L2_CID_RDS_RX_PS_NAME: - case V4L2_CID_RDS_RX_RADIO_TEXT: - *type = V4L2_CTRL_TYPE_STRING; - break; - case V4L2_CID_ISO_SENSITIVITY: - case V4L2_CID_AUTO_EXPOSURE_BIAS: - case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: - case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES: - *type = V4L2_CTRL_TYPE_INTEGER_MENU; - break; - case V4L2_CID_USER_CLASS: - case V4L2_CID_CAMERA_CLASS: - case V4L2_CID_CODEC_CLASS: - case V4L2_CID_FM_TX_CLASS: - case V4L2_CID_FLASH_CLASS: - case V4L2_CID_JPEG_CLASS: - case V4L2_CID_IMAGE_SOURCE_CLASS: - case V4L2_CID_IMAGE_PROC_CLASS: - case V4L2_CID_DV_CLASS: - case V4L2_CID_FM_RX_CLASS: - case V4L2_CID_RF_TUNER_CLASS: - case V4L2_CID_DETECT_CLASS: - case V4L2_CID_CODEC_STATELESS_CLASS: - case V4L2_CID_COLORIMETRY_CLASS: - *type = V4L2_CTRL_TYPE_CTRL_CLASS; - /* You can neither read nor write these */ - *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY; - *min = *max = *step = *def = 0; - break; - case V4L2_CID_BG_COLOR: - *type = V4L2_CTRL_TYPE_INTEGER; - *step = 1; - *min = 0; - /* Max is calculated as RGB888 that is 2^24 */ - *max = 0xFFFFFF; - break; - case V4L2_CID_FLASH_FAULT: - case V4L2_CID_JPEG_ACTIVE_MARKER: - case V4L2_CID_3A_LOCK: - case V4L2_CID_AUTO_FOCUS_STATUS: - case V4L2_CID_DV_TX_HOTPLUG: - case V4L2_CID_DV_TX_RXSENSE: - case V4L2_CID_DV_TX_EDID_PRESENT: - case V4L2_CID_DV_RX_POWER_PRESENT: - *type = V4L2_CTRL_TYPE_BITMASK; - break; - case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: - case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: - *type = V4L2_CTRL_TYPE_INTEGER; - *flags |= V4L2_CTRL_FLAG_READ_ONLY; - break; - case V4L2_CID_MPEG_VIDEO_DEC_PTS: - *type = V4L2_CTRL_TYPE_INTEGER64; - *flags |= V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY; - *min = *def = 0; - *max = 0x1ffffffffLL; - *step = 1; - break; - case V4L2_CID_MPEG_VIDEO_DEC_FRAME: - *type = V4L2_CTRL_TYPE_INTEGER64; - *flags |= V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY; - *min = *def = 0; - *max = 0x7fffffffffffffffLL; - *step = 1; - break; - case V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR: - *type = V4L2_CTRL_TYPE_INTEGER64; - *min = 0; - /* default for 8 bit black, luma is 16, chroma is 128 */ - *def = 0x8000800010LL; - *max = 0xffffffffffffLL; - *step = 1; - break; - case V4L2_CID_PIXEL_RATE: - *type = V4L2_CTRL_TYPE_INTEGER64; - *flags |= V4L2_CTRL_FLAG_READ_ONLY; - break; - case V4L2_CID_DETECT_MD_REGION_GRID: - *type = V4L2_CTRL_TYPE_U8; - break; - case V4L2_CID_DETECT_MD_THRESHOLD_GRID: - *type = V4L2_CTRL_TYPE_U16; - break; - case V4L2_CID_RDS_TX_ALT_FREQS: - *type = V4L2_CTRL_TYPE_U32; - break; - case V4L2_CID_STATELESS_MPEG2_SEQUENCE: - *type = V4L2_CTRL_TYPE_MPEG2_SEQUENCE; - break; - case V4L2_CID_STATELESS_MPEG2_PICTURE: - *type = V4L2_CTRL_TYPE_MPEG2_PICTURE; - break; - case V4L2_CID_STATELESS_MPEG2_QUANTISATION: - *type = V4L2_CTRL_TYPE_MPEG2_QUANTISATION; - break; - case V4L2_CID_STATELESS_FWHT_PARAMS: - *type = V4L2_CTRL_TYPE_FWHT_PARAMS; - break; - case V4L2_CID_STATELESS_H264_SPS: - *type = V4L2_CTRL_TYPE_H264_SPS; - break; - case V4L2_CID_STATELESS_H264_PPS: - *type = V4L2_CTRL_TYPE_H264_PPS; - break; - case V4L2_CID_STATELESS_H264_SCALING_MATRIX: - *type = V4L2_CTRL_TYPE_H264_SCALING_MATRIX; - break; - case V4L2_CID_STATELESS_H264_SLICE_PARAMS: - *type = V4L2_CTRL_TYPE_H264_SLICE_PARAMS; - break; - case V4L2_CID_STATELESS_H264_DECODE_PARAMS: - *type = V4L2_CTRL_TYPE_H264_DECODE_PARAMS; - break; - case V4L2_CID_STATELESS_H264_PRED_WEIGHTS: - *type = V4L2_CTRL_TYPE_H264_PRED_WEIGHTS; - break; - case V4L2_CID_STATELESS_VP8_FRAME: - *type = V4L2_CTRL_TYPE_VP8_FRAME; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_SPS: - *type = V4L2_CTRL_TYPE_HEVC_SPS; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_PPS: - *type = V4L2_CTRL_TYPE_HEVC_PPS; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: - *type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS; - break; - case V4L2_CID_UNIT_CELL_SIZE: - *type = V4L2_CTRL_TYPE_AREA; - *flags |= V4L2_CTRL_FLAG_READ_ONLY; - break; - case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO: - *type = V4L2_CTRL_TYPE_HDR10_CLL_INFO; - break; - case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY: - *type = V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY; - break; - default: - *type = V4L2_CTRL_TYPE_INTEGER; - break; - } - switch (id) { - case V4L2_CID_MPEG_AUDIO_ENCODING: - case V4L2_CID_MPEG_AUDIO_MODE: - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - case V4L2_CID_MPEG_STREAM_TYPE: - *flags |= V4L2_CTRL_FLAG_UPDATE; - break; - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - case V4L2_CID_BRIGHTNESS: - case V4L2_CID_CONTRAST: - case V4L2_CID_SATURATION: - case V4L2_CID_HUE: - case V4L2_CID_RED_BALANCE: - case V4L2_CID_BLUE_BALANCE: - case V4L2_CID_GAMMA: - case V4L2_CID_SHARPNESS: - case V4L2_CID_CHROMA_GAIN: - case V4L2_CID_RDS_TX_DEVIATION: - case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: - case V4L2_CID_AUDIO_LIMITER_DEVIATION: - case V4L2_CID_AUDIO_COMPRESSION_GAIN: - case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: - case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: - case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: - case V4L2_CID_PILOT_TONE_DEVIATION: - case V4L2_CID_PILOT_TONE_FREQUENCY: - case V4L2_CID_TUNE_POWER_LEVEL: - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - case V4L2_CID_RF_TUNER_RF_GAIN: - case V4L2_CID_RF_TUNER_LNA_GAIN: - case V4L2_CID_RF_TUNER_MIXER_GAIN: - case V4L2_CID_RF_TUNER_IF_GAIN: - case V4L2_CID_RF_TUNER_BANDWIDTH: - case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD: - *flags |= V4L2_CTRL_FLAG_SLIDER; - break; - case V4L2_CID_PAN_RELATIVE: - case V4L2_CID_TILT_RELATIVE: - case V4L2_CID_FOCUS_RELATIVE: - case V4L2_CID_IRIS_RELATIVE: - case V4L2_CID_ZOOM_RELATIVE: - *flags |= V4L2_CTRL_FLAG_WRITE_ONLY | - V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; - break; - case V4L2_CID_FLASH_STROBE_STATUS: - case V4L2_CID_AUTO_FOCUS_STATUS: - case V4L2_CID_FLASH_READY: - case V4L2_CID_DV_TX_HOTPLUG: - case V4L2_CID_DV_TX_RXSENSE: - case V4L2_CID_DV_TX_EDID_PRESENT: - case V4L2_CID_DV_RX_POWER_PRESENT: - case V4L2_CID_DV_RX_IT_CONTENT_TYPE: - case V4L2_CID_RDS_RX_PTY: - case V4L2_CID_RDS_RX_PS_NAME: - case V4L2_CID_RDS_RX_RADIO_TEXT: - case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT: - case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM: - case V4L2_CID_RDS_RX_MUSIC_SPEECH: - case V4L2_CID_CAMERA_ORIENTATION: - case V4L2_CID_CAMERA_SENSOR_ROTATION: - *flags |= V4L2_CTRL_FLAG_READ_ONLY; - break; - case V4L2_CID_RF_TUNER_PLL_LOCK: - *flags |= V4L2_CTRL_FLAG_VOLATILE; - break; - } -} -EXPORT_SYMBOL(v4l2_ctrl_fill); - -static u32 user_flags(const struct v4l2_ctrl *ctrl) -{ - u32 flags = ctrl->flags; - - if (ctrl->is_ptr) - flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD; - - return flags; -} - -static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 changes) -{ - memset(ev, 0, sizeof(*ev)); - ev->type = V4L2_EVENT_CTRL; - ev->id = ctrl->id; - ev->u.ctrl.changes = changes; - ev->u.ctrl.type = ctrl->type; - ev->u.ctrl.flags = user_flags(ctrl); - if (ctrl->is_ptr) - ev->u.ctrl.value64 = 0; - else - ev->u.ctrl.value64 = *ctrl->p_cur.p_s64; - ev->u.ctrl.minimum = ctrl->minimum; - ev->u.ctrl.maximum = ctrl->maximum; - if (ctrl->type == V4L2_CTRL_TYPE_MENU - || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU) - ev->u.ctrl.step = 1; - else - ev->u.ctrl.step = ctrl->step; - ev->u.ctrl.default_value = ctrl->default_value; -} - -static void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes) -{ - struct v4l2_event ev; - struct v4l2_subscribed_event *sev; - - if (list_empty(&ctrl->ev_subs)) - return; - fill_event(&ev, ctrl, changes); - - list_for_each_entry(sev, &ctrl->ev_subs, node) - if (sev->fh != fh || - (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK)) - v4l2_event_queue_fh(sev->fh, &ev); -} - -static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx, - union v4l2_ctrl_ptr ptr1, - union v4l2_ctrl_ptr ptr2) -{ - switch (ctrl->type) { - case V4L2_CTRL_TYPE_BUTTON: - return false; - case V4L2_CTRL_TYPE_STRING: - idx *= ctrl->elem_size; - /* strings are always 0-terminated */ - return !strcmp(ptr1.p_char + idx, ptr2.p_char + idx); - case V4L2_CTRL_TYPE_INTEGER64: - return ptr1.p_s64[idx] == ptr2.p_s64[idx]; - case V4L2_CTRL_TYPE_U8: - return ptr1.p_u8[idx] == ptr2.p_u8[idx]; - case V4L2_CTRL_TYPE_U16: - return ptr1.p_u16[idx] == ptr2.p_u16[idx]; - case V4L2_CTRL_TYPE_U32: - return ptr1.p_u32[idx] == ptr2.p_u32[idx]; - default: - if (ctrl->is_int) - return ptr1.p_s32[idx] == ptr2.p_s32[idx]; - idx *= ctrl->elem_size; - return !memcmp(ptr1.p_const + idx, ptr2.p_const + idx, - ctrl->elem_size); - } -} - -static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, - union v4l2_ctrl_ptr ptr) -{ - struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence; - struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture; - struct v4l2_ctrl_mpeg2_quantisation *p_mpeg2_quant; - struct v4l2_ctrl_vp8_frame *p_vp8_frame; - struct v4l2_ctrl_fwht_params *p_fwht_params; - void *p = ptr.p + idx * ctrl->elem_size; - - if (ctrl->p_def.p_const) - memcpy(p, ctrl->p_def.p_const, ctrl->elem_size); - else - memset(p, 0, ctrl->elem_size); - - switch ((u32)ctrl->type) { - case V4L2_CTRL_TYPE_MPEG2_SEQUENCE: - p_mpeg2_sequence = p; - - /* 4:2:0 */ - p_mpeg2_sequence->chroma_format = 1; - break; - case V4L2_CTRL_TYPE_MPEG2_PICTURE: - p_mpeg2_picture = p; - - /* interlaced top field */ - p_mpeg2_picture->picture_structure = V4L2_MPEG2_PIC_TOP_FIELD; - p_mpeg2_picture->picture_coding_type = - V4L2_MPEG2_PIC_CODING_TYPE_I; - break; - case V4L2_CTRL_TYPE_MPEG2_QUANTISATION: - p_mpeg2_quant = p; - - memcpy(p_mpeg2_quant->intra_quantiser_matrix, - mpeg2_intra_quant_matrix, - ARRAY_SIZE(mpeg2_intra_quant_matrix)); - /* - * The default non-intra MPEG-2 quantisation - * coefficients are all 16, as per the specification. - */ - memset(p_mpeg2_quant->non_intra_quantiser_matrix, 16, - sizeof(p_mpeg2_quant->non_intra_quantiser_matrix)); - break; - case V4L2_CTRL_TYPE_VP8_FRAME: - p_vp8_frame = p; - p_vp8_frame->num_dct_parts = 1; - break; - case V4L2_CTRL_TYPE_FWHT_PARAMS: - p_fwht_params = p; - p_fwht_params->version = V4L2_FWHT_VERSION; - p_fwht_params->width = 1280; - p_fwht_params->height = 720; - p_fwht_params->flags = V4L2_FWHT_FL_PIXENC_YUV | - (2 << V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET); - break; - } -} - -static void std_init(const struct v4l2_ctrl *ctrl, u32 idx, - union v4l2_ctrl_ptr ptr) -{ - switch (ctrl->type) { - case V4L2_CTRL_TYPE_STRING: - idx *= ctrl->elem_size; - memset(ptr.p_char + idx, ' ', ctrl->minimum); - ptr.p_char[idx + ctrl->minimum] = '\0'; - break; - case V4L2_CTRL_TYPE_INTEGER64: - ptr.p_s64[idx] = ctrl->default_value; - break; - case V4L2_CTRL_TYPE_INTEGER: - case V4L2_CTRL_TYPE_INTEGER_MENU: - case V4L2_CTRL_TYPE_MENU: - case V4L2_CTRL_TYPE_BITMASK: - case V4L2_CTRL_TYPE_BOOLEAN: - ptr.p_s32[idx] = ctrl->default_value; - break; - case V4L2_CTRL_TYPE_BUTTON: - case V4L2_CTRL_TYPE_CTRL_CLASS: - ptr.p_s32[idx] = 0; - break; - case V4L2_CTRL_TYPE_U8: - ptr.p_u8[idx] = ctrl->default_value; - break; - case V4L2_CTRL_TYPE_U16: - ptr.p_u16[idx] = ctrl->default_value; - break; - case V4L2_CTRL_TYPE_U32: - ptr.p_u32[idx] = ctrl->default_value; - break; - default: - std_init_compound(ctrl, idx, ptr); - break; - } -} - -static void std_log(const struct v4l2_ctrl *ctrl) -{ - union v4l2_ctrl_ptr ptr = ctrl->p_cur; - - if (ctrl->is_array) { - unsigned i; - - for (i = 0; i < ctrl->nr_of_dims; i++) - pr_cont("[%u]", ctrl->dims[i]); - pr_cont(" "); - } - - switch (ctrl->type) { - case V4L2_CTRL_TYPE_INTEGER: - pr_cont("%d", *ptr.p_s32); - break; - case V4L2_CTRL_TYPE_BOOLEAN: - pr_cont("%s", *ptr.p_s32 ? "true" : "false"); - break; - case V4L2_CTRL_TYPE_MENU: - pr_cont("%s", ctrl->qmenu[*ptr.p_s32]); - break; - case V4L2_CTRL_TYPE_INTEGER_MENU: - pr_cont("%lld", ctrl->qmenu_int[*ptr.p_s32]); - break; - case V4L2_CTRL_TYPE_BITMASK: - pr_cont("0x%08x", *ptr.p_s32); - break; - case V4L2_CTRL_TYPE_INTEGER64: - pr_cont("%lld", *ptr.p_s64); - break; - case V4L2_CTRL_TYPE_STRING: - pr_cont("%s", ptr.p_char); - break; - case V4L2_CTRL_TYPE_U8: - pr_cont("%u", (unsigned)*ptr.p_u8); - break; - case V4L2_CTRL_TYPE_U16: - pr_cont("%u", (unsigned)*ptr.p_u16); - break; - case V4L2_CTRL_TYPE_U32: - pr_cont("%u", (unsigned)*ptr.p_u32); - break; - case V4L2_CTRL_TYPE_H264_SPS: - pr_cont("H264_SPS"); - break; - case V4L2_CTRL_TYPE_H264_PPS: - pr_cont("H264_PPS"); - break; - case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: - pr_cont("H264_SCALING_MATRIX"); - break; - case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: - pr_cont("H264_SLICE_PARAMS"); - break; - case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: - pr_cont("H264_DECODE_PARAMS"); - break; - case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: - pr_cont("H264_PRED_WEIGHTS"); - break; - case V4L2_CTRL_TYPE_FWHT_PARAMS: - pr_cont("FWHT_PARAMS"); - break; - case V4L2_CTRL_TYPE_VP8_FRAME: - pr_cont("VP8_FRAME"); - break; - case V4L2_CTRL_TYPE_HDR10_CLL_INFO: - pr_cont("HDR10_CLL_INFO"); - break; - case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY: - pr_cont("HDR10_MASTERING_DISPLAY"); - break; - case V4L2_CTRL_TYPE_MPEG2_QUANTISATION: - pr_cont("MPEG2_QUANTISATION"); - break; - case V4L2_CTRL_TYPE_MPEG2_SEQUENCE: - pr_cont("MPEG2_SEQUENCE"); - break; - case V4L2_CTRL_TYPE_MPEG2_PICTURE: - pr_cont("MPEG2_PICTURE"); - break; - default: - pr_cont("unknown type %d", ctrl->type); - break; - } -} - -/* - * Round towards the closest legal value. Be careful when we are - * close to the maximum range of the control type to prevent - * wrap-arounds. - */ -#define ROUND_TO_RANGE(val, offset_type, ctrl) \ -({ \ - offset_type offset; \ - if ((ctrl)->maximum >= 0 && \ - val >= (ctrl)->maximum - (s32)((ctrl)->step / 2)) \ - val = (ctrl)->maximum; \ - else \ - val += (s32)((ctrl)->step / 2); \ - val = clamp_t(typeof(val), val, \ - (ctrl)->minimum, (ctrl)->maximum); \ - offset = (val) - (ctrl)->minimum; \ - offset = (ctrl)->step * (offset / (u32)(ctrl)->step); \ - val = (ctrl)->minimum + offset; \ - 0; \ -}) - -/* Validate a new control */ - -#define zero_padding(s) \ - memset(&(s).padding, 0, sizeof((s).padding)) -#define zero_reserved(s) \ - memset(&(s).reserved, 0, sizeof((s).reserved)) - -/* - * Compound controls validation requires setting unused fields/flags to zero - * in order to properly detect unchanged controls with std_equal's memcmp. - */ -static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, - union v4l2_ctrl_ptr ptr) -{ - struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence; - struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture; - struct v4l2_ctrl_vp8_frame *p_vp8_frame; - struct v4l2_ctrl_fwht_params *p_fwht_params; - struct v4l2_ctrl_h264_sps *p_h264_sps; - struct v4l2_ctrl_h264_pps *p_h264_pps; - struct v4l2_ctrl_h264_pred_weights *p_h264_pred_weights; - struct v4l2_ctrl_h264_slice_params *p_h264_slice_params; - struct v4l2_ctrl_h264_decode_params *p_h264_dec_params; - struct v4l2_ctrl_hevc_sps *p_hevc_sps; - struct v4l2_ctrl_hevc_pps *p_hevc_pps; - struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params; - struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering; - struct v4l2_area *area; - void *p = ptr.p + idx * ctrl->elem_size; - unsigned int i; - - switch ((u32)ctrl->type) { - case V4L2_CTRL_TYPE_MPEG2_SEQUENCE: - p_mpeg2_sequence = p; - - switch (p_mpeg2_sequence->chroma_format) { - case 1: /* 4:2:0 */ - case 2: /* 4:2:2 */ - case 3: /* 4:4:4 */ - break; - default: - return -EINVAL; - } - break; - - case V4L2_CTRL_TYPE_MPEG2_PICTURE: - p_mpeg2_picture = p; - - switch (p_mpeg2_picture->intra_dc_precision) { - case 0: /* 8 bits */ - case 1: /* 9 bits */ - case 2: /* 10 bits */ - case 3: /* 11 bits */ - break; - default: - return -EINVAL; - } - - switch (p_mpeg2_picture->picture_structure) { - case V4L2_MPEG2_PIC_TOP_FIELD: - case V4L2_MPEG2_PIC_BOTTOM_FIELD: - case V4L2_MPEG2_PIC_FRAME: - break; - default: - return -EINVAL; - } - - switch (p_mpeg2_picture->picture_coding_type) { - case V4L2_MPEG2_PIC_CODING_TYPE_I: - case V4L2_MPEG2_PIC_CODING_TYPE_P: - case V4L2_MPEG2_PIC_CODING_TYPE_B: - break; - default: - return -EINVAL; - } - zero_reserved(*p_mpeg2_picture); - break; - - case V4L2_CTRL_TYPE_MPEG2_QUANTISATION: - break; - - case V4L2_CTRL_TYPE_FWHT_PARAMS: - p_fwht_params = p; - if (p_fwht_params->version < V4L2_FWHT_VERSION) - return -EINVAL; - if (!p_fwht_params->width || !p_fwht_params->height) - return -EINVAL; - break; - - case V4L2_CTRL_TYPE_H264_SPS: - p_h264_sps = p; - - /* Some syntax elements are only conditionally valid */ - if (p_h264_sps->pic_order_cnt_type != 0) { - p_h264_sps->log2_max_pic_order_cnt_lsb_minus4 = 0; - } else if (p_h264_sps->pic_order_cnt_type != 1) { - p_h264_sps->num_ref_frames_in_pic_order_cnt_cycle = 0; - p_h264_sps->offset_for_non_ref_pic = 0; - p_h264_sps->offset_for_top_to_bottom_field = 0; - memset(&p_h264_sps->offset_for_ref_frame, 0, - sizeof(p_h264_sps->offset_for_ref_frame)); - } - - if (!V4L2_H264_SPS_HAS_CHROMA_FORMAT(p_h264_sps)) { - p_h264_sps->chroma_format_idc = 1; - p_h264_sps->bit_depth_luma_minus8 = 0; - p_h264_sps->bit_depth_chroma_minus8 = 0; - - p_h264_sps->flags &= - ~V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS; - - if (p_h264_sps->chroma_format_idc < 3) - p_h264_sps->flags &= - ~V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE; - } - - if (p_h264_sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) - p_h264_sps->flags &= - ~V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD; - - /* - * Chroma 4:2:2 format require at least High 4:2:2 profile. - * - * The H264 specification and well-known parser implementations - * use profile-idc values directly, as that is clearer and - * less ambiguous. We do the same here. - */ - if (p_h264_sps->profile_idc < 122 && - p_h264_sps->chroma_format_idc > 1) - return -EINVAL; - /* Chroma 4:4:4 format require at least High 4:2:2 profile */ - if (p_h264_sps->profile_idc < 244 && - p_h264_sps->chroma_format_idc > 2) - return -EINVAL; - if (p_h264_sps->chroma_format_idc > 3) - return -EINVAL; - - if (p_h264_sps->bit_depth_luma_minus8 > 6) - return -EINVAL; - if (p_h264_sps->bit_depth_chroma_minus8 > 6) - return -EINVAL; - if (p_h264_sps->log2_max_frame_num_minus4 > 12) - return -EINVAL; - if (p_h264_sps->pic_order_cnt_type > 2) - return -EINVAL; - if (p_h264_sps->log2_max_pic_order_cnt_lsb_minus4 > 12) - return -EINVAL; - if (p_h264_sps->max_num_ref_frames > V4L2_H264_REF_LIST_LEN) - return -EINVAL; - break; - - case V4L2_CTRL_TYPE_H264_PPS: - p_h264_pps = p; - - if (p_h264_pps->num_slice_groups_minus1 > 7) - return -EINVAL; - if (p_h264_pps->num_ref_idx_l0_default_active_minus1 > - (V4L2_H264_REF_LIST_LEN - 1)) - return -EINVAL; - if (p_h264_pps->num_ref_idx_l1_default_active_minus1 > - (V4L2_H264_REF_LIST_LEN - 1)) - return -EINVAL; - if (p_h264_pps->weighted_bipred_idc > 2) - return -EINVAL; - /* - * pic_init_qp_minus26 shall be in the range of - * -(26 + QpBdOffset_y) to +25, inclusive, - * where QpBdOffset_y is 6 * bit_depth_luma_minus8 - */ - if (p_h264_pps->pic_init_qp_minus26 < -62 || - p_h264_pps->pic_init_qp_minus26 > 25) - return -EINVAL; - if (p_h264_pps->pic_init_qs_minus26 < -26 || - p_h264_pps->pic_init_qs_minus26 > 25) - return -EINVAL; - if (p_h264_pps->chroma_qp_index_offset < -12 || - p_h264_pps->chroma_qp_index_offset > 12) - return -EINVAL; - if (p_h264_pps->second_chroma_qp_index_offset < -12 || - p_h264_pps->second_chroma_qp_index_offset > 12) - return -EINVAL; - break; - - case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: - break; - - case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: - p_h264_pred_weights = p; - - if (p_h264_pred_weights->luma_log2_weight_denom > 7) - return -EINVAL; - if (p_h264_pred_weights->chroma_log2_weight_denom > 7) - return -EINVAL; - break; - - case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: - p_h264_slice_params = p; - - if (p_h264_slice_params->slice_type != V4L2_H264_SLICE_TYPE_B) - p_h264_slice_params->flags &= - ~V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED; - - if (p_h264_slice_params->colour_plane_id > 2) - return -EINVAL; - if (p_h264_slice_params->cabac_init_idc > 2) - return -EINVAL; - if (p_h264_slice_params->disable_deblocking_filter_idc > 2) - return -EINVAL; - if (p_h264_slice_params->slice_alpha_c0_offset_div2 < -6 || - p_h264_slice_params->slice_alpha_c0_offset_div2 > 6) - return -EINVAL; - if (p_h264_slice_params->slice_beta_offset_div2 < -6 || - p_h264_slice_params->slice_beta_offset_div2 > 6) - return -EINVAL; - - if (p_h264_slice_params->slice_type == V4L2_H264_SLICE_TYPE_I || - p_h264_slice_params->slice_type == V4L2_H264_SLICE_TYPE_SI) - p_h264_slice_params->num_ref_idx_l0_active_minus1 = 0; - if (p_h264_slice_params->slice_type != V4L2_H264_SLICE_TYPE_B) - p_h264_slice_params->num_ref_idx_l1_active_minus1 = 0; - - if (p_h264_slice_params->num_ref_idx_l0_active_minus1 > - (V4L2_H264_REF_LIST_LEN - 1)) - return -EINVAL; - if (p_h264_slice_params->num_ref_idx_l1_active_minus1 > - (V4L2_H264_REF_LIST_LEN - 1)) - return -EINVAL; - zero_reserved(*p_h264_slice_params); - break; - - case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: - p_h264_dec_params = p; - - if (p_h264_dec_params->nal_ref_idc > 3) - return -EINVAL; - for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) { - struct v4l2_h264_dpb_entry *dpb_entry = - &p_h264_dec_params->dpb[i]; - - zero_reserved(*dpb_entry); - } - zero_reserved(*p_h264_dec_params); - break; - - case V4L2_CTRL_TYPE_VP8_FRAME: - p_vp8_frame = p; - - switch (p_vp8_frame->num_dct_parts) { - case 1: - case 2: - case 4: - case 8: - break; - default: - return -EINVAL; - } - zero_padding(p_vp8_frame->segment); - zero_padding(p_vp8_frame->lf); - zero_padding(p_vp8_frame->quant); - zero_padding(p_vp8_frame->entropy); - zero_padding(p_vp8_frame->coder_state); - break; - - case V4L2_CTRL_TYPE_HEVC_SPS: - p_hevc_sps = p; - - if (!(p_hevc_sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED)) { - p_hevc_sps->pcm_sample_bit_depth_luma_minus1 = 0; - p_hevc_sps->pcm_sample_bit_depth_chroma_minus1 = 0; - p_hevc_sps->log2_min_pcm_luma_coding_block_size_minus3 = 0; - p_hevc_sps->log2_diff_max_min_pcm_luma_coding_block_size = 0; - } - - if (!(p_hevc_sps->flags & - V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT)) - p_hevc_sps->num_long_term_ref_pics_sps = 0; - break; - - case V4L2_CTRL_TYPE_HEVC_PPS: - p_hevc_pps = p; - - if (!(p_hevc_pps->flags & - V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED)) - p_hevc_pps->diff_cu_qp_delta_depth = 0; - - if (!(p_hevc_pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED)) { - p_hevc_pps->num_tile_columns_minus1 = 0; - p_hevc_pps->num_tile_rows_minus1 = 0; - memset(&p_hevc_pps->column_width_minus1, 0, - sizeof(p_hevc_pps->column_width_minus1)); - memset(&p_hevc_pps->row_height_minus1, 0, - sizeof(p_hevc_pps->row_height_minus1)); - - p_hevc_pps->flags &= - ~V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED; - } - - if (p_hevc_pps->flags & - V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER) { - p_hevc_pps->pps_beta_offset_div2 = 0; - p_hevc_pps->pps_tc_offset_div2 = 0; - } - - zero_padding(*p_hevc_pps); - break; - - case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: - p_hevc_slice_params = p; - - if (p_hevc_slice_params->num_active_dpb_entries > - V4L2_HEVC_DPB_ENTRIES_NUM_MAX) - return -EINVAL; - - zero_padding(p_hevc_slice_params->pred_weight_table); - - for (i = 0; i < p_hevc_slice_params->num_active_dpb_entries; - i++) { - struct v4l2_hevc_dpb_entry *dpb_entry = - &p_hevc_slice_params->dpb[i]; - - zero_padding(*dpb_entry); - } - - zero_padding(*p_hevc_slice_params); - break; - - case V4L2_CTRL_TYPE_HDR10_CLL_INFO: - break; - - case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY: - p_hdr10_mastering = p; - - for (i = 0; i < 3; ++i) { - if (p_hdr10_mastering->display_primaries_x[i] < - V4L2_HDR10_MASTERING_PRIMARIES_X_LOW || - p_hdr10_mastering->display_primaries_x[i] > - V4L2_HDR10_MASTERING_PRIMARIES_X_HIGH || - p_hdr10_mastering->display_primaries_y[i] < - V4L2_HDR10_MASTERING_PRIMARIES_Y_LOW || - p_hdr10_mastering->display_primaries_y[i] > - V4L2_HDR10_MASTERING_PRIMARIES_Y_HIGH) - return -EINVAL; - } - - if (p_hdr10_mastering->white_point_x < - V4L2_HDR10_MASTERING_WHITE_POINT_X_LOW || - p_hdr10_mastering->white_point_x > - V4L2_HDR10_MASTERING_WHITE_POINT_X_HIGH || - p_hdr10_mastering->white_point_y < - V4L2_HDR10_MASTERING_WHITE_POINT_Y_LOW || - p_hdr10_mastering->white_point_y > - V4L2_HDR10_MASTERING_WHITE_POINT_Y_HIGH) - return -EINVAL; - - if (p_hdr10_mastering->max_display_mastering_luminance < - V4L2_HDR10_MASTERING_MAX_LUMA_LOW || - p_hdr10_mastering->max_display_mastering_luminance > - V4L2_HDR10_MASTERING_MAX_LUMA_HIGH || - p_hdr10_mastering->min_display_mastering_luminance < - V4L2_HDR10_MASTERING_MIN_LUMA_LOW || - p_hdr10_mastering->min_display_mastering_luminance > - V4L2_HDR10_MASTERING_MIN_LUMA_HIGH) - return -EINVAL; - - /* The following restriction comes from ITU-T Rec. H.265 spec */ - if (p_hdr10_mastering->max_display_mastering_luminance == - V4L2_HDR10_MASTERING_MAX_LUMA_LOW && - p_hdr10_mastering->min_display_mastering_luminance == - V4L2_HDR10_MASTERING_MIN_LUMA_HIGH) - return -EINVAL; - - break; - - case V4L2_CTRL_TYPE_AREA: - area = p; - if (!area->width || !area->height) - return -EINVAL; - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, - union v4l2_ctrl_ptr ptr) -{ - size_t len; - u64 offset; - s64 val; - - switch ((u32)ctrl->type) { - case V4L2_CTRL_TYPE_INTEGER: - return ROUND_TO_RANGE(ptr.p_s32[idx], u32, ctrl); - case V4L2_CTRL_TYPE_INTEGER64: - /* - * We can't use the ROUND_TO_RANGE define here due to - * the u64 divide that needs special care. - */ - val = ptr.p_s64[idx]; - if (ctrl->maximum >= 0 && val >= ctrl->maximum - (s64)(ctrl->step / 2)) - val = ctrl->maximum; - else - val += (s64)(ctrl->step / 2); - val = clamp_t(s64, val, ctrl->minimum, ctrl->maximum); - offset = val - ctrl->minimum; - do_div(offset, ctrl->step); - ptr.p_s64[idx] = ctrl->minimum + offset * ctrl->step; - return 0; - case V4L2_CTRL_TYPE_U8: - return ROUND_TO_RANGE(ptr.p_u8[idx], u8, ctrl); - case V4L2_CTRL_TYPE_U16: - return ROUND_TO_RANGE(ptr.p_u16[idx], u16, ctrl); - case V4L2_CTRL_TYPE_U32: - return ROUND_TO_RANGE(ptr.p_u32[idx], u32, ctrl); - - case V4L2_CTRL_TYPE_BOOLEAN: - ptr.p_s32[idx] = !!ptr.p_s32[idx]; - return 0; - - case V4L2_CTRL_TYPE_MENU: - case V4L2_CTRL_TYPE_INTEGER_MENU: - if (ptr.p_s32[idx] < ctrl->minimum || ptr.p_s32[idx] > ctrl->maximum) - return -ERANGE; - if (ptr.p_s32[idx] < BITS_PER_LONG_LONG && - (ctrl->menu_skip_mask & BIT_ULL(ptr.p_s32[idx]))) - return -EINVAL; - if (ctrl->type == V4L2_CTRL_TYPE_MENU && - ctrl->qmenu[ptr.p_s32[idx]][0] == '\0') - return -EINVAL; - return 0; - - case V4L2_CTRL_TYPE_BITMASK: - ptr.p_s32[idx] &= ctrl->maximum; - return 0; - - case V4L2_CTRL_TYPE_BUTTON: - case V4L2_CTRL_TYPE_CTRL_CLASS: - ptr.p_s32[idx] = 0; - return 0; - - case V4L2_CTRL_TYPE_STRING: - idx *= ctrl->elem_size; - len = strlen(ptr.p_char + idx); - if (len < ctrl->minimum) - return -ERANGE; - if ((len - (u32)ctrl->minimum) % (u32)ctrl->step) - return -ERANGE; - return 0; - - default: - return std_validate_compound(ctrl, idx, ptr); - } -} - -static const struct v4l2_ctrl_type_ops std_type_ops = { - .equal = std_equal, - .init = std_init, - .log = std_log, - .validate = std_validate, -}; - -/* Helper function: copy the given control value back to the caller */ -static int ptr_to_user(struct v4l2_ext_control *c, - struct v4l2_ctrl *ctrl, - union v4l2_ctrl_ptr ptr) -{ - u32 len; - - if (ctrl->is_ptr && !ctrl->is_string) - return copy_to_user(c->ptr, ptr.p_const, c->size) ? - -EFAULT : 0; - - switch (ctrl->type) { - case V4L2_CTRL_TYPE_STRING: - len = strlen(ptr.p_char); - if (c->size < len + 1) { - c->size = ctrl->elem_size; - return -ENOSPC; - } - return copy_to_user(c->string, ptr.p_char, len + 1) ? - -EFAULT : 0; - case V4L2_CTRL_TYPE_INTEGER64: - c->value64 = *ptr.p_s64; - break; - default: - c->value = *ptr.p_s32; - break; - } - return 0; -} - -/* Helper function: copy the current control value back to the caller */ -static int cur_to_user(struct v4l2_ext_control *c, - struct v4l2_ctrl *ctrl) -{ - return ptr_to_user(c, ctrl, ctrl->p_cur); -} - -/* Helper function: copy the new control value back to the caller */ -static int new_to_user(struct v4l2_ext_control *c, - struct v4l2_ctrl *ctrl) -{ - return ptr_to_user(c, ctrl, ctrl->p_new); -} - -/* Helper function: copy the request value back to the caller */ -static int req_to_user(struct v4l2_ext_control *c, - struct v4l2_ctrl_ref *ref) -{ - return ptr_to_user(c, ref->ctrl, ref->p_req); -} - -/* Helper function: copy the initial control value back to the caller */ -static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl) -{ - int idx; - - for (idx = 0; idx < ctrl->elems; idx++) - ctrl->type_ops->init(ctrl, idx, ctrl->p_new); - - return ptr_to_user(c, ctrl, ctrl->p_new); -} - -/* Helper function: copy the caller-provider value to the given control value */ -static int user_to_ptr(struct v4l2_ext_control *c, - struct v4l2_ctrl *ctrl, - union v4l2_ctrl_ptr ptr) -{ - int ret; - u32 size; - - ctrl->is_new = 1; - if (ctrl->is_ptr && !ctrl->is_string) { - unsigned idx; - - ret = copy_from_user(ptr.p, c->ptr, c->size) ? -EFAULT : 0; - if (ret || !ctrl->is_array) - return ret; - for (idx = c->size / ctrl->elem_size; idx < ctrl->elems; idx++) - ctrl->type_ops->init(ctrl, idx, ptr); - return 0; - } - - switch (ctrl->type) { - case V4L2_CTRL_TYPE_INTEGER64: - *ptr.p_s64 = c->value64; - break; - case V4L2_CTRL_TYPE_STRING: - size = c->size; - if (size == 0) - return -ERANGE; - if (size > ctrl->maximum + 1) - size = ctrl->maximum + 1; - ret = copy_from_user(ptr.p_char, c->string, size) ? -EFAULT : 0; - if (!ret) { - char last = ptr.p_char[size - 1]; - - ptr.p_char[size - 1] = 0; - /* If the string was longer than ctrl->maximum, - then return an error. */ - if (strlen(ptr.p_char) == ctrl->maximum && last) - return -ERANGE; - } - return ret; - default: - *ptr.p_s32 = c->value; - break; - } - return 0; -} - -/* Helper function: copy the caller-provider value as the new control value */ -static int user_to_new(struct v4l2_ext_control *c, - struct v4l2_ctrl *ctrl) -{ - return user_to_ptr(c, ctrl, ctrl->p_new); -} - -/* Copy the one value to another. */ -static void ptr_to_ptr(struct v4l2_ctrl *ctrl, - union v4l2_ctrl_ptr from, union v4l2_ctrl_ptr to) -{ - if (ctrl == NULL) - return; - memcpy(to.p, from.p_const, ctrl->elems * ctrl->elem_size); -} - -/* Copy the new value to the current value. */ -static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags) -{ - bool changed; - - if (ctrl == NULL) - return; - - /* has_changed is set by cluster_changed */ - changed = ctrl->has_changed; - if (changed) - ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur); - - if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) { - /* Note: CH_FLAGS is only set for auto clusters. */ - ctrl->flags &= - ~(V4L2_CTRL_FLAG_INACTIVE | V4L2_CTRL_FLAG_VOLATILE); - if (!is_cur_manual(ctrl->cluster[0])) { - ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - if (ctrl->cluster[0]->has_volatiles) - ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; - } - fh = NULL; - } - if (changed || ch_flags) { - /* If a control was changed that was not one of the controls - modified by the application, then send the event to all. */ - if (!ctrl->is_new) - fh = NULL; - send_event(fh, ctrl, - (changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) | ch_flags); - if (ctrl->call_notify && changed && ctrl->handler->notify) - ctrl->handler->notify(ctrl, ctrl->handler->notify_priv); - } -} - -/* Copy the current value to the new value */ -static void cur_to_new(struct v4l2_ctrl *ctrl) -{ - if (ctrl == NULL) - return; - ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new); -} - -/* Copy the new value to the request value */ -static void new_to_req(struct v4l2_ctrl_ref *ref) -{ - if (!ref) - return; - ptr_to_ptr(ref->ctrl, ref->ctrl->p_new, ref->p_req); - ref->valid_p_req = true; -} - -/* Copy the current value to the request value */ -static void cur_to_req(struct v4l2_ctrl_ref *ref) -{ - if (!ref) - return; - ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->p_req); - ref->valid_p_req = true; -} - -/* Copy the request value to the new value */ -static void req_to_new(struct v4l2_ctrl_ref *ref) -{ - if (!ref) - return; - if (ref->valid_p_req) - ptr_to_ptr(ref->ctrl, ref->p_req, ref->ctrl->p_new); - else - ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->ctrl->p_new); -} - -/* Return non-zero if one or more of the controls in the cluster has a new - value that differs from the current value. */ -static int cluster_changed(struct v4l2_ctrl *master) -{ - bool changed = false; - unsigned idx; - int i; - - for (i = 0; i < master->ncontrols; i++) { - struct v4l2_ctrl *ctrl = master->cluster[i]; - bool ctrl_changed = false; - - if (ctrl == NULL) - continue; - - if (ctrl->flags & V4L2_CTRL_FLAG_EXECUTE_ON_WRITE) - changed = ctrl_changed = true; - - /* - * Set has_changed to false to avoid generating - * the event V4L2_EVENT_CTRL_CH_VALUE - */ - if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) { - ctrl->has_changed = false; - continue; - } - - for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++) - ctrl_changed = !ctrl->type_ops->equal(ctrl, idx, - ctrl->p_cur, ctrl->p_new); - ctrl->has_changed = ctrl_changed; - changed |= ctrl->has_changed; - } - return changed; -} - -/* Control range checking */ -static int check_range(enum v4l2_ctrl_type type, - s64 min, s64 max, u64 step, s64 def) -{ - switch (type) { - case V4L2_CTRL_TYPE_BOOLEAN: - if (step != 1 || max > 1 || min < 0) - return -ERANGE; - fallthrough; - case V4L2_CTRL_TYPE_U8: - case V4L2_CTRL_TYPE_U16: - case V4L2_CTRL_TYPE_U32: - case V4L2_CTRL_TYPE_INTEGER: - case V4L2_CTRL_TYPE_INTEGER64: - if (step == 0 || min > max || def < min || def > max) - return -ERANGE; - return 0; - case V4L2_CTRL_TYPE_BITMASK: - if (step || min || !max || (def & ~max)) - return -ERANGE; - return 0; - case V4L2_CTRL_TYPE_MENU: - case V4L2_CTRL_TYPE_INTEGER_MENU: - if (min > max || def < min || def > max) - return -ERANGE; - /* Note: step == menu_skip_mask for menu controls. - So here we check if the default value is masked out. */ - if (step && ((1 << def) & step)) - return -EINVAL; - return 0; - case V4L2_CTRL_TYPE_STRING: - if (min > max || min < 0 || step < 1 || def) - return -ERANGE; - return 0; - default: - return 0; - } -} - -/* Validate a new control */ -static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new) -{ - unsigned idx; - int err = 0; - - for (idx = 0; !err && idx < ctrl->elems; idx++) - err = ctrl->type_ops->validate(ctrl, idx, p_new); - return err; -} - -static inline u32 node2id(struct list_head *node) -{ - return list_entry(node, struct v4l2_ctrl_ref, node)->ctrl->id; -} - -/* Set the handler's error code if it wasn't set earlier already */ -static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err) -{ - if (hdl->error == 0) - hdl->error = err; - return err; -} - -/* Initialize the handler */ -int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl, - unsigned nr_of_controls_hint, - struct lock_class_key *key, const char *name) -{ - mutex_init(&hdl->_lock); - hdl->lock = &hdl->_lock; - lockdep_set_class_and_name(hdl->lock, key, name); - INIT_LIST_HEAD(&hdl->ctrls); - INIT_LIST_HEAD(&hdl->ctrl_refs); - INIT_LIST_HEAD(&hdl->requests); - INIT_LIST_HEAD(&hdl->requests_queued); - hdl->request_is_queued = false; - hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8; - hdl->buckets = kvmalloc_array(hdl->nr_of_buckets, - sizeof(hdl->buckets[0]), - GFP_KERNEL | __GFP_ZERO); - hdl->error = hdl->buckets ? 0 : -ENOMEM; - media_request_object_init(&hdl->req_obj); - return hdl->error; -} -EXPORT_SYMBOL(v4l2_ctrl_handler_init_class); - -/* Free all controls and control refs */ -void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl) -{ - struct v4l2_ctrl_ref *ref, *next_ref; - struct v4l2_ctrl *ctrl, *next_ctrl; - struct v4l2_subscribed_event *sev, *next_sev; - - if (hdl == NULL || hdl->buckets == NULL) - return; - - /* - * If the main handler is freed and it is used by handler objects in - * outstanding requests, then unbind and put those objects before - * freeing the main handler. - * - * The main handler can be identified by having a NULL ops pointer in - * the request object. - */ - if (!hdl->req_obj.ops && !list_empty(&hdl->requests)) { - struct v4l2_ctrl_handler *req, *next_req; - - list_for_each_entry_safe(req, next_req, &hdl->requests, requests) { - media_request_object_unbind(&req->req_obj); - media_request_object_put(&req->req_obj); - } - } - mutex_lock(hdl->lock); - /* Free all nodes */ - list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) { - list_del(&ref->node); - kfree(ref); - } - /* Free all controls owned by the handler */ - list_for_each_entry_safe(ctrl, next_ctrl, &hdl->ctrls, node) { - list_del(&ctrl->node); - list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node) - list_del(&sev->node); - kvfree(ctrl); - } - kvfree(hdl->buckets); - hdl->buckets = NULL; - hdl->cached = NULL; - hdl->error = 0; - mutex_unlock(hdl->lock); - mutex_destroy(&hdl->_lock); -} -EXPORT_SYMBOL(v4l2_ctrl_handler_free); - -/* For backwards compatibility: V4L2_CID_PRIVATE_BASE should no longer - be used except in G_CTRL, S_CTRL, QUERYCTRL and QUERYMENU when dealing - with applications that do not use the NEXT_CTRL flag. - - We just find the n-th private user control. It's O(N), but that should not - be an issue in this particular case. */ -static struct v4l2_ctrl_ref *find_private_ref( - struct v4l2_ctrl_handler *hdl, u32 id) -{ - struct v4l2_ctrl_ref *ref; - - id -= V4L2_CID_PRIVATE_BASE; - list_for_each_entry(ref, &hdl->ctrl_refs, node) { - /* Search for private user controls that are compatible with - VIDIOC_G/S_CTRL. */ - if (V4L2_CTRL_ID2WHICH(ref->ctrl->id) == V4L2_CTRL_CLASS_USER && - V4L2_CTRL_DRIVER_PRIV(ref->ctrl->id)) { - if (!ref->ctrl->is_int) - continue; - if (id == 0) - return ref; - id--; - } - } - return NULL; -} - -/* Find a control with the given ID. */ -static struct v4l2_ctrl_ref *find_ref(struct v4l2_ctrl_handler *hdl, u32 id) -{ - struct v4l2_ctrl_ref *ref; - int bucket; - - id &= V4L2_CTRL_ID_MASK; - - /* Old-style private controls need special handling */ - if (id >= V4L2_CID_PRIVATE_BASE) - return find_private_ref(hdl, id); - bucket = id % hdl->nr_of_buckets; - - /* Simple optimization: cache the last control found */ - if (hdl->cached && hdl->cached->ctrl->id == id) - return hdl->cached; - - /* Not in cache, search the hash */ - ref = hdl->buckets ? hdl->buckets[bucket] : NULL; - while (ref && ref->ctrl->id != id) - ref = ref->next; - - if (ref) - hdl->cached = ref; /* cache it! */ - return ref; -} - -/* Find a control with the given ID. Take the handler's lock first. */ -static struct v4l2_ctrl_ref *find_ref_lock( - struct v4l2_ctrl_handler *hdl, u32 id) -{ - struct v4l2_ctrl_ref *ref = NULL; - - if (hdl) { - mutex_lock(hdl->lock); - ref = find_ref(hdl, id); - mutex_unlock(hdl->lock); - } - return ref; -} - -/* Find a control with the given ID. */ -struct v4l2_ctrl *v4l2_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id) -{ - struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id); - - return ref ? ref->ctrl : NULL; -} -EXPORT_SYMBOL(v4l2_ctrl_find); - -/* Allocate a new v4l2_ctrl_ref and hook it into the handler. */ -static int handler_new_ref(struct v4l2_ctrl_handler *hdl, - struct v4l2_ctrl *ctrl, - struct v4l2_ctrl_ref **ctrl_ref, - bool from_other_dev, bool allocate_req) -{ - struct v4l2_ctrl_ref *ref; - struct v4l2_ctrl_ref *new_ref; - u32 id = ctrl->id; - u32 class_ctrl = V4L2_CTRL_ID2WHICH(id) | 1; - int bucket = id % hdl->nr_of_buckets; /* which bucket to use */ - unsigned int size_extra_req = 0; - - if (ctrl_ref) - *ctrl_ref = NULL; - - /* - * Automatically add the control class if it is not yet present and - * the new control is not a compound control. - */ - if (ctrl->type < V4L2_CTRL_COMPOUND_TYPES && - id != class_ctrl && find_ref_lock(hdl, class_ctrl) == NULL) - if (!v4l2_ctrl_new_std(hdl, NULL, class_ctrl, 0, 0, 0, 0)) - return hdl->error; - - if (hdl->error) - return hdl->error; - - if (allocate_req) - size_extra_req = ctrl->elems * ctrl->elem_size; - new_ref = kzalloc(sizeof(*new_ref) + size_extra_req, GFP_KERNEL); - if (!new_ref) - return handler_set_err(hdl, -ENOMEM); - new_ref->ctrl = ctrl; - new_ref->from_other_dev = from_other_dev; - if (size_extra_req) - new_ref->p_req.p = &new_ref[1]; - - INIT_LIST_HEAD(&new_ref->node); - - mutex_lock(hdl->lock); - - /* Add immediately at the end of the list if the list is empty, or if - the last element in the list has a lower ID. - This ensures that when elements are added in ascending order the - insertion is an O(1) operation. */ - if (list_empty(&hdl->ctrl_refs) || id > node2id(hdl->ctrl_refs.prev)) { - list_add_tail(&new_ref->node, &hdl->ctrl_refs); - goto insert_in_hash; - } - - /* Find insert position in sorted list */ - list_for_each_entry(ref, &hdl->ctrl_refs, node) { - if (ref->ctrl->id < id) - continue; - /* Don't add duplicates */ - if (ref->ctrl->id == id) { - kfree(new_ref); - goto unlock; - } - list_add(&new_ref->node, ref->node.prev); - break; - } - -insert_in_hash: - /* Insert the control node in the hash */ - new_ref->next = hdl->buckets[bucket]; - hdl->buckets[bucket] = new_ref; - if (ctrl_ref) - *ctrl_ref = new_ref; - if (ctrl->handler == hdl) { - /* By default each control starts in a cluster of its own. - * new_ref->ctrl is basically a cluster array with one - * element, so that's perfect to use as the cluster pointer. - * But only do this for the handler that owns the control. - */ - ctrl->cluster = &new_ref->ctrl; - ctrl->ncontrols = 1; - } - -unlock: - mutex_unlock(hdl->lock); - return 0; -} - -/* Add a new control */ -static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, - const struct v4l2_ctrl_ops *ops, - const struct v4l2_ctrl_type_ops *type_ops, - u32 id, const char *name, enum v4l2_ctrl_type type, - s64 min, s64 max, u64 step, s64 def, - const u32 dims[V4L2_CTRL_MAX_DIMS], u32 elem_size, - u32 flags, const char * const *qmenu, - const s64 *qmenu_int, const union v4l2_ctrl_ptr p_def, - void *priv) -{ - struct v4l2_ctrl *ctrl; - unsigned sz_extra; - unsigned nr_of_dims = 0; - unsigned elems = 1; - bool is_array; - unsigned tot_ctrl_size; - unsigned idx; - void *data; - int err; - - if (hdl->error) - return NULL; - - while (dims && dims[nr_of_dims]) { - elems *= dims[nr_of_dims]; - nr_of_dims++; - if (nr_of_dims == V4L2_CTRL_MAX_DIMS) - break; - } - is_array = nr_of_dims > 0; - - /* Prefill elem_size for all types handled by std_type_ops */ - switch ((u32)type) { - case V4L2_CTRL_TYPE_INTEGER64: - elem_size = sizeof(s64); - break; - case V4L2_CTRL_TYPE_STRING: - elem_size = max + 1; - break; - case V4L2_CTRL_TYPE_U8: - elem_size = sizeof(u8); - break; - case V4L2_CTRL_TYPE_U16: - elem_size = sizeof(u16); - break; - case V4L2_CTRL_TYPE_U32: - elem_size = sizeof(u32); - break; - case V4L2_CTRL_TYPE_MPEG2_SEQUENCE: - elem_size = sizeof(struct v4l2_ctrl_mpeg2_sequence); - break; - case V4L2_CTRL_TYPE_MPEG2_PICTURE: - elem_size = sizeof(struct v4l2_ctrl_mpeg2_picture); - break; - case V4L2_CTRL_TYPE_MPEG2_QUANTISATION: - elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantisation); - break; - case V4L2_CTRL_TYPE_FWHT_PARAMS: - elem_size = sizeof(struct v4l2_ctrl_fwht_params); - break; - case V4L2_CTRL_TYPE_H264_SPS: - elem_size = sizeof(struct v4l2_ctrl_h264_sps); - break; - case V4L2_CTRL_TYPE_H264_PPS: - elem_size = sizeof(struct v4l2_ctrl_h264_pps); - break; - case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: - elem_size = sizeof(struct v4l2_ctrl_h264_scaling_matrix); - break; - case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: - elem_size = sizeof(struct v4l2_ctrl_h264_slice_params); - break; - case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: - elem_size = sizeof(struct v4l2_ctrl_h264_decode_params); - break; - case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: - elem_size = sizeof(struct v4l2_ctrl_h264_pred_weights); - break; - case V4L2_CTRL_TYPE_VP8_FRAME: - elem_size = sizeof(struct v4l2_ctrl_vp8_frame); - break; - case V4L2_CTRL_TYPE_HEVC_SPS: - elem_size = sizeof(struct v4l2_ctrl_hevc_sps); - break; - case V4L2_CTRL_TYPE_HEVC_PPS: - elem_size = sizeof(struct v4l2_ctrl_hevc_pps); - break; - case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: - elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params); - break; - case V4L2_CTRL_TYPE_HDR10_CLL_INFO: - elem_size = sizeof(struct v4l2_ctrl_hdr10_cll_info); - break; - case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY: - elem_size = sizeof(struct v4l2_ctrl_hdr10_mastering_display); - break; - case V4L2_CTRL_TYPE_AREA: - elem_size = sizeof(struct v4l2_area); - break; - default: - if (type < V4L2_CTRL_COMPOUND_TYPES) - elem_size = sizeof(s32); - break; - } - tot_ctrl_size = elem_size * elems; - - /* Sanity checks */ - if (id == 0 || name == NULL || !elem_size || - id >= V4L2_CID_PRIVATE_BASE || - (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) || - (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL)) { - handler_set_err(hdl, -ERANGE); - return NULL; - } - err = check_range(type, min, max, step, def); - if (err) { - handler_set_err(hdl, err); - return NULL; - } - if (is_array && - (type == V4L2_CTRL_TYPE_BUTTON || - type == V4L2_CTRL_TYPE_CTRL_CLASS)) { - handler_set_err(hdl, -EINVAL); - return NULL; - } - - sz_extra = 0; - if (type == V4L2_CTRL_TYPE_BUTTON) - flags |= V4L2_CTRL_FLAG_WRITE_ONLY | - V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; - else if (type == V4L2_CTRL_TYPE_CTRL_CLASS) - flags |= V4L2_CTRL_FLAG_READ_ONLY; - else if (type == V4L2_CTRL_TYPE_INTEGER64 || - type == V4L2_CTRL_TYPE_STRING || - type >= V4L2_CTRL_COMPOUND_TYPES || - is_array) - sz_extra += 2 * tot_ctrl_size; - - if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) - sz_extra += elem_size; - - ctrl = kvzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL); - if (ctrl == NULL) { - handler_set_err(hdl, -ENOMEM); - return NULL; - } - - INIT_LIST_HEAD(&ctrl->node); - INIT_LIST_HEAD(&ctrl->ev_subs); - ctrl->handler = hdl; - ctrl->ops = ops; - ctrl->type_ops = type_ops ? type_ops : &std_type_ops; - ctrl->id = id; - ctrl->name = name; - ctrl->type = type; - ctrl->flags = flags; - ctrl->minimum = min; - ctrl->maximum = max; - ctrl->step = step; - ctrl->default_value = def; - ctrl->is_string = !is_array && type == V4L2_CTRL_TYPE_STRING; - ctrl->is_ptr = is_array || type >= V4L2_CTRL_COMPOUND_TYPES || ctrl->is_string; - ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64; - ctrl->is_array = is_array; - ctrl->elems = elems; - ctrl->nr_of_dims = nr_of_dims; - if (nr_of_dims) - memcpy(ctrl->dims, dims, nr_of_dims * sizeof(dims[0])); - ctrl->elem_size = elem_size; - if (type == V4L2_CTRL_TYPE_MENU) - ctrl->qmenu = qmenu; - else if (type == V4L2_CTRL_TYPE_INTEGER_MENU) - ctrl->qmenu_int = qmenu_int; - ctrl->priv = priv; - ctrl->cur.val = ctrl->val = def; - data = &ctrl[1]; - - if (!ctrl->is_int) { - ctrl->p_new.p = data; - ctrl->p_cur.p = data + tot_ctrl_size; - } else { - ctrl->p_new.p = &ctrl->val; - ctrl->p_cur.p = &ctrl->cur.val; - } - - if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) { - ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size; - memcpy(ctrl->p_def.p, p_def.p_const, elem_size); - } - - for (idx = 0; idx < elems; idx++) { - ctrl->type_ops->init(ctrl, idx, ctrl->p_cur); - ctrl->type_ops->init(ctrl, idx, ctrl->p_new); - } - - if (handler_new_ref(hdl, ctrl, NULL, false, false)) { - kvfree(ctrl); - return NULL; - } - mutex_lock(hdl->lock); - list_add_tail(&ctrl->node, &hdl->ctrls); - mutex_unlock(hdl->lock); - return ctrl; -} - -struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl, - const struct v4l2_ctrl_config *cfg, void *priv) -{ - bool is_menu; - struct v4l2_ctrl *ctrl; - const char *name = cfg->name; - const char * const *qmenu = cfg->qmenu; - const s64 *qmenu_int = cfg->qmenu_int; - enum v4l2_ctrl_type type = cfg->type; - u32 flags = cfg->flags; - s64 min = cfg->min; - s64 max = cfg->max; - u64 step = cfg->step; - s64 def = cfg->def; - - if (name == NULL) - v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step, - &def, &flags); - - is_menu = (type == V4L2_CTRL_TYPE_MENU || - type == V4L2_CTRL_TYPE_INTEGER_MENU); - if (is_menu) - WARN_ON(step); - else - WARN_ON(cfg->menu_skip_mask); - if (type == V4L2_CTRL_TYPE_MENU && !qmenu) { - qmenu = v4l2_ctrl_get_menu(cfg->id); - } else if (type == V4L2_CTRL_TYPE_INTEGER_MENU && !qmenu_int) { - handler_set_err(hdl, -EINVAL); - return NULL; - } - - ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->type_ops, cfg->id, name, - type, min, max, - is_menu ? cfg->menu_skip_mask : step, def, - cfg->dims, cfg->elem_size, - flags, qmenu, qmenu_int, cfg->p_def, priv); - if (ctrl) - ctrl->is_private = cfg->is_private; - return ctrl; -} -EXPORT_SYMBOL(v4l2_ctrl_new_custom); - -/* Helper function for standard non-menu controls */ -struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl, - const struct v4l2_ctrl_ops *ops, - u32 id, s64 min, s64 max, u64 step, s64 def) -{ - const char *name; - enum v4l2_ctrl_type type; - u32 flags; - - v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); - if (type == V4L2_CTRL_TYPE_MENU || - type == V4L2_CTRL_TYPE_INTEGER_MENU || - type >= V4L2_CTRL_COMPOUND_TYPES) { - handler_set_err(hdl, -EINVAL); - return NULL; - } - return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, - min, max, step, def, NULL, 0, - flags, NULL, NULL, ptr_null, NULL); -} -EXPORT_SYMBOL(v4l2_ctrl_new_std); - -/* Helper function for standard menu controls */ -struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl, - const struct v4l2_ctrl_ops *ops, - u32 id, u8 _max, u64 mask, u8 _def) -{ - const char * const *qmenu = NULL; - const s64 *qmenu_int = NULL; - unsigned int qmenu_int_len = 0; - const char *name; - enum v4l2_ctrl_type type; - s64 min; - s64 max = _max; - s64 def = _def; - u64 step; - u32 flags; - - v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); - - if (type == V4L2_CTRL_TYPE_MENU) - qmenu = v4l2_ctrl_get_menu(id); - else if (type == V4L2_CTRL_TYPE_INTEGER_MENU) - qmenu_int = v4l2_ctrl_get_int_menu(id, &qmenu_int_len); - - if ((!qmenu && !qmenu_int) || (qmenu_int && max > qmenu_int_len)) { - handler_set_err(hdl, -EINVAL); - return NULL; - } - return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, - 0, max, mask, def, NULL, 0, - flags, qmenu, qmenu_int, ptr_null, NULL); -} -EXPORT_SYMBOL(v4l2_ctrl_new_std_menu); - -/* Helper function for standard menu controls with driver defined menu */ -struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl, - const struct v4l2_ctrl_ops *ops, u32 id, u8 _max, - u64 mask, u8 _def, const char * const *qmenu) -{ - enum v4l2_ctrl_type type; - const char *name; - u32 flags; - u64 step; - s64 min; - s64 max = _max; - s64 def = _def; - - /* v4l2_ctrl_new_std_menu_items() should only be called for - * standard controls without a standard menu. - */ - if (v4l2_ctrl_get_menu(id)) { - handler_set_err(hdl, -EINVAL); - return NULL; - } - - v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); - if (type != V4L2_CTRL_TYPE_MENU || qmenu == NULL) { - handler_set_err(hdl, -EINVAL); - return NULL; - } - return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, - 0, max, mask, def, NULL, 0, - flags, qmenu, NULL, ptr_null, NULL); - -} -EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items); - -/* Helper function for standard compound controls */ -struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl, - const struct v4l2_ctrl_ops *ops, u32 id, - const union v4l2_ctrl_ptr p_def) -{ - const char *name; - enum v4l2_ctrl_type type; - u32 flags; - s64 min, max, step, def; - - v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); - if (type < V4L2_CTRL_COMPOUND_TYPES) { - handler_set_err(hdl, -EINVAL); - return NULL; - } - return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, - min, max, step, def, NULL, 0, - flags, NULL, NULL, p_def, NULL); -} -EXPORT_SYMBOL(v4l2_ctrl_new_std_compound); - -/* Helper function for standard integer menu controls */ -struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl, - const struct v4l2_ctrl_ops *ops, - u32 id, u8 _max, u8 _def, const s64 *qmenu_int) -{ - const char *name; - enum v4l2_ctrl_type type; - s64 min; - u64 step; - s64 max = _max; - s64 def = _def; - u32 flags; - - v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); - if (type != V4L2_CTRL_TYPE_INTEGER_MENU) { - handler_set_err(hdl, -EINVAL); - return NULL; - } - return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, - 0, max, 0, def, NULL, 0, - flags, NULL, qmenu_int, ptr_null, NULL); -} -EXPORT_SYMBOL(v4l2_ctrl_new_int_menu); - -/* Add the controls from another handler to our own. */ -int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl, - struct v4l2_ctrl_handler *add, - bool (*filter)(const struct v4l2_ctrl *ctrl), - bool from_other_dev) -{ - struct v4l2_ctrl_ref *ref; - int ret = 0; - - /* Do nothing if either handler is NULL or if they are the same */ - if (!hdl || !add || hdl == add) - return 0; - if (hdl->error) - return hdl->error; - mutex_lock(add->lock); - list_for_each_entry(ref, &add->ctrl_refs, node) { - struct v4l2_ctrl *ctrl = ref->ctrl; - - /* Skip handler-private controls. */ - if (ctrl->is_private) - continue; - /* And control classes */ - if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS) - continue; - /* Filter any unwanted controls */ - if (filter && !filter(ctrl)) - continue; - ret = handler_new_ref(hdl, ctrl, NULL, from_other_dev, false); - if (ret) - break; - } - mutex_unlock(add->lock); - return ret; -} -EXPORT_SYMBOL(v4l2_ctrl_add_handler); - -bool v4l2_ctrl_radio_filter(const struct v4l2_ctrl *ctrl) -{ - if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_TX) - return true; - if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_RX) - return true; - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - case V4L2_CID_AUDIO_LOUDNESS: - return true; - default: - break; - } - return false; -} -EXPORT_SYMBOL(v4l2_ctrl_radio_filter); - -/* Cluster controls */ -void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls) -{ - bool has_volatiles = false; - int i; - - /* The first control is the master control and it must not be NULL */ - if (WARN_ON(ncontrols == 0 || controls[0] == NULL)) - return; - - for (i = 0; i < ncontrols; i++) { - if (controls[i]) { - controls[i]->cluster = controls; - controls[i]->ncontrols = ncontrols; - if (controls[i]->flags & V4L2_CTRL_FLAG_VOLATILE) - has_volatiles = true; - } - } - controls[0]->has_volatiles = has_volatiles; -} -EXPORT_SYMBOL(v4l2_ctrl_cluster); - -void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls, - u8 manual_val, bool set_volatile) -{ - struct v4l2_ctrl *master = controls[0]; - u32 flag = 0; - int i; - - v4l2_ctrl_cluster(ncontrols, controls); - WARN_ON(ncontrols <= 1); - WARN_ON(manual_val < master->minimum || manual_val > master->maximum); - WARN_ON(set_volatile && !has_op(master, g_volatile_ctrl)); - master->is_auto = true; - master->has_volatiles = set_volatile; - master->manual_mode_value = manual_val; - master->flags |= V4L2_CTRL_FLAG_UPDATE; - - if (!is_cur_manual(master)) - flag = V4L2_CTRL_FLAG_INACTIVE | - (set_volatile ? V4L2_CTRL_FLAG_VOLATILE : 0); - - for (i = 1; i < ncontrols; i++) - if (controls[i]) - controls[i]->flags |= flag; -} -EXPORT_SYMBOL(v4l2_ctrl_auto_cluster); - -/* Activate/deactivate a control. */ -void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active) -{ - /* invert since the actual flag is called 'inactive' */ - bool inactive = !active; - bool old; - - if (ctrl == NULL) - return; - - if (inactive) - /* set V4L2_CTRL_FLAG_INACTIVE */ - old = test_and_set_bit(4, &ctrl->flags); - else - /* clear V4L2_CTRL_FLAG_INACTIVE */ - old = test_and_clear_bit(4, &ctrl->flags); - if (old != inactive) - send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS); -} -EXPORT_SYMBOL(v4l2_ctrl_activate); - -void __v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed) -{ - bool old; - - if (ctrl == NULL) - return; - - lockdep_assert_held(ctrl->handler->lock); - - if (grabbed) - /* set V4L2_CTRL_FLAG_GRABBED */ - old = test_and_set_bit(1, &ctrl->flags); - else - /* clear V4L2_CTRL_FLAG_GRABBED */ - old = test_and_clear_bit(1, &ctrl->flags); - if (old != grabbed) - send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS); -} -EXPORT_SYMBOL(__v4l2_ctrl_grab); - -/* Log the control name and value */ -static void log_ctrl(const struct v4l2_ctrl *ctrl, - const char *prefix, const char *colon) -{ - if (ctrl->flags & (V4L2_CTRL_FLAG_DISABLED | V4L2_CTRL_FLAG_WRITE_ONLY)) - return; - if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS) - return; - - pr_info("%s%s%s: ", prefix, colon, ctrl->name); - - ctrl->type_ops->log(ctrl); - - if (ctrl->flags & (V4L2_CTRL_FLAG_INACTIVE | - V4L2_CTRL_FLAG_GRABBED | - V4L2_CTRL_FLAG_VOLATILE)) { - if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) - pr_cont(" inactive"); - if (ctrl->flags & V4L2_CTRL_FLAG_GRABBED) - pr_cont(" grabbed"); - if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) - pr_cont(" volatile"); - } - pr_cont("\n"); -} - -/* Log all controls owned by the handler */ -void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl, - const char *prefix) -{ - struct v4l2_ctrl *ctrl; - const char *colon = ""; - int len; - - if (hdl == NULL) - return; - if (prefix == NULL) - prefix = ""; - len = strlen(prefix); - if (len && prefix[len - 1] != ' ') - colon = ": "; - mutex_lock(hdl->lock); - list_for_each_entry(ctrl, &hdl->ctrls, node) - if (!(ctrl->flags & V4L2_CTRL_FLAG_DISABLED)) - log_ctrl(ctrl, prefix, colon); - mutex_unlock(hdl->lock); -} -EXPORT_SYMBOL(v4l2_ctrl_handler_log_status); - -int v4l2_ctrl_subdev_log_status(struct v4l2_subdev *sd) -{ - v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name); - return 0; -} -EXPORT_SYMBOL(v4l2_ctrl_subdev_log_status); - -/* Call s_ctrl for all controls owned by the handler */ -int __v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl) -{ - struct v4l2_ctrl *ctrl; - int ret = 0; - - if (hdl == NULL) - return 0; - - lockdep_assert_held(hdl->lock); - - list_for_each_entry(ctrl, &hdl->ctrls, node) - ctrl->done = false; - - list_for_each_entry(ctrl, &hdl->ctrls, node) { - struct v4l2_ctrl *master = ctrl->cluster[0]; - int i; - - /* Skip if this control was already handled by a cluster. */ - /* Skip button controls and read-only controls. */ - if (ctrl->done || ctrl->type == V4L2_CTRL_TYPE_BUTTON || - (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)) - continue; - - for (i = 0; i < master->ncontrols; i++) { - if (master->cluster[i]) { - cur_to_new(master->cluster[i]); - master->cluster[i]->is_new = 1; - master->cluster[i]->done = true; - } - } - ret = call_op(master, s_ctrl); - if (ret) - break; - } - - return ret; -} -EXPORT_SYMBOL_GPL(__v4l2_ctrl_handler_setup); - -int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl) -{ - int ret; - - if (hdl == NULL) - return 0; - - mutex_lock(hdl->lock); - ret = __v4l2_ctrl_handler_setup(hdl); - mutex_unlock(hdl->lock); - - return ret; -} -EXPORT_SYMBOL(v4l2_ctrl_handler_setup); - -/* Implement VIDIOC_QUERY_EXT_CTRL */ -int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctrl *qc) -{ - const unsigned next_flags = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND; - u32 id = qc->id & V4L2_CTRL_ID_MASK; - struct v4l2_ctrl_ref *ref; - struct v4l2_ctrl *ctrl; - - if (hdl == NULL) - return -EINVAL; - - mutex_lock(hdl->lock); - - /* Try to find it */ - ref = find_ref(hdl, id); - - if ((qc->id & next_flags) && !list_empty(&hdl->ctrl_refs)) { - bool is_compound; - /* Match any control that is not hidden */ - unsigned mask = 1; - bool match = false; - - if ((qc->id & next_flags) == V4L2_CTRL_FLAG_NEXT_COMPOUND) { - /* Match any hidden control */ - match = true; - } else if ((qc->id & next_flags) == next_flags) { - /* Match any control, compound or not */ - mask = 0; - } - - /* Find the next control with ID > qc->id */ - - /* Did we reach the end of the control list? */ - if (id >= node2id(hdl->ctrl_refs.prev)) { - ref = NULL; /* Yes, so there is no next control */ - } else if (ref) { - /* We found a control with the given ID, so just get - the next valid one in the list. */ - list_for_each_entry_continue(ref, &hdl->ctrl_refs, node) { - is_compound = ref->ctrl->is_array || - ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES; - if (id < ref->ctrl->id && - (is_compound & mask) == match) - break; - } - if (&ref->node == &hdl->ctrl_refs) - ref = NULL; - } else { - /* No control with the given ID exists, so start - searching for the next largest ID. We know there - is one, otherwise the first 'if' above would have - been true. */ - list_for_each_entry(ref, &hdl->ctrl_refs, node) { - is_compound = ref->ctrl->is_array || - ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES; - if (id < ref->ctrl->id && - (is_compound & mask) == match) - break; - } - if (&ref->node == &hdl->ctrl_refs) - ref = NULL; - } - } - mutex_unlock(hdl->lock); - - if (!ref) - return -EINVAL; - - ctrl = ref->ctrl; - memset(qc, 0, sizeof(*qc)); - if (id >= V4L2_CID_PRIVATE_BASE) - qc->id = id; - else - qc->id = ctrl->id; - strscpy(qc->name, ctrl->name, sizeof(qc->name)); - qc->flags = user_flags(ctrl); - qc->type = ctrl->type; - qc->elem_size = ctrl->elem_size; - qc->elems = ctrl->elems; - qc->nr_of_dims = ctrl->nr_of_dims; - memcpy(qc->dims, ctrl->dims, qc->nr_of_dims * sizeof(qc->dims[0])); - qc->minimum = ctrl->minimum; - qc->maximum = ctrl->maximum; - qc->default_value = ctrl->default_value; - if (ctrl->type == V4L2_CTRL_TYPE_MENU - || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU) - qc->step = 1; - else - qc->step = ctrl->step; - return 0; -} -EXPORT_SYMBOL(v4l2_query_ext_ctrl); - -/* Implement VIDIOC_QUERYCTRL */ -int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc) -{ - struct v4l2_query_ext_ctrl qec = { qc->id }; - int rc; - - rc = v4l2_query_ext_ctrl(hdl, &qec); - if (rc) - return rc; - - qc->id = qec.id; - qc->type = qec.type; - qc->flags = qec.flags; - strscpy(qc->name, qec.name, sizeof(qc->name)); - switch (qc->type) { - case V4L2_CTRL_TYPE_INTEGER: - case V4L2_CTRL_TYPE_BOOLEAN: - case V4L2_CTRL_TYPE_MENU: - case V4L2_CTRL_TYPE_INTEGER_MENU: - case V4L2_CTRL_TYPE_STRING: - case V4L2_CTRL_TYPE_BITMASK: - qc->minimum = qec.minimum; - qc->maximum = qec.maximum; - qc->step = qec.step; - qc->default_value = qec.default_value; - break; - default: - qc->minimum = 0; - qc->maximum = 0; - qc->step = 0; - qc->default_value = 0; - break; - } - return 0; -} -EXPORT_SYMBOL(v4l2_queryctrl); - -/* Implement VIDIOC_QUERYMENU */ -int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm) -{ - struct v4l2_ctrl *ctrl; - u32 i = qm->index; - - ctrl = v4l2_ctrl_find(hdl, qm->id); - if (!ctrl) - return -EINVAL; - - qm->reserved = 0; - /* Sanity checks */ - switch (ctrl->type) { - case V4L2_CTRL_TYPE_MENU: - if (ctrl->qmenu == NULL) - return -EINVAL; - break; - case V4L2_CTRL_TYPE_INTEGER_MENU: - if (ctrl->qmenu_int == NULL) - return -EINVAL; - break; - default: - return -EINVAL; - } - - if (i < ctrl->minimum || i > ctrl->maximum) - return -EINVAL; - - /* Use mask to see if this menu item should be skipped */ - if (ctrl->menu_skip_mask & (1ULL << i)) - return -EINVAL; - /* Empty menu items should also be skipped */ - if (ctrl->type == V4L2_CTRL_TYPE_MENU) { - if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0') - return -EINVAL; - strscpy(qm->name, ctrl->qmenu[i], sizeof(qm->name)); - } else { - qm->value = ctrl->qmenu_int[i]; - } - return 0; -} -EXPORT_SYMBOL(v4l2_querymenu); - -static int v4l2_ctrl_request_clone(struct v4l2_ctrl_handler *hdl, - const struct v4l2_ctrl_handler *from) -{ - struct v4l2_ctrl_ref *ref; - int err = 0; - - if (WARN_ON(!hdl || hdl == from)) - return -EINVAL; - - if (hdl->error) - return hdl->error; - - WARN_ON(hdl->lock != &hdl->_lock); - - mutex_lock(from->lock); - list_for_each_entry(ref, &from->ctrl_refs, node) { - struct v4l2_ctrl *ctrl = ref->ctrl; - struct v4l2_ctrl_ref *new_ref; - - /* Skip refs inherited from other devices */ - if (ref->from_other_dev) - continue; - err = handler_new_ref(hdl, ctrl, &new_ref, false, true); - if (err) - break; - } - mutex_unlock(from->lock); - return err; -} - -static void v4l2_ctrl_request_queue(struct media_request_object *obj) -{ - struct v4l2_ctrl_handler *hdl = - container_of(obj, struct v4l2_ctrl_handler, req_obj); - struct v4l2_ctrl_handler *main_hdl = obj->priv; - - mutex_lock(main_hdl->lock); - list_add_tail(&hdl->requests_queued, &main_hdl->requests_queued); - hdl->request_is_queued = true; - mutex_unlock(main_hdl->lock); -} - -static void v4l2_ctrl_request_unbind(struct media_request_object *obj) -{ - struct v4l2_ctrl_handler *hdl = - container_of(obj, struct v4l2_ctrl_handler, req_obj); - struct v4l2_ctrl_handler *main_hdl = obj->priv; - - mutex_lock(main_hdl->lock); - list_del_init(&hdl->requests); - if (hdl->request_is_queued) { - list_del_init(&hdl->requests_queued); - hdl->request_is_queued = false; - } - mutex_unlock(main_hdl->lock); -} - -static void v4l2_ctrl_request_release(struct media_request_object *obj) -{ - struct v4l2_ctrl_handler *hdl = - container_of(obj, struct v4l2_ctrl_handler, req_obj); - - v4l2_ctrl_handler_free(hdl); - kfree(hdl); -} - -static const struct media_request_object_ops req_ops = { - .queue = v4l2_ctrl_request_queue, - .unbind = v4l2_ctrl_request_unbind, - .release = v4l2_ctrl_request_release, -}; - -struct v4l2_ctrl_handler *v4l2_ctrl_request_hdl_find(struct media_request *req, - struct v4l2_ctrl_handler *parent) -{ - struct media_request_object *obj; - - if (WARN_ON(req->state != MEDIA_REQUEST_STATE_VALIDATING && - req->state != MEDIA_REQUEST_STATE_QUEUED)) - return NULL; - - obj = media_request_object_find(req, &req_ops, parent); - if (obj) - return container_of(obj, struct v4l2_ctrl_handler, req_obj); - return NULL; -} -EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_find); - -struct v4l2_ctrl * -v4l2_ctrl_request_hdl_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id) -{ - struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id); - - return (ref && ref->valid_p_req) ? ref->ctrl : NULL; -} -EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_ctrl_find); - -static int v4l2_ctrl_request_bind(struct media_request *req, - struct v4l2_ctrl_handler *hdl, - struct v4l2_ctrl_handler *from) -{ - int ret; - - ret = v4l2_ctrl_request_clone(hdl, from); - - if (!ret) { - ret = media_request_object_bind(req, &req_ops, - from, false, &hdl->req_obj); - if (!ret) { - mutex_lock(from->lock); - list_add_tail(&hdl->requests, &from->requests); - mutex_unlock(from->lock); - } - } - return ret; -} - -/* Some general notes on the atomic requirements of VIDIOC_G/TRY/S_EXT_CTRLS: - - It is not a fully atomic operation, just best-effort only. After all, if - multiple controls have to be set through multiple i2c writes (for example) - then some initial writes may succeed while others fail. Thus leaving the - system in an inconsistent state. The question is how much effort you are - willing to spend on trying to make something atomic that really isn't. - - From the point of view of an application the main requirement is that - when you call VIDIOC_S_EXT_CTRLS and some values are invalid then an - error should be returned without actually affecting any controls. - - If all the values are correct, then it is acceptable to just give up - in case of low-level errors. - - It is important though that the application can tell when only a partial - configuration was done. The way we do that is through the error_idx field - of struct v4l2_ext_controls: if that is equal to the count field then no - controls were affected. Otherwise all controls before that index were - successful in performing their 'get' or 'set' operation, the control at - the given index failed, and you don't know what happened with the controls - after the failed one. Since if they were part of a control cluster they - could have been successfully processed (if a cluster member was encountered - at index < error_idx), they could have failed (if a cluster member was at - error_idx), or they may not have been processed yet (if the first cluster - member appeared after error_idx). - - It is all fairly theoretical, though. In practice all you can do is to - bail out. If error_idx == count, then it is an application bug. If - error_idx < count then it is only an application bug if the error code was - EBUSY. That usually means that something started streaming just when you - tried to set the controls. In all other cases it is a driver/hardware - problem and all you can do is to retry or bail out. - - Note that these rules do not apply to VIDIOC_TRY_EXT_CTRLS: since that - never modifies controls the error_idx is just set to whatever control - has an invalid value. - */ - -/* Prepare for the extended g/s/try functions. - Find the controls in the control array and do some basic checks. */ -static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl, - struct v4l2_ext_controls *cs, - struct v4l2_ctrl_helper *helpers, - struct video_device *vdev, - bool get) -{ - struct v4l2_ctrl_helper *h; - bool have_clusters = false; - u32 i; - - for (i = 0, h = helpers; i < cs->count; i++, h++) { - struct v4l2_ext_control *c = &cs->controls[i]; - struct v4l2_ctrl_ref *ref; - struct v4l2_ctrl *ctrl; - u32 id = c->id & V4L2_CTRL_ID_MASK; - - cs->error_idx = i; - - if (cs->which && - cs->which != V4L2_CTRL_WHICH_DEF_VAL && - cs->which != V4L2_CTRL_WHICH_REQUEST_VAL && - V4L2_CTRL_ID2WHICH(id) != cs->which) { - dprintk(vdev, - "invalid which 0x%x or control id 0x%x\n", - cs->which, id); - return -EINVAL; - } - - /* Old-style private controls are not allowed for - extended controls */ - if (id >= V4L2_CID_PRIVATE_BASE) { - dprintk(vdev, - "old-style private controls not allowed\n"); - return -EINVAL; - } - ref = find_ref_lock(hdl, id); - if (ref == NULL) { - dprintk(vdev, "cannot find control id 0x%x\n", id); - return -EINVAL; - } - h->ref = ref; - ctrl = ref->ctrl; - if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED) { - dprintk(vdev, "control id 0x%x is disabled\n", id); - return -EINVAL; - } - - if (ctrl->cluster[0]->ncontrols > 1) - have_clusters = true; - if (ctrl->cluster[0] != ctrl) - ref = find_ref_lock(hdl, ctrl->cluster[0]->id); - if (ctrl->is_ptr && !ctrl->is_string) { - unsigned tot_size = ctrl->elems * ctrl->elem_size; - - if (c->size < tot_size) { - /* - * In the get case the application first - * queries to obtain the size of the control. - */ - if (get) { - c->size = tot_size; - return -ENOSPC; - } - dprintk(vdev, - "pointer control id 0x%x size too small, %d bytes but %d bytes needed\n", - id, c->size, tot_size); - return -EFAULT; - } - c->size = tot_size; - } - /* Store the ref to the master control of the cluster */ - h->mref = ref; - /* Initially set next to 0, meaning that there is no other - control in this helper array belonging to the same - cluster */ - h->next = 0; - } - - /* We are done if there were no controls that belong to a multi- - control cluster. */ - if (!have_clusters) - return 0; - - /* The code below figures out in O(n) time which controls in the list - belong to the same cluster. */ - - /* This has to be done with the handler lock taken. */ - mutex_lock(hdl->lock); - - /* First zero the helper field in the master control references */ - for (i = 0; i < cs->count; i++) - helpers[i].mref->helper = NULL; - for (i = 0, h = helpers; i < cs->count; i++, h++) { - struct v4l2_ctrl_ref *mref = h->mref; - - /* If the mref->helper is set, then it points to an earlier - helper that belongs to the same cluster. */ - if (mref->helper) { - /* Set the next field of mref->helper to the current - index: this means that that earlier helper now - points to the next helper in the same cluster. */ - mref->helper->next = i; - /* mref should be set only for the first helper in the - cluster, clear the others. */ - h->mref = NULL; - } - /* Point the mref helper to the current helper struct. */ - mref->helper = h; - } - mutex_unlock(hdl->lock); - return 0; -} - -/* Handles the corner case where cs->count == 0. It checks whether the - specified control class exists. If that class ID is 0, then it checks - whether there are any controls at all. */ -static int class_check(struct v4l2_ctrl_handler *hdl, u32 which) -{ - if (which == 0 || which == V4L2_CTRL_WHICH_DEF_VAL || - which == V4L2_CTRL_WHICH_REQUEST_VAL) - return 0; - return find_ref_lock(hdl, which | 1) ? 0 : -EINVAL; -} - -/* - * Get extended controls. Allocates the helpers array if needed. - * - * Note that v4l2_g_ext_ctrls_common() with 'which' set to - * V4L2_CTRL_WHICH_REQUEST_VAL is only called if the request was - * completed, and in that case valid_p_req is true for all controls. - */ -static int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl, - struct v4l2_ext_controls *cs, - struct video_device *vdev) -{ - struct v4l2_ctrl_helper helper[4]; - struct v4l2_ctrl_helper *helpers = helper; - int ret; - int i, j; - bool is_default, is_request; - - is_default = (cs->which == V4L2_CTRL_WHICH_DEF_VAL); - is_request = (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL); - - cs->error_idx = cs->count; - cs->which = V4L2_CTRL_ID2WHICH(cs->which); - - if (hdl == NULL) - return -EINVAL; - - if (cs->count == 0) - return class_check(hdl, cs->which); - - if (cs->count > ARRAY_SIZE(helper)) { - helpers = kvmalloc_array(cs->count, sizeof(helper[0]), - GFP_KERNEL); - if (helpers == NULL) - return -ENOMEM; - } - - ret = prepare_ext_ctrls(hdl, cs, helpers, vdev, true); - cs->error_idx = cs->count; - - for (i = 0; !ret && i < cs->count; i++) - if (helpers[i].ref->ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY) - ret = -EACCES; - - for (i = 0; !ret && i < cs->count; i++) { - struct v4l2_ctrl *master; - bool is_volatile = false; - u32 idx = i; - - if (helpers[i].mref == NULL) - continue; - - master = helpers[i].mref->ctrl; - cs->error_idx = i; - - v4l2_ctrl_lock(master); - - /* - * g_volatile_ctrl will update the new control values. - * This makes no sense for V4L2_CTRL_WHICH_DEF_VAL and - * V4L2_CTRL_WHICH_REQUEST_VAL. In the case of requests - * it is v4l2_ctrl_request_complete() that copies the - * volatile controls at the time of request completion - * to the request, so you don't want to do that again. - */ - if (!is_default && !is_request && - ((master->flags & V4L2_CTRL_FLAG_VOLATILE) || - (master->has_volatiles && !is_cur_manual(master)))) { - for (j = 0; j < master->ncontrols; j++) - cur_to_new(master->cluster[j]); - ret = call_op(master, g_volatile_ctrl); - is_volatile = true; - } - - if (ret) { - v4l2_ctrl_unlock(master); - break; - } - - /* - * Copy the default value (if is_default is true), the - * request value (if is_request is true and p_req is valid), - * the new volatile value (if is_volatile is true) or the - * current value. - */ - do { - struct v4l2_ctrl_ref *ref = helpers[idx].ref; - - if (is_default) - ret = def_to_user(cs->controls + idx, ref->ctrl); - else if (is_request && ref->valid_p_req) - ret = req_to_user(cs->controls + idx, ref); - else if (is_volatile) - ret = new_to_user(cs->controls + idx, ref->ctrl); - else - ret = cur_to_user(cs->controls + idx, ref->ctrl); - idx = helpers[idx].next; - } while (!ret && idx); - - v4l2_ctrl_unlock(master); - } - - if (cs->count > ARRAY_SIZE(helper)) - kvfree(helpers); - return ret; -} - -static struct media_request_object * -v4l2_ctrls_find_req_obj(struct v4l2_ctrl_handler *hdl, - struct media_request *req, bool set) -{ - struct media_request_object *obj; - struct v4l2_ctrl_handler *new_hdl; - int ret; - - if (IS_ERR(req)) - return ERR_CAST(req); - - if (set && WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING)) - return ERR_PTR(-EBUSY); - - obj = media_request_object_find(req, &req_ops, hdl); - if (obj) - return obj; - /* - * If there are no controls in this completed request, - * then that can only happen if: - * - * 1) no controls were present in the queued request, and - * 2) v4l2_ctrl_request_complete() could not allocate a - * control handler object to store the completed state in. - * - * So return ENOMEM to indicate that there was an out-of-memory - * error. - */ - if (!set) - return ERR_PTR(-ENOMEM); - - new_hdl = kzalloc(sizeof(*new_hdl), GFP_KERNEL); - if (!new_hdl) - return ERR_PTR(-ENOMEM); - - obj = &new_hdl->req_obj; - ret = v4l2_ctrl_handler_init(new_hdl, (hdl->nr_of_buckets - 1) * 8); - if (!ret) - ret = v4l2_ctrl_request_bind(req, new_hdl, hdl); - if (ret) { - v4l2_ctrl_handler_free(new_hdl); - kfree(new_hdl); - return ERR_PTR(ret); - } - - media_request_object_get(obj); - return obj; -} - -int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct video_device *vdev, - struct media_device *mdev, struct v4l2_ext_controls *cs) -{ - struct media_request_object *obj = NULL; - struct media_request *req = NULL; - int ret; - - if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL) { - if (!mdev || cs->request_fd < 0) - return -EINVAL; - - req = media_request_get_by_fd(mdev, cs->request_fd); - if (IS_ERR(req)) - return PTR_ERR(req); - - if (req->state != MEDIA_REQUEST_STATE_COMPLETE) { - media_request_put(req); - return -EACCES; - } - - ret = media_request_lock_for_access(req); - if (ret) { - media_request_put(req); - return ret; - } - - obj = v4l2_ctrls_find_req_obj(hdl, req, false); - if (IS_ERR(obj)) { - media_request_unlock_for_access(req); - media_request_put(req); - return PTR_ERR(obj); - } - - hdl = container_of(obj, struct v4l2_ctrl_handler, - req_obj); - } - - ret = v4l2_g_ext_ctrls_common(hdl, cs, vdev); - - if (obj) { - media_request_unlock_for_access(req); - media_request_object_put(obj); - media_request_put(req); - } - return ret; -} -EXPORT_SYMBOL(v4l2_g_ext_ctrls); - -/* Helper function to get a single control */ -static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c) -{ - struct v4l2_ctrl *master = ctrl->cluster[0]; - int ret = 0; - int i; - - /* Compound controls are not supported. The new_to_user() and - * cur_to_user() calls below would need to be modified not to access - * userspace memory when called from get_ctrl(). - */ - if (!ctrl->is_int && ctrl->type != V4L2_CTRL_TYPE_INTEGER64) - return -EINVAL; - - if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY) - return -EACCES; - - v4l2_ctrl_lock(master); - /* g_volatile_ctrl will update the current control values */ - if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) { - for (i = 0; i < master->ncontrols; i++) - cur_to_new(master->cluster[i]); - ret = call_op(master, g_volatile_ctrl); - new_to_user(c, ctrl); - } else { - cur_to_user(c, ctrl); - } - v4l2_ctrl_unlock(master); - return ret; -} - -int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control) -{ - struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id); - struct v4l2_ext_control c; - int ret; - - if (ctrl == NULL || !ctrl->is_int) - return -EINVAL; - ret = get_ctrl(ctrl, &c); - control->value = c.value; - return ret; -} -EXPORT_SYMBOL(v4l2_g_ctrl); - -s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_ext_control c; - - /* It's a driver bug if this happens. */ - if (WARN_ON(!ctrl->is_int)) - return 0; - c.value = 0; - get_ctrl(ctrl, &c); - return c.value; -} -EXPORT_SYMBOL(v4l2_ctrl_g_ctrl); - -s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl) -{ - struct v4l2_ext_control c; - - /* It's a driver bug if this happens. */ - if (WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64)) - return 0; - c.value64 = 0; - get_ctrl(ctrl, &c); - return c.value64; -} -EXPORT_SYMBOL(v4l2_ctrl_g_ctrl_int64); - - -/* Core function that calls try/s_ctrl and ensures that the new value is - copied to the current value on a set. - Must be called with ctrl->handler->lock held. */ -static int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master, - bool set, u32 ch_flags) -{ - bool update_flag; - int ret; - int i; - - /* Go through the cluster and either validate the new value or - (if no new value was set), copy the current value to the new - value, ensuring a consistent view for the control ops when - called. */ - for (i = 0; i < master->ncontrols; i++) { - struct v4l2_ctrl *ctrl = master->cluster[i]; - - if (ctrl == NULL) - continue; - - if (!ctrl->is_new) { - cur_to_new(ctrl); - continue; - } - /* Check again: it may have changed since the - previous check in try_or_set_ext_ctrls(). */ - if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) - return -EBUSY; - } - - ret = call_op(master, try_ctrl); - - /* Don't set if there is no change */ - if (ret || !set || !cluster_changed(master)) - return ret; - ret = call_op(master, s_ctrl); - if (ret) - return ret; - - /* If OK, then make the new values permanent. */ - update_flag = is_cur_manual(master) != is_new_manual(master); - - for (i = 0; i < master->ncontrols; i++) { - /* - * If we switch from auto to manual mode, and this cluster - * contains volatile controls, then all non-master controls - * have to be marked as changed. The 'new' value contains - * the volatile value (obtained by update_from_auto_cluster), - * which now has to become the current value. - */ - if (i && update_flag && is_new_manual(master) && - master->has_volatiles && master->cluster[i]) - master->cluster[i]->has_changed = true; - - new_to_cur(fh, master->cluster[i], ch_flags | - ((update_flag && i > 0) ? V4L2_EVENT_CTRL_CH_FLAGS : 0)); - } - return 0; -} - -/* Validate controls. */ -static int validate_ctrls(struct v4l2_ext_controls *cs, - struct v4l2_ctrl_helper *helpers, - struct video_device *vdev, - bool set) -{ - unsigned i; - int ret = 0; - - cs->error_idx = cs->count; - for (i = 0; i < cs->count; i++) { - struct v4l2_ctrl *ctrl = helpers[i].ref->ctrl; - union v4l2_ctrl_ptr p_new; - - cs->error_idx = i; - - if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) { - dprintk(vdev, - "control id 0x%x is read-only\n", - ctrl->id); - return -EACCES; - } - /* This test is also done in try_set_control_cluster() which - is called in atomic context, so that has the final say, - but it makes sense to do an up-front check as well. Once - an error occurs in try_set_control_cluster() some other - controls may have been set already and we want to do a - best-effort to avoid that. */ - if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) { - dprintk(vdev, - "control id 0x%x is grabbed, cannot set\n", - ctrl->id); - return -EBUSY; - } - /* - * Skip validation for now if the payload needs to be copied - * from userspace into kernelspace. We'll validate those later. - */ - if (ctrl->is_ptr) - continue; - if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) - p_new.p_s64 = &cs->controls[i].value64; - else - p_new.p_s32 = &cs->controls[i].value; - ret = validate_new(ctrl, p_new); - if (ret) - return ret; - } - return 0; -} - -/* Obtain the current volatile values of an autocluster and mark them - as new. */ -static void update_from_auto_cluster(struct v4l2_ctrl *master) -{ - int i; - - for (i = 1; i < master->ncontrols; i++) - cur_to_new(master->cluster[i]); - if (!call_op(master, g_volatile_ctrl)) - for (i = 1; i < master->ncontrols; i++) - if (master->cluster[i]) - master->cluster[i]->is_new = 1; -} - -/* Try or try-and-set controls */ -static int try_set_ext_ctrls_common(struct v4l2_fh *fh, - struct v4l2_ctrl_handler *hdl, - struct v4l2_ext_controls *cs, - struct video_device *vdev, bool set) -{ - struct v4l2_ctrl_helper helper[4]; - struct v4l2_ctrl_helper *helpers = helper; - unsigned i, j; - int ret; - - cs->error_idx = cs->count; - - /* Default value cannot be changed */ - if (cs->which == V4L2_CTRL_WHICH_DEF_VAL) { - dprintk(vdev, "%s: cannot change default value\n", - video_device_node_name(vdev)); - return -EINVAL; - } - - cs->which = V4L2_CTRL_ID2WHICH(cs->which); - - if (hdl == NULL) { - dprintk(vdev, "%s: invalid null control handler\n", - video_device_node_name(vdev)); - return -EINVAL; - } - - if (cs->count == 0) - return class_check(hdl, cs->which); - - if (cs->count > ARRAY_SIZE(helper)) { - helpers = kvmalloc_array(cs->count, sizeof(helper[0]), - GFP_KERNEL); - if (!helpers) - return -ENOMEM; - } - ret = prepare_ext_ctrls(hdl, cs, helpers, vdev, false); - if (!ret) - ret = validate_ctrls(cs, helpers, vdev, set); - if (ret && set) - cs->error_idx = cs->count; - for (i = 0; !ret && i < cs->count; i++) { - struct v4l2_ctrl *master; - u32 idx = i; - - if (helpers[i].mref == NULL) - continue; - - cs->error_idx = i; - master = helpers[i].mref->ctrl; - v4l2_ctrl_lock(master); - - /* Reset the 'is_new' flags of the cluster */ - for (j = 0; j < master->ncontrols; j++) - if (master->cluster[j]) - master->cluster[j]->is_new = 0; - - /* For volatile autoclusters that are currently in auto mode - we need to discover if it will be set to manual mode. - If so, then we have to copy the current volatile values - first since those will become the new manual values (which - may be overwritten by explicit new values from this set - of controls). */ - if (master->is_auto && master->has_volatiles && - !is_cur_manual(master)) { - /* Pick an initial non-manual value */ - s32 new_auto_val = master->manual_mode_value + 1; - u32 tmp_idx = idx; - - do { - /* Check if the auto control is part of the - list, and remember the new value. */ - if (helpers[tmp_idx].ref->ctrl == master) - new_auto_val = cs->controls[tmp_idx].value; - tmp_idx = helpers[tmp_idx].next; - } while (tmp_idx); - /* If the new value == the manual value, then copy - the current volatile values. */ - if (new_auto_val == master->manual_mode_value) - update_from_auto_cluster(master); - } - - /* Copy the new caller-supplied control values. - user_to_new() sets 'is_new' to 1. */ - do { - struct v4l2_ctrl *ctrl = helpers[idx].ref->ctrl; - - ret = user_to_new(cs->controls + idx, ctrl); - if (!ret && ctrl->is_ptr) { - ret = validate_new(ctrl, ctrl->p_new); - if (ret) - dprintk(vdev, - "failed to validate control %s (%d)\n", - v4l2_ctrl_get_name(ctrl->id), ret); - } - idx = helpers[idx].next; - } while (!ret && idx); - - if (!ret) - ret = try_or_set_cluster(fh, master, - !hdl->req_obj.req && set, 0); - if (!ret && hdl->req_obj.req && set) { - for (j = 0; j < master->ncontrols; j++) { - struct v4l2_ctrl_ref *ref = - find_ref(hdl, master->cluster[j]->id); - - new_to_req(ref); - } - } - - /* Copy the new values back to userspace. */ - if (!ret) { - idx = i; - do { - ret = new_to_user(cs->controls + idx, - helpers[idx].ref->ctrl); - idx = helpers[idx].next; - } while (!ret && idx); - } - v4l2_ctrl_unlock(master); - } - - if (cs->count > ARRAY_SIZE(helper)) - kvfree(helpers); - return ret; -} - -static int try_set_ext_ctrls(struct v4l2_fh *fh, - struct v4l2_ctrl_handler *hdl, - struct video_device *vdev, - struct media_device *mdev, - struct v4l2_ext_controls *cs, bool set) -{ - struct media_request_object *obj = NULL; - struct media_request *req = NULL; - int ret; - - if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL) { - if (!mdev) { - dprintk(vdev, "%s: missing media device\n", - video_device_node_name(vdev)); - return -EINVAL; - } - - if (cs->request_fd < 0) { - dprintk(vdev, "%s: invalid request fd %d\n", - video_device_node_name(vdev), cs->request_fd); - return -EINVAL; - } - - req = media_request_get_by_fd(mdev, cs->request_fd); - if (IS_ERR(req)) { - dprintk(vdev, "%s: cannot find request fd %d\n", - video_device_node_name(vdev), cs->request_fd); - return PTR_ERR(req); - } - - ret = media_request_lock_for_update(req); - if (ret) { - dprintk(vdev, "%s: cannot lock request fd %d\n", - video_device_node_name(vdev), cs->request_fd); - media_request_put(req); - return ret; - } - - obj = v4l2_ctrls_find_req_obj(hdl, req, set); - if (IS_ERR(obj)) { - dprintk(vdev, - "%s: cannot find request object for request fd %d\n", - video_device_node_name(vdev), - cs->request_fd); - media_request_unlock_for_update(req); - media_request_put(req); - return PTR_ERR(obj); - } - hdl = container_of(obj, struct v4l2_ctrl_handler, - req_obj); - } - - ret = try_set_ext_ctrls_common(fh, hdl, cs, vdev, set); - if (ret) - dprintk(vdev, - "%s: try_set_ext_ctrls_common failed (%d)\n", - video_device_node_name(vdev), ret); - - if (obj) { - media_request_unlock_for_update(req); - media_request_object_put(obj); - media_request_put(req); - } - - return ret; -} - -int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, - struct video_device *vdev, - struct media_device *mdev, - struct v4l2_ext_controls *cs) -{ - return try_set_ext_ctrls(NULL, hdl, vdev, mdev, cs, false); -} -EXPORT_SYMBOL(v4l2_try_ext_ctrls); - -int v4l2_s_ext_ctrls(struct v4l2_fh *fh, - struct v4l2_ctrl_handler *hdl, - struct video_device *vdev, - struct media_device *mdev, - struct v4l2_ext_controls *cs) -{ - return try_set_ext_ctrls(fh, hdl, vdev, mdev, cs, true); -} -EXPORT_SYMBOL(v4l2_s_ext_ctrls); - -/* Helper function for VIDIOC_S_CTRL compatibility */ -static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags) -{ - struct v4l2_ctrl *master = ctrl->cluster[0]; - int ret; - int i; - - /* Reset the 'is_new' flags of the cluster */ - for (i = 0; i < master->ncontrols; i++) - if (master->cluster[i]) - master->cluster[i]->is_new = 0; - - ret = validate_new(ctrl, ctrl->p_new); - if (ret) - return ret; - - /* For autoclusters with volatiles that are switched from auto to - manual mode we have to update the current volatile values since - those will become the initial manual values after such a switch. */ - if (master->is_auto && master->has_volatiles && ctrl == master && - !is_cur_manual(master) && ctrl->val == master->manual_mode_value) - update_from_auto_cluster(master); - - ctrl->is_new = 1; - return try_or_set_cluster(fh, master, true, ch_flags); -} - -/* Helper function for VIDIOC_S_CTRL compatibility */ -static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, - struct v4l2_ext_control *c) -{ - int ret; - - v4l2_ctrl_lock(ctrl); - user_to_new(c, ctrl); - ret = set_ctrl(fh, ctrl, 0); - if (!ret) - cur_to_user(c, ctrl); - v4l2_ctrl_unlock(ctrl); - return ret; -} - -int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, - struct v4l2_control *control) -{ - struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id); - struct v4l2_ext_control c = { control->id }; - int ret; - - if (ctrl == NULL || !ctrl->is_int) - return -EINVAL; - - if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) - return -EACCES; - - c.value = control->value; - ret = set_ctrl_lock(fh, ctrl, &c); - control->value = c.value; - return ret; -} -EXPORT_SYMBOL(v4l2_s_ctrl); - -int __v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val) -{ - lockdep_assert_held(ctrl->handler->lock); - - /* It's a driver bug if this happens. */ - if (WARN_ON(!ctrl->is_int)) - return -EINVAL; - ctrl->val = val; - return set_ctrl(NULL, ctrl, 0); -} -EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl); - -int __v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val) -{ - lockdep_assert_held(ctrl->handler->lock); - - /* It's a driver bug if this happens. */ - if (WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64)) - return -EINVAL; - *ctrl->p_new.p_s64 = val; - return set_ctrl(NULL, ctrl, 0); -} -EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_int64); - -int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s) -{ - lockdep_assert_held(ctrl->handler->lock); - - /* It's a driver bug if this happens. */ - if (WARN_ON(ctrl->type != V4L2_CTRL_TYPE_STRING)) - return -EINVAL; - strscpy(ctrl->p_new.p_char, s, ctrl->maximum + 1); - return set_ctrl(NULL, ctrl, 0); -} -EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string); - -int __v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl *ctrl, - enum v4l2_ctrl_type type, const void *p) -{ - lockdep_assert_held(ctrl->handler->lock); - - /* It's a driver bug if this happens. */ - if (WARN_ON(ctrl->type != type)) - return -EINVAL; - memcpy(ctrl->p_new.p, p, ctrl->elems * ctrl->elem_size); - return set_ctrl(NULL, ctrl, 0); -} -EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_compound); - -void v4l2_ctrl_request_complete(struct media_request *req, - struct v4l2_ctrl_handler *main_hdl) -{ - struct media_request_object *obj; - struct v4l2_ctrl_handler *hdl; - struct v4l2_ctrl_ref *ref; - - if (!req || !main_hdl) - return; - - /* - * Note that it is valid if nothing was found. It means - * that this request doesn't have any controls and so just - * wants to leave the controls unchanged. - */ - obj = media_request_object_find(req, &req_ops, main_hdl); - if (!obj) { - int ret; - - /* Create a new request so the driver can return controls */ - hdl = kzalloc(sizeof(*hdl), GFP_KERNEL); - if (!hdl) - return; - - ret = v4l2_ctrl_handler_init(hdl, (main_hdl->nr_of_buckets - 1) * 8); - if (!ret) - ret = v4l2_ctrl_request_bind(req, hdl, main_hdl); - if (ret) { - v4l2_ctrl_handler_free(hdl); - kfree(hdl); - return; - } - hdl->request_is_queued = true; - obj = media_request_object_find(req, &req_ops, main_hdl); - } - hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj); - - list_for_each_entry(ref, &hdl->ctrl_refs, node) { - struct v4l2_ctrl *ctrl = ref->ctrl; - struct v4l2_ctrl *master = ctrl->cluster[0]; - unsigned int i; - - if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) { - v4l2_ctrl_lock(master); - /* g_volatile_ctrl will update the current control values */ - for (i = 0; i < master->ncontrols; i++) - cur_to_new(master->cluster[i]); - call_op(master, g_volatile_ctrl); - new_to_req(ref); - v4l2_ctrl_unlock(master); - continue; - } - if (ref->valid_p_req) - continue; - - /* Copy the current control value into the request */ - v4l2_ctrl_lock(ctrl); - cur_to_req(ref); - v4l2_ctrl_unlock(ctrl); - } - - mutex_lock(main_hdl->lock); - WARN_ON(!hdl->request_is_queued); - list_del_init(&hdl->requests_queued); - hdl->request_is_queued = false; - mutex_unlock(main_hdl->lock); - media_request_object_complete(obj); - media_request_object_put(obj); -} -EXPORT_SYMBOL(v4l2_ctrl_request_complete); - -int v4l2_ctrl_request_setup(struct media_request *req, - struct v4l2_ctrl_handler *main_hdl) -{ - struct media_request_object *obj; - struct v4l2_ctrl_handler *hdl; - struct v4l2_ctrl_ref *ref; - int ret = 0; - - if (!req || !main_hdl) - return 0; - - if (WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED)) - return -EBUSY; - - /* - * Note that it is valid if nothing was found. It means - * that this request doesn't have any controls and so just - * wants to leave the controls unchanged. - */ - obj = media_request_object_find(req, &req_ops, main_hdl); - if (!obj) - return 0; - if (obj->completed) { - media_request_object_put(obj); - return -EBUSY; - } - hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj); - - list_for_each_entry(ref, &hdl->ctrl_refs, node) - ref->req_done = false; - - list_for_each_entry(ref, &hdl->ctrl_refs, node) { - struct v4l2_ctrl *ctrl = ref->ctrl; - struct v4l2_ctrl *master = ctrl->cluster[0]; - bool have_new_data = false; - int i; - - /* - * Skip if this control was already handled by a cluster. - * Skip button controls and read-only controls. - */ - if (ref->req_done || (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)) - continue; - - v4l2_ctrl_lock(master); - for (i = 0; i < master->ncontrols; i++) { - if (master->cluster[i]) { - struct v4l2_ctrl_ref *r = - find_ref(hdl, master->cluster[i]->id); - - if (r->valid_p_req) { - have_new_data = true; - break; - } - } - } - if (!have_new_data) { - v4l2_ctrl_unlock(master); - continue; - } - - for (i = 0; i < master->ncontrols; i++) { - if (master->cluster[i]) { - struct v4l2_ctrl_ref *r = - find_ref(hdl, master->cluster[i]->id); - - req_to_new(r); - master->cluster[i]->is_new = 1; - r->req_done = true; - } - } - /* - * For volatile autoclusters that are currently in auto mode - * we need to discover if it will be set to manual mode. - * If so, then we have to copy the current volatile values - * first since those will become the new manual values (which - * may be overwritten by explicit new values from this set - * of controls). - */ - if (master->is_auto && master->has_volatiles && - !is_cur_manual(master)) { - s32 new_auto_val = *master->p_new.p_s32; - - /* - * If the new value == the manual value, then copy - * the current volatile values. - */ - if (new_auto_val == master->manual_mode_value) - update_from_auto_cluster(master); - } - - ret = try_or_set_cluster(NULL, master, true, 0); - v4l2_ctrl_unlock(master); - - if (ret) - break; - } - - media_request_object_put(obj); - return ret; -} -EXPORT_SYMBOL(v4l2_ctrl_request_setup); - -void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv) -{ - if (ctrl == NULL) - return; - if (notify == NULL) { - ctrl->call_notify = 0; - return; - } - if (WARN_ON(ctrl->handler->notify && ctrl->handler->notify != notify)) - return; - ctrl->handler->notify = notify; - ctrl->handler->notify_priv = priv; - ctrl->call_notify = 1; -} -EXPORT_SYMBOL(v4l2_ctrl_notify); - -int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, - s64 min, s64 max, u64 step, s64 def) -{ - bool value_changed; - bool range_changed = false; - int ret; - - lockdep_assert_held(ctrl->handler->lock); - - switch (ctrl->type) { - case V4L2_CTRL_TYPE_INTEGER: - case V4L2_CTRL_TYPE_INTEGER64: - case V4L2_CTRL_TYPE_BOOLEAN: - case V4L2_CTRL_TYPE_MENU: - case V4L2_CTRL_TYPE_INTEGER_MENU: - case V4L2_CTRL_TYPE_BITMASK: - case V4L2_CTRL_TYPE_U8: - case V4L2_CTRL_TYPE_U16: - case V4L2_CTRL_TYPE_U32: - if (ctrl->is_array) - return -EINVAL; - ret = check_range(ctrl->type, min, max, step, def); - if (ret) - return ret; - break; - default: - return -EINVAL; - } - if ((ctrl->minimum != min) || (ctrl->maximum != max) || - (ctrl->step != step) || ctrl->default_value != def) { - range_changed = true; - ctrl->minimum = min; - ctrl->maximum = max; - ctrl->step = step; - ctrl->default_value = def; - } - cur_to_new(ctrl); - if (validate_new(ctrl, ctrl->p_new)) { - if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) - *ctrl->p_new.p_s64 = def; - else - *ctrl->p_new.p_s32 = def; - } - - if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) - value_changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64; - else - value_changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32; - if (value_changed) - ret = set_ctrl(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE); - else if (range_changed) - send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE); - return ret; -} -EXPORT_SYMBOL(__v4l2_ctrl_modify_range); - -static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) -{ - struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id); - - if (ctrl == NULL) - return -EINVAL; - - v4l2_ctrl_lock(ctrl); - list_add_tail(&sev->node, &ctrl->ev_subs); - if (ctrl->type != V4L2_CTRL_TYPE_CTRL_CLASS && - (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL)) { - struct v4l2_event ev; - u32 changes = V4L2_EVENT_CTRL_CH_FLAGS; - - if (!(ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)) - changes |= V4L2_EVENT_CTRL_CH_VALUE; - fill_event(&ev, ctrl, changes); - /* Mark the queue as active, allowing this initial - event to be accepted. */ - sev->elems = elems; - v4l2_event_queue_fh(sev->fh, &ev); - } - v4l2_ctrl_unlock(ctrl); - return 0; -} - -static void v4l2_ctrl_del_event(struct v4l2_subscribed_event *sev) -{ - struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id); - - if (ctrl == NULL) - return; - - v4l2_ctrl_lock(ctrl); - list_del(&sev->node); - v4l2_ctrl_unlock(ctrl); -} - -void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new) -{ - u32 old_changes = old->u.ctrl.changes; - - old->u.ctrl = new->u.ctrl; - old->u.ctrl.changes |= old_changes; -} -EXPORT_SYMBOL(v4l2_ctrl_replace); - -void v4l2_ctrl_merge(const struct v4l2_event *old, struct v4l2_event *new) -{ - new->u.ctrl.changes |= old->u.ctrl.changes; -} -EXPORT_SYMBOL(v4l2_ctrl_merge); - -const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops = { - .add = v4l2_ctrl_add_event, - .del = v4l2_ctrl_del_event, - .replace = v4l2_ctrl_replace, - .merge = v4l2_ctrl_merge, -}; -EXPORT_SYMBOL(v4l2_ctrl_sub_ev_ops); - -int v4l2_ctrl_log_status(struct file *file, void *fh) -{ - struct video_device *vfd = video_devdata(file); - struct v4l2_fh *vfh = file->private_data; - - if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev) - v4l2_ctrl_handler_log_status(vfh->ctrl_handler, - vfd->v4l2_dev->name); - return 0; -} -EXPORT_SYMBOL(v4l2_ctrl_log_status); - -int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) -{ - if (sub->type == V4L2_EVENT_CTRL) - return v4l2_event_subscribe(fh, sub, 0, &v4l2_ctrl_sub_ev_ops); - return -EINVAL; -} -EXPORT_SYMBOL(v4l2_ctrl_subscribe_event); - -int v4l2_ctrl_subdev_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - if (!sd->ctrl_handler) - return -EINVAL; - return v4l2_ctrl_subscribe_event(fh, sub); -} -EXPORT_SYMBOL(v4l2_ctrl_subdev_subscribe_event); - -__poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait) -{ - struct v4l2_fh *fh = file->private_data; - - poll_wait(file, &fh->wait, wait); - if (v4l2_event_pending(fh)) - return EPOLLPRI; - return 0; -} -EXPORT_SYMBOL(v4l2_ctrl_poll); - -int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl, - const struct v4l2_ctrl_ops *ctrl_ops, - const struct v4l2_fwnode_device_properties *p) -{ - if (p->orientation != V4L2_FWNODE_PROPERTY_UNSET) { - u32 orientation_ctrl; - - switch (p->orientation) { - case V4L2_FWNODE_ORIENTATION_FRONT: - orientation_ctrl = V4L2_CAMERA_ORIENTATION_FRONT; - break; - case V4L2_FWNODE_ORIENTATION_BACK: - orientation_ctrl = V4L2_CAMERA_ORIENTATION_BACK; - break; - case V4L2_FWNODE_ORIENTATION_EXTERNAL: - orientation_ctrl = V4L2_CAMERA_ORIENTATION_EXTERNAL; - break; - default: - return -EINVAL; - } - if (!v4l2_ctrl_new_std_menu(hdl, ctrl_ops, - V4L2_CID_CAMERA_ORIENTATION, - V4L2_CAMERA_ORIENTATION_EXTERNAL, 0, - orientation_ctrl)) - return hdl->error; - } - - if (p->rotation != V4L2_FWNODE_PROPERTY_UNSET) { - if (!v4l2_ctrl_new_std(hdl, ctrl_ops, - V4L2_CID_CAMERA_SENSOR_ROTATION, - p->rotation, p->rotation, 1, - p->rotation)) - return hdl->error; - } - - return hdl->error; -} -EXPORT_SYMBOL(v4l2_ctrl_new_fwnode_properties); -- cgit v1.3.1 From ca940790d2ddc91e976f1e9e685052a54a1c50cf Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 May 2021 17:23:50 +0100 Subject: arm64: Document requirement for access to FEAT_HCX v8.7 of the architecture introduced FEAT_HCX which adds an additional hypervisor configuration register HCRX_EL2. Even though Linux does not currently make use of this feature let's document that the EL3 trap for access to the register should be disabled so that we are able to make use of it in future. Signed-off-by: Mark Brown Acked-by: Catalin Marinas Link: https://lore.kernel.org/r/20210512162350.20349-1-broonie@kernel.org Signed-off-by: Will Deacon --- Documentation/arm64/booting.rst | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'Documentation') diff --git a/Documentation/arm64/booting.rst b/Documentation/arm64/booting.rst index 18b8cc1bf32c..a9192e7a231b 100644 --- a/Documentation/arm64/booting.rst +++ b/Documentation/arm64/booting.rst @@ -277,6 +277,12 @@ Before jumping into the kernel, the following conditions must be met: - SCR_EL3.FGTEn (bit 27) must be initialised to 0b1. + For CPUs with support for HCRX_EL2 (FEAT_HCX) present: + + - If EL3 is present and the kernel is entered at EL2: + + - SCR_EL3.HXEn (bit 38) must be initialised to 0b1. + For CPUs with Advanced SIMD and floating point support: - If EL3 is present: -- cgit v1.3.1 From 084071d5e9226add45a6031928bf10e6afc855fd Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Tue, 25 May 2021 10:41:17 -0300 Subject: KVM: rename KVM_REQ_PENDING_TIMER to KVM_REQ_UNBLOCK KVM_REQ_UNBLOCK will be used to exit a vcpu from its inner vcpu halt emulation loop. Rename KVM_REQ_PENDING_TIMER to KVM_REQ_UNBLOCK, switch PowerPC to arch specific request bit. Signed-off-by: Marcelo Tosatti Message-Id: <20210525134321.303768132@redhat.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/vcpu-requests.rst | 8 +++++--- arch/powerpc/include/asm/kvm_host.h | 1 + arch/x86/kvm/lapic.c | 2 +- arch/x86/kvm/x86.c | 2 +- include/linux/kvm_host.h | 2 +- virt/kvm/kvm_main.c | 2 ++ 6 files changed, 11 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/vcpu-requests.rst b/Documentation/virt/kvm/vcpu-requests.rst index 5feb3706a7ae..af1b37441e0a 100644 --- a/Documentation/virt/kvm/vcpu-requests.rst +++ b/Documentation/virt/kvm/vcpu-requests.rst @@ -118,10 +118,12 @@ KVM_REQ_MMU_RELOAD necessary to inform each VCPU to completely refresh the tables. This request is used for that. -KVM_REQ_PENDING_TIMER +KVM_REQ_UNBLOCK - This request may be made from a timer handler run on the host on behalf - of a VCPU. It informs the VCPU thread to inject a timer interrupt. + This request informs the vCPU to exit kvm_vcpu_block. It is used for + example from timer handlers that run on the host on behalf of a vCPU, + or in order to update the interrupt routing and ensure that assigned + devices will wake up the vCPU. KVM_REQ_UNHALT diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 1e83359f286b..7f2e90db2050 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -51,6 +51,7 @@ /* PPC-specific vcpu->requests bit members */ #define KVM_REQ_WATCHDOG KVM_ARCH_REQ(0) #define KVM_REQ_EPR_EXIT KVM_ARCH_REQ(1) +#define KVM_REQ_PENDING_TIMER KVM_ARCH_REQ(2) #include diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 5d91f2367c31..8120e8614b92 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1669,7 +1669,7 @@ static void apic_timer_expired(struct kvm_lapic *apic, bool from_timer_fn) } atomic_inc(&apic->lapic_timer.pending); - kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu); + kvm_make_request(KVM_REQ_UNBLOCK, vcpu); if (from_timer_fn) kvm_vcpu_kick(vcpu); } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 98538b1cb453..fe464b66898f 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9501,7 +9501,7 @@ static int vcpu_run(struct kvm_vcpu *vcpu) if (r <= 0) break; - kvm_clear_request(KVM_REQ_PENDING_TIMER, vcpu); + kvm_clear_request(KVM_REQ_UNBLOCK, vcpu); if (kvm_cpu_has_pending_timer(vcpu)) kvm_inject_pending_timer_irqs(vcpu); diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 5d4b96b36ec0..76102efbf079 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -147,7 +147,7 @@ static inline bool is_error_page(struct page *page) */ #define KVM_REQ_TLB_FLUSH (0 | KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) #define KVM_REQ_MMU_RELOAD (1 | KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) -#define KVM_REQ_PENDING_TIMER 2 +#define KVM_REQ_UNBLOCK 2 #define KVM_REQ_UNHALT 3 #define KVM_REQUEST_ARCH_BASE 8 diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 5f40725144f5..37a2d500a148 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2929,6 +2929,8 @@ static int kvm_vcpu_check_block(struct kvm_vcpu *vcpu) goto out; if (signal_pending(current)) goto out; + if (kvm_check_request(KVM_REQ_UNBLOCK, vcpu)) + goto out; ret = 0; out: -- cgit v1.3.1 From f7ebe6b76940f873645ff110192b08e64334a112 Mon Sep 17 00:00:00 2001 From: Akira Yokosawa Date: Wed, 26 May 2021 00:25:39 +0900 Subject: docs: Activate exCJK only in CJK chapters Activating xeCJK in English and Italian-translation documents results in sub-optimal typesetting with wide-looking apostrophes and quotation marks. The xeCJK package provides macros for enabling and disabling its effect in the middle of a document, namely \makexeCJKactive and \makexeCJKinactive. So the goal of this change is to activate xeCJK in the relevant chapters in translations. To do this: o Define custom macros in the preamble depending on the availability of the "Noto Sans CJK" font so that those macros can be used regardless of the use of xeCJK package. o Patch \sphinxtableofcontents so that xeCJK is inactivated after table of contents. o Embed those custom macros in each language's index.rst file as a ".. raw:: latex" construct. Note: A CJK chapter needs \kerneldocCJKon in front of its chapter heading, while a non-CJK chapter should have \kerneldocCJKoff below its chapter heading. This is to make sure the CJK font is available to CJK chapter's heading and ending page's footer. Tested against Sphinx versions 2.4.4 and 4.0.2. Signed-off-by: Akira Yokosawa Tested-by: Wu XiangCheng Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/lkml/2061da0a-6ab1-35f3-99c1-dbc415444f37@gmail.com Link: https://lore.kernel.org/r/83208ddc-5de9-b283-3fd6-92c635348ca0@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/conf.py | 13 +++++++++++++ Documentation/translations/index.rst | 4 ++++ Documentation/translations/it_IT/index.rst | 4 ++++ Documentation/translations/ja_JP/index.rst | 5 +++-- Documentation/translations/ko_KR/index.rst | 5 +++-- Documentation/translations/zh_CN/index.rst | 1 + 6 files changed, 28 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/conf.py b/Documentation/conf.py index 879e86dbea66..25aa00c707b0 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -371,6 +371,19 @@ if cjk_cmd.find("Noto Sans CJK SC") >= 0: % This is needed for translations \\usepackage{xeCJK} \\setCJKmainfont{Noto Sans CJK SC} + % Define custom macros to on/off CJK + \\newcommand{\\kerneldocCJKon}{\\makexeCJKactive} + \\newcommand{\\kerneldocCJKoff}{\\makexeCJKinactive} + % To customize \sphinxtableofcontents + \\usepackage{etoolbox} + % Inactivate CJK after tableofcontents + \\apptocmd{\\sphinxtableofcontents}{\\kerneldocCJKoff}{}{} + ''' +else: + latex_elements['preamble'] += ''' + % Custom macros to on/off CJK (Dummy) + \\newcommand{\\kerneldocCJKon}{} + \\newcommand{\\kerneldocCJKoff}{} ''' # Fix reference escape troubles with Sphinx 1.4.x diff --git a/Documentation/translations/index.rst b/Documentation/translations/index.rst index e446e5ed00a6..556b050884fc 100644 --- a/Documentation/translations/index.rst +++ b/Documentation/translations/index.rst @@ -18,6 +18,10 @@ Translations Disclaimer ---------- +.. raw:: latex + + \kerneldocCJKoff + Translation's purpose is to ease reading and understanding in languages other than English. Its aim is to help people who do not understand English or have doubts about its interpretation. Additionally, some people prefer to read diff --git a/Documentation/translations/it_IT/index.rst b/Documentation/translations/it_IT/index.rst index bb8fa7346939..e80a3097aa57 100644 --- a/Documentation/translations/it_IT/index.rst +++ b/Documentation/translations/it_IT/index.rst @@ -4,6 +4,10 @@ Traduzione italiana =================== +.. raw:: latex + + \kerneldocCJKoff + :manutentore: Federico Vaga .. _it_disclaimer: diff --git a/Documentation/translations/ja_JP/index.rst b/Documentation/translations/ja_JP/index.rst index 2f91b895e3c2..f94ba62d41c3 100644 --- a/Documentation/translations/ja_JP/index.rst +++ b/Documentation/translations/ja_JP/index.rst @@ -1,7 +1,8 @@ .. raw:: latex - \renewcommand\thesection* - \renewcommand\thesubsection* + \renewcommand\thesection* + \renewcommand\thesubsection* + \kerneldocCJKon Japanese translations ===================== diff --git a/Documentation/translations/ko_KR/index.rst b/Documentation/translations/ko_KR/index.rst index b9e27d20b039..6ae258118bdf 100644 --- a/Documentation/translations/ko_KR/index.rst +++ b/Documentation/translations/ko_KR/index.rst @@ -1,7 +1,8 @@ .. raw:: latex - \renewcommand\thesection* - \renewcommand\thesubsection* + \renewcommand\thesection* + \renewcommand\thesubsection* + \kerneldocCJKon 한국어 번역 =========== diff --git a/Documentation/translations/zh_CN/index.rst b/Documentation/translations/zh_CN/index.rst index a736057da41f..1f953d3439a5 100644 --- a/Documentation/translations/zh_CN/index.rst +++ b/Documentation/translations/zh_CN/index.rst @@ -4,6 +4,7 @@ \renewcommand\thesection* \renewcommand\thesubsection* + \kerneldocCJKon .. _linux_doc_zh: -- cgit v1.3.1 From b77e4c4e655b455c4aba196838d1102c0e3414a4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 25 May 2021 14:23:52 +0200 Subject: iio: ABI: sysfs-bus-iio: fix a typo Descrption -> Description This causes some errors when parsed via scripts/get_abi.pl. Signed-off-by: Mauro Carvalho Chehab Acked-by: Jonathan Cameron Link: https://lore.kernel.org/r/fa90a2deebac80da42b1ad4cf570c4ace436577d.1621944866.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/ABI/testing/sysfs-bus-iio | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 267973541e72..433fe0ab74be 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -786,7 +786,7 @@ What: /sys/.../events/in_capacitanceY_adaptive_thresh_rising_en What: /sys/.../events/in_capacitanceY_adaptive_thresh_falling_en KernelVersion: 5.13 Contact: linux-iio@vger.kernel.org -Descrption: +Description: Adaptive thresholds are similar to normal fixed thresholds but the value is expressed as an offset from a value which provides a low frequency approximation of the channel itself. @@ -798,7 +798,7 @@ What: /sys/.../in_capacitanceY_adaptive_thresh_rising_timeout What: /sys/.../in_capacitanceY_adaptive_thresh_falling_timeout KernelVersion: 5.11 Contact: linux-iio@vger.kernel.org -Descrption: +Description: When adaptive thresholds are used, the tracking signal may adjust too slowly to step changes in the raw signal. *_timeout (in seconds) specifies a time for which the -- cgit v1.3.1 From 1e03fe240512621605ec47f93dc29994026a2984 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 25 May 2021 14:23:53 +0200 Subject: iio: ABI: sysfs-bus-iio: avoid a warning when doc is built The description of those vars produce this warning: Documentation/ABI/testing/sysfs-bus-iio:799: WARNING: Inline emphasis start-string without end-string. Due to an asterisk, which is the markup for emphasis. One possible fix would be to use ``*_timeout`` to avoid it, but looking at the descriptions of other fields in this file, a common pattern is to refer to "these" when talking about the API calls that are described. So, change the text in order to preserve the meaning while avoiding the need of using an asterisk there. Reported-by: Jonathan Corbet Reported-by: Matthew Wilcox Signed-off-by: Mauro Carvalho Chehab Acked-by: Jonathan Cameron Link: https://lore.kernel.org/r/dbf0d94f85217f103d77dc8389c8db272f5702d2.1621944866.git.mchehab+huawei@kernel.org [jc fixed specifiy->specify] Signed-off-by: Jonathan Corbet --- Documentation/ABI/testing/sysfs-bus-iio | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 433fe0ab74be..6f98b6a9b785 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -801,7 +801,7 @@ Contact: linux-iio@vger.kernel.org Description: When adaptive thresholds are used, the tracking signal may adjust too slowly to step changes in the raw signal. - *_timeout (in seconds) specifies a time for which the + Thus these specify the time in seconds for which the difference between the slow tracking signal and the raw signal is allowed to remain out-of-range before a reset event occurs in which the tracking signal is made equal -- cgit v1.3.1 From 544ef682c60484151292eb04183e44a9dd6bb0de Mon Sep 17 00:00:00 2001 From: Barry Song Date: Mon, 24 May 2021 17:17:15 +1200 Subject: docs: kernel-parameters: mark numa=off is supported by a bundle of architectures risc-v and arm64 support numa=off by common arch_numa_init() in drivers/base/arch_numa.c. x86, ppc, mips, sparc support it by arch-level early_param. numa=off is widely used in linux distributions. it is better to document it. Signed-off-by: Barry Song Link: https://lore.kernel.org/r/20210524051715.13604-1-song.bao.hua@hisilicon.com Signed-off-by: Jonathan Corbet --- Documentation/admin-guide/kernel-parameters.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index cb89dbdedc46..a388fbdaa2ec 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3513,6 +3513,9 @@ nr_uarts= [SERIAL] maximum number of UARTs to be registered. + numa=off [KNL, ARM64, PPC, RISCV, SPARC, X86] Disable NUMA, Only + set up a single NUMA node spanning all memory. + numa_balancing= [KNL,ARM64,PPC,RISCV,S390,X86] Enable or disable automatic NUMA balancing. Allowed values are enable and disable -- cgit v1.3.1 From 811c3c4723cc2309654c58e8615c775d41ac53ef Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Mon, 24 May 2021 10:40:16 +0800 Subject: docs/zh_CN:add core-api refcount-vs-atomic.rst translation. Translate Documentation/core-api/refcount-vs-atomic.rst into Chinese. Signed-off-by: Yanteng Si Reviewed-by: Wu XiangCheng Link: https://lore.kernel.org/r/cbdd1d8b23b8ce6dff0a98a0d89b78673365aa28.1621823299.git.siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/core-api/index.rst | 3 +- .../zh_CN/core-api/refcount-vs-atomic.rst | 154 +++++++++++++++++++++ 2 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/core-api/refcount-vs-atomic.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/core-api/index.rst b/Documentation/translations/zh_CN/core-api/index.rst index a1dd792e46f7..90c9a72a4b0e 100644 --- a/Documentation/translations/zh_CN/core-api/index.rst +++ b/Documentation/translations/zh_CN/core-api/index.rst @@ -65,10 +65,11 @@ Linux如何让一切同时发生。 详情请参阅 :maxdepth: 1 irq/index + refcount-vs-atomic + Todolist: - refcount-vs-atomic local_ops padata ../RCU/index diff --git a/Documentation/translations/zh_CN/core-api/refcount-vs-atomic.rst b/Documentation/translations/zh_CN/core-api/refcount-vs-atomic.rst new file mode 100644 index 000000000000..ea834e38d2f6 --- /dev/null +++ b/Documentation/translations/zh_CN/core-api/refcount-vs-atomic.rst @@ -0,0 +1,154 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/core-api/refcount-vs-atomic.rst +:Translator: Yanteng Si + +.. _cn_refcount-vs-atomic: + + +======================================= +与atomic_t相比,refcount_t的API是这样的 +======================================= + +.. contents:: :local: + +简介 +==== + +refcount_t API的目标是为实现对象的引用计数器提供一个最小的API。虽然来自 +lib/refcount.c的独立于架构的通用实现在下面使用了原子操作,但一些 ``refcount_*()`` +和 ``atomic_*()`` 函数在内存顺序保证方面有很多不同。本文档概述了这些差异,并 +提供了相应的例子,以帮助开发者根据这些内存顺序保证的变化来验证他们的代码。 + +本文档中使用的术语尽量遵循tools/memory-model/Documentation/explanation.txt +中定义的正式LKMM。 + +memory-barriers.txt和atomic_t.txt提供了更多关于内存顺序的背景,包括通用的 +和针对原子操作的。 + +内存顺序的相关类型 +================== + +.. note:: 下面的部分只涵盖了本文使用的与原子操作和引用计数器有关的一些内存顺 + 序类型。如果想了解更广泛的情况,请查阅memory-barriers.txt文件。 + +在没有任何内存顺序保证的情况下(即完全无序),atomics和refcounters只提供原 +子性和程序顺序(program order, po)关系(在同一个CPU上)。它保证每个 +``atomic_* ()`` 和 ``refcount_*()`` 操作都是原子性的,指令在单个CPU上按程序 +顺序执行。这是用READ_ONCE()/WRITE_ONCE()和比较并交换原语实现的。 + +强(完全)内存顺序保证在同一CPU上的所有较早加载和存储的指令(所有程序顺序较早 +[po-earlier]指令)在执行任何程序顺序较后指令(po-later)之前完成。它还保证 +同一CPU上储存的程序优先较早的指令和来自其他CPU传播的指令必须在该CPU执行任何 +程序顺序较后指令之前传播到其他CPU(A-累积属性)。这是用smp_mb()实现的。 + +RELEASE内存顺序保证了在同一CPU上所有较早加载和存储的指令(所有程序顺序较早 +指令)在此操作前完成。它还保证同一CPU上储存的程序优先较早的指令和来自其他CPU +传播的指令必须在释放(release)操作之前传播到所有其他CPU(A-累积属性)。这是用 +smp_store_release()实现的。 + +ACQUIRE内存顺序保证了同一CPU上的所有后加载和存储的指令(所有程序顺序较后 +指令)在获取(acquire)操作之后完成。它还保证在获取操作执行后,同一CPU上 +储存的所有程序顺序较后指令必须传播到所有其他CPU。这是用 +smp_acquire__after_ctrl_dep()实现的。 + +对Refcounters的控制依赖(取决于成功)保证了如果一个对象的引用被成功获得(引用计数 +器的增量或增加行为发生了,函数返回true),那么进一步的存储是针对这个操作的命令。对存 +储的控制依赖没有使用任何明确的屏障来实现,而是依赖于CPU不对存储进行猜测。这只是 +一个单一的CPU关系,对其他CPU不提供任何保证。 + + +函数的比较 +========== + +情况1) - 非 “读/修改/写”(RMW)操作 +------------------------------------ + +函数变化: + + * atomic_set() --> refcount_set() + * atomic_read() --> refcount_read() + +内存顺序保证变化: + + * none (两者都是完全无序的) + + +情况2) - 基于增量的操作,不返回任何值 +-------------------------------------- + +函数变化: + + * atomic_inc() --> refcount_inc() + * atomic_add() --> refcount_add() + +内存顺序保证变化: + + * none (两者都是完全无序的) + +情况3) - 基于递减的RMW操作,没有返回值 +--------------------------------------- + +函数变化: + + * atomic_dec() --> refcount_dec() + +内存顺序保证变化: + + * 完全无序的 --> RELEASE顺序 + + +情况4) - 基于增量的RMW操作,返回一个值 +--------------------------------------- + +函数变化: + + * atomic_inc_not_zero() --> refcount_inc_not_zero() + * 无原子性对应函数 --> refcount_add_not_zero() + +内存顺序保证变化: + + * 完全有序的 --> 控制依赖于存储的成功 + +.. note:: 此处 **假设** 了,必要的顺序是作为获得对象指针的结果而提供的。 + + +情况 5) - 基于Dec/Sub递减的通用RMW操作,返回一个值 +--------------------------------------------------- + +函数变化: + + * atomic_dec_and_test() --> refcount_dec_and_test() + * atomic_sub_and_test() --> refcount_sub_and_test() + +内存顺序保证变化: + + * 完全有序的 --> RELEASE顺序 + 成功后ACQUIRE顺序 + + +情况6)其他基于递减的RMW操作,返回一个值 +---------------------------------------- + +函数变化: + + * 无原子性对应函数 --> refcount_dec_if_one() + * ``atomic_add_unless(&var, -1, 1)`` --> ``refcount_dec_not_one(&var)`` + +内存顺序保证变化: + + * 完全有序的 --> RELEASE顺序 + 控制依赖 + +.. note:: atomic_add_unless()只在执行成功时提供完整的顺序。 + + +情况7)--基于锁的RMW +-------------------- + +函数变化: + + * atomic_dec_and_lock() --> refcount_dec_and_lock() + * atomic_dec_and_mutex_lock() --> refcount_dec_and_mutex_lock() + +内存顺序保证变化: + + * 完全有序 --> RELEASE顺序 + 控制依赖 + 持有 -- cgit v1.3.1 From 8de8fe4f5db6b6bdaf23977f4d165f8c4e94f4ce Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Mon, 24 May 2021 10:40:17 +0800 Subject: docs/zh_CN: add core api local_ops.rst translation Translate Documentation/core-api/local_ops.rst into Chinese. Signed-off-by: Yanteng Si Reviewed-by: Wu XiangCheng Link: https://lore.kernel.org/r/11da5738679fbab9e875f434745d16db1f167f90.1621823299.git.siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/core-api/index.rst | 3 +- .../translations/zh_CN/core-api/local_ops.rst | 194 +++++++++++++++++++++ 2 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 Documentation/translations/zh_CN/core-api/local_ops.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/core-api/index.rst b/Documentation/translations/zh_CN/core-api/index.rst index 90c9a72a4b0e..4b7efb7edb18 100644 --- a/Documentation/translations/zh_CN/core-api/index.rst +++ b/Documentation/translations/zh_CN/core-api/index.rst @@ -66,11 +66,10 @@ Linux如何让一切同时发生。 详情请参阅 irq/index refcount-vs-atomic - + local_ops Todolist: - local_ops padata ../RCU/index diff --git a/Documentation/translations/zh_CN/core-api/local_ops.rst b/Documentation/translations/zh_CN/core-api/local_ops.rst new file mode 100644 index 000000000000..ee67379b6869 --- /dev/null +++ b/Documentation/translations/zh_CN/core-api/local_ops.rst @@ -0,0 +1,194 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/core-api/local_ops.rst +:Translator: Yanteng Si + +.. _cn_local_ops: + + +======================== +本地原子操作的语义和行为 +======================== + +:作者: Mathieu Desnoyers + + +本文解释了本地原子操作的目的,如何为任何给定的架构实现这些操作,并说明了 +如何正确使用这些操作。它还强调了在内存写入顺序很重要的情况下,跨CPU读取 +这些本地变量时必须采取的预防措施。 + +.. note:: + + 注意,基于 ``local_t`` 的操作不建议用于一般内核操作。请使用 ``this_cpu`` + 操作来代替使用,除非真的有特殊目的。大多数内核中使用的 ``local_t`` 已 + 经被 ``this_cpu`` 操作所取代。 ``this_cpu`` 操作在一条指令中结合了重 + 定位和类似 ``local_t`` 的语义,产生了更紧凑和更快的执行代码。 + + +本地原子操作的目的 +================== + +本地原子操作的目的是提供快速和高度可重入的每CPU计数器。它们通过移除LOCK前 +缀和通常需要在CPU间同步的内存屏障,将标准原子操作的性能成本降到最低。 + +在许多情况下,拥有快速的每CPU原子计数器是很有吸引力的:它不需要禁用中断来保护中 +断处理程序,它允许在NMI(Non Maskable Interrupt)处理程序中使用连贯的计数器。 +它对追踪目的和各种性能监测计数器特别有用。 + +本地原子操作只保证在拥有数据的CPU上的变量修改的原子性。因此,必须注意确保只 +有一个CPU写到 ``local_t`` 的数据。这是通过使用每CPU的数据来实现的,并确 +保我们在一个抢占式安全上下文中修改它。然而,从任何一个CPU读取 ``local_t`` +数据都是允许的:这样它就会显得与所有者CPU的其他内存写入顺序不一致。 + + +针对特定架构的实现 +================== + +这可以通过稍微修改标准的原子操作来实现:只有它们的UP变体必须被保留。这通常 +意味着删除LOCK前缀(在i386和x86_64上)和任何SMP同步屏障。如果架构在SMP和 +UP之间没有不同的行为,在你的架构的 ``local.h`` 中包括 ``asm-generic/local.h`` +就足够了。 + +通过在一个结构体中嵌入一个 ``atomic_long_t`` , ``local_t`` 类型被定义为 +一个不透明的 ``signed long`` 。这样做的目的是为了使从这个类型到 +``long`` 的转换失败。该定义看起来像:: + + typedef struct { atomic_long_t a; } local_t; + + +使用本地原子操作时应遵循的规则 +============================== + +* 被本地操作触及的变量必须是每cpu的变量。 + +* *只有* 这些变量的CPU所有者才可以写入这些变量。 + +* 这个CPU可以从任何上下文(进程、中断、软中断、nmi...)中使用本地操作来更新 + 它的local_t变量。 + +* 当在进程上下文中使用本地操作时,必须禁用抢占(或中断),以确保进程在获得每 + CPU变量和进行实际的本地操作之间不会被迁移到不同的CPU。 + +* 当在中断上下文中使用本地操作时,在主线内核上不需要特别注意,因为它们将在局 + 部CPU上运行,并且已经禁用了抢占。然而,我建议无论如何都要明确地禁用抢占, + 以确保它在-rt内核上仍能正确工作。 + +* 读取本地cpu变量将提供该变量的当前拷贝。 + +* 对这些变量的读取可以从任何CPU进行,因为对 “ ``long`` ”,对齐的变量的更新 + 总是原子的。由于写入程序的CPU没有进行内存同步,所以在读取 *其他* cpu的变 + 量时,可以读取该变量的过期副本。 + + +如何使用本地原子操作 +==================== + +:: + + #include + #include + + static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0); + + +计数器 +====== + +计数是在一个signed long的所有位上进行的。 + +在可抢占的上下文中,围绕本地原子操作使用 ``get_cpu_var()`` 和 +``put_cpu_var()`` :它确保在对每个cpu变量进行写访问时,抢占被禁用。比如 +说:: + + local_inc(&get_cpu_var(counters)); + put_cpu_var(counters); + +如果你已经在一个抢占安全上下文中,你可以使用 ``this_cpu_ptr()`` 代替:: + + local_inc(this_cpu_ptr(&counters)); + + + +读取计数器 +========== + +那些本地计数器可以从外部的CPU中读取,以求得计数的总和。请注意,local_read +所看到的跨CPU的数据必须被认为是相对于拥有该数据的CPU上发生的其他内存写入来 +说不符合顺序的:: + + long sum = 0; + for_each_online_cpu(cpu) + sum += local_read(&per_cpu(counters, cpu)); + +如果你想使用远程local_read来同步CPU之间对资源的访问,必须在写入者和读取者 +的CPU上分别使用显式的 ``smp_wmb()`` 和 ``smp_rmb()`` 内存屏障。如果你使 +用 ``local_t`` 变量作为写在缓冲区中的字节的计数器,就会出现这种情况:在缓 +冲区写和计数器增量之间应该有一个 ``smp_wmb()`` ,在计数器读和缓冲区读之间 +也应有一个 ``smp_rmb()`` 。 + +下面是一个使用 ``local.h`` 实现每个cpu基本计数器的示例模块:: + + /* test-local.c + * + * Sample module for local.h usage. + */ + + + #include + #include + #include + + static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0); + + static struct timer_list test_timer; + + /* IPI called on each CPU. */ + static void test_each(void *info) + { + /* Increment the counter from a non preemptible context */ + printk("Increment on cpu %d\n", smp_processor_id()); + local_inc(this_cpu_ptr(&counters)); + + /* This is what incrementing the variable would look like within a + * preemptible context (it disables preemption) : + * + * local_inc(&get_cpu_var(counters)); + * put_cpu_var(counters); + */ + } + + static void do_test_timer(unsigned long data) + { + int cpu; + + /* Increment the counters */ + on_each_cpu(test_each, NULL, 1); + /* Read all the counters */ + printk("Counters read from CPU %d\n", smp_processor_id()); + for_each_online_cpu(cpu) { + printk("Read : CPU %d, count %ld\n", cpu, + local_read(&per_cpu(counters, cpu))); + } + mod_timer(&test_timer, jiffies + 1000); + } + + static int __init test_init(void) + { + /* initialize the timer that will increment the counter */ + timer_setup(&test_timer, do_test_timer, 0); + mod_timer(&test_timer, jiffies + 1); + + return 0; + } + + static void __exit test_exit(void) + { + del_timer_sync(&test_timer); + } + + module_init(test_init); + module_exit(test_exit); + + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Mathieu Desnoyers"); + MODULE_DESCRIPTION("Local Atomic Ops"); -- cgit v1.3.1 From c8237760cc56c79e04a6a47696ef8bb0aab8c77a Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Mon, 24 May 2021 10:23:08 +0800 Subject: docs: zh_CN: update Chinese translations Two new commits were added to the original document: commit ddba35031db2ea89facc91c745e5ad55ba2e0e7f commit 20bc8c1e972f29afcac85e524e430c11a6df5f58 translate them into Chinese. Signed-off-by: Yanteng Si Reviewed-by: Wu XiangCheng Link: https://lore.kernel.org/r/20210524022308.1216098-1-siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/core-api/printk-formats.rst | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/core-api/printk-formats.rst b/Documentation/translations/zh_CN/core-api/printk-formats.rst index 624a090e6ee5..a680c8f164c3 100644 --- a/Documentation/translations/zh_CN/core-api/printk-formats.rst +++ b/Documentation/translations/zh_CN/core-api/printk-formats.rst @@ -122,6 +122,17 @@ seq_printf(),而不是printk())由用户空间进程读取,使用下面描 ``B`` 占位符的结果是带有偏移量的符号名,在打印堆栈回溯时应该使用。占位符将考虑编译器优化 的影响,当使用尾部调用并使用noreturn GCC属性标记时,可能会发生这种优化。 +如果指针在一个模块内,模块名称和可选的构建ID将被打印在符号名称之后,并在说明符的末尾添加 +一个额外的 ``b`` 。 + +:: + + %pS versatile_init+0x0/0x110 [module_name] + %pSb versatile_init+0x0/0x110 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e] + %pSRb versatile_init+0x9/0x110 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e] + (with __builtin_extract_return_addr() translation) + %pBb prev_fn_of_versatile_init+0x88/0x88 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e] + 来自BPF / tracing追踪的探查指针 ---------------------------------- @@ -483,9 +494,10 @@ Fwnode handles :: %pt[RT] YYYY-mm-ddTHH:MM:SS + %pt[RT]s YYYY-mm-dd HH:MM:SS %pt[RT]d YYYY-mm-dd %pt[RT]t HH:MM:SS - %pt[RT][dt][r] + %pt[RT][dt][r][s] 用于打印日期和时间:: @@ -497,6 +509,9 @@ Fwnode handles 默认情况下,年将以1900为单位递增,月将以1为单位递增。 使用%pt[RT]r (raw) 来抑制这种行为。 +%pt[RT]s(空格)将覆盖ISO 8601的分隔符,在日期和时间之间使用''(空格)而 +不是'T'(大写T)。当日期或时间被省略时,它不会有任何影响。 + 通过引用传递。 clk结构体 -- cgit v1.3.1 From a5063ab976024f72865029646d7c8c9dfa63b595 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Wed, 12 May 2021 09:20:49 +1200 Subject: dt-bindings: i2c: mpc: Add fsl,i2c-erratum-a004447 flag Document the fsl,i2c-erratum-a004447 flag which indicates the presence of an i2c erratum on some QorIQ SoCs. Signed-off-by: Chris Packham Acked-by: Rob Herring Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-mpc.yaml | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-mpc.yaml b/Documentation/devicetree/bindings/i2c/i2c-mpc.yaml index 7b553d559c83..98c6fcf7bf26 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mpc.yaml +++ b/Documentation/devicetree/bindings/i2c/i2c-mpc.yaml @@ -46,6 +46,13 @@ properties: description: | I2C bus timeout in microseconds + fsl,i2c-erratum-a004447: + $ref: /schemas/types.yaml#/definitions/flag + description: | + Indicates the presence of QorIQ erratum A-004447, which + says that the standard i2c recovery scheme mechanism does + not work and an alternate implementation is needed. + required: - compatible - reg -- cgit v1.3.1 From aac902925ea646e461c95edc98a8a57eb0def917 Mon Sep 17 00:00:00 2001 From: Sargun Dhillon Date: Mon, 17 May 2021 12:39:05 -0700 Subject: Documentation: seccomp: Fix user notification documentation The documentation had some previously incorrect information about how userspace notifications (and responses) were handled due to a change from a previously proposed patchset. Signed-off-by: Sargun Dhillon Acked-by: Tycho Andersen Acked-by: Christian Brauner Signed-off-by: Kees Cook Fixes: 6a21cc50f0c7 ("seccomp: add a return code to trap to userspace") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20210517193908.3113-2-sargun@sargun.me --- Documentation/userspace-api/seccomp_filter.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/seccomp_filter.rst b/Documentation/userspace-api/seccomp_filter.rst index bd9165241b6c..6efb41cc8072 100644 --- a/Documentation/userspace-api/seccomp_filter.rst +++ b/Documentation/userspace-api/seccomp_filter.rst @@ -250,14 +250,14 @@ Users can read via ``ioctl(SECCOMP_IOCTL_NOTIF_RECV)`` (or ``poll()``) on a seccomp notification fd to receive a ``struct seccomp_notif``, which contains five members: the input length of the structure, a unique-per-filter ``id``, the ``pid`` of the task which triggered this request (which may be 0 if the -task is in a pid ns not visible from the listener's pid namespace), a ``flags`` -member which for now only has ``SECCOMP_NOTIF_FLAG_SIGNALED``, representing -whether or not the notification is a result of a non-fatal signal, and the -``data`` passed to seccomp. Userspace can then make a decision based on this -information about what to do, and ``ioctl(SECCOMP_IOCTL_NOTIF_SEND)`` a -response, indicating what should be returned to userspace. The ``id`` member of -``struct seccomp_notif_resp`` should be the same ``id`` as in ``struct -seccomp_notif``. +task is in a pid ns not visible from the listener's pid namespace). The +notification also contains the ``data`` passed to seccomp, and a filters flag. +The structure should be zeroed out prior to calling the ioctl. + +Userspace can then make a decision based on this information about what to do, +and ``ioctl(SECCOMP_IOCTL_NOTIF_SEND)`` a response, indicating what should be +returned to userspace. The ``id`` member of ``struct seccomp_notif_resp`` should +be the same ``id`` as in ``struct seccomp_notif``. It is worth noting that ``struct seccomp_data`` contains the values of register arguments to the syscall, but does not contain pointers to memory. The task's -- cgit v1.3.1 From fab6216fafdd74cd84de929ffe7b787976d32cff Mon Sep 17 00:00:00 2001 From: Xiongwei Song Date: Mon, 24 May 2021 23:05:45 +0800 Subject: locking/lockdep,doc: Improve readability of the block matrix The block condition matrix is using 'E' as the writer notation, however, the writer reminder below the matrix is using 'W', to make them consistent and make the matrix more readable, we'd better to use 'W' to represent writer. Suggested-by: Waiman Long Suggested-by: Boqun Feng Signed-off-by: Xiongwei Song Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Boqun Feng Link: https://lkml.kernel.org/r/1621868745-23311-1-git-send-email-sxwjean@me.com --- Documentation/locking/lockdep-design.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/locking/lockdep-design.rst b/Documentation/locking/lockdep-design.rst index 9f3cfca9f8a4..82f36cab61bd 100644 --- a/Documentation/locking/lockdep-design.rst +++ b/Documentation/locking/lockdep-design.rst @@ -453,9 +453,9 @@ There are simply four block conditions: Block condition matrix, Y means the row blocks the column, and N means otherwise. +---+---+---+---+ - | | E | r | R | + | | W | r | R | +---+---+---+---+ - | E | Y | Y | Y | + | W | Y | Y | Y | +---+---+---+---+ | r | Y | Y | N | +---+---+---+---+ -- cgit v1.3.1 From c58e7ed28b4534ed073371843d03c433d6a9fe34 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 26 May 2021 12:22:51 -0400 Subject: PM: runtime: document common mistake with pm_runtime_get_sync() pm_runtime_get_sync(), contradictory to intuition, does not drop the runtime PM usage counter on errors which lead to several wrong usages in drivers (missing the put). pm_runtime_resume_and_get() was added as a better implementation so document the preference of using it, hoping it will stop bad patterns. Suggested-by: Marek Szyprowski Signed-off-by: Krzysztof Kozlowski [ rjw: Documentation change edits ] Signed-off-by: Rafael J. Wysocki --- Documentation/power/runtime_pm.rst | 6 +++++- include/linux/pm_runtime.h | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst index 18ae21bf7f92..b48cac5f9048 100644 --- a/Documentation/power/runtime_pm.rst +++ b/Documentation/power/runtime_pm.rst @@ -378,7 +378,11 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: `int pm_runtime_get_sync(struct device *dev);` - increment the device's usage counter, run pm_runtime_resume(dev) and - return its result + return its result; + note that it does not drop the device's usage counter on errors, so + consider using pm_runtime_resume_and_get() instead of it, especially + if its return value is checked by the caller, as this is likely to + result in cleaner code. `int pm_runtime_get_if_in_use(struct device *dev);` - return -EINVAL if 'power.disable_depth' is nonzero; otherwise, if the diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 6c08a085367b..aab8b35e9f8a 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -380,6 +380,9 @@ static inline int pm_runtime_get(struct device *dev) * The possible return values of this function are the same as for * pm_runtime_resume() and the runtime PM usage counter of @dev remains * incremented in all cases, even if it returns an error code. + * Consider using pm_runtime_resume_and_get() instead of it, especially + * if its return value is checked by the caller, as this is likely to result + * in cleaner code. */ static inline int pm_runtime_get_sync(struct device *dev) { -- cgit v1.3.1 From ec6aba3d2be1ed75b3f4c894bb64a36d40db1f55 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 25 May 2021 09:25:19 +0200 Subject: kprobes: Remove kprobe::fault_handler The reason for kprobe::fault_handler(), as given by their comment: * We come here because instructions in the pre/post * handler caused the page_fault, this could happen * if handler tries to access user space by * copy_from_user(), get_user() etc. Let the * user-specified handler try to fix it first. Is just plain bad. Those other handlers are ran from non-preemptible context and had better use _nofault() functions. Also, there is no upstream usage of this. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Christoph Hellwig Acked-by: Masami Hiramatsu Link: https://lore.kernel.org/r/20210525073213.561116662@infradead.org --- Documentation/trace/kprobes.rst | 24 +++++------------------- arch/arc/kernel/kprobes.c | 10 ---------- arch/arm/probes/kprobes/core.c | 9 --------- arch/arm64/kernel/probes/kprobes.c | 10 ---------- arch/csky/kernel/probes/kprobes.c | 10 ---------- arch/ia64/kernel/kprobes.c | 9 --------- arch/mips/kernel/kprobes.c | 3 --- arch/powerpc/kernel/kprobes.c | 10 ---------- arch/riscv/kernel/probes/kprobes.c | 10 ---------- arch/s390/kernel/kprobes.c | 10 ---------- arch/sh/kernel/kprobes.c | 10 ---------- arch/sparc/kernel/kprobes.c | 10 ---------- arch/x86/kernel/kprobes/core.c | 10 ---------- include/linux/kprobes.h | 8 -------- kernel/kprobes.c | 19 ------------------- samples/kprobes/kprobe_example.c | 15 --------------- 16 files changed, 5 insertions(+), 172 deletions(-) (limited to 'Documentation') diff --git a/Documentation/trace/kprobes.rst b/Documentation/trace/kprobes.rst index b757b6dfd3d4..998149ce2fd9 100644 --- a/Documentation/trace/kprobes.rst +++ b/Documentation/trace/kprobes.rst @@ -362,14 +362,11 @@ register_kprobe #include int register_kprobe(struct kprobe *kp); -Sets a breakpoint at the address kp->addr. When the breakpoint is -hit, Kprobes calls kp->pre_handler. After the probed instruction -is single-stepped, Kprobe calls kp->post_handler. If a fault -occurs during execution of kp->pre_handler or kp->post_handler, -or during single-stepping of the probed instruction, Kprobes calls -kp->fault_handler. Any or all handlers can be NULL. If kp->flags -is set KPROBE_FLAG_DISABLED, that kp will be registered but disabled, -so, its handlers aren't hit until calling enable_kprobe(kp). +Sets a breakpoint at the address kp->addr. When the breakpoint is hit, Kprobes +calls kp->pre_handler. After the probed instruction is single-stepped, Kprobe +calls kp->post_handler. Any or all handlers can be NULL. If kp->flags is set +KPROBE_FLAG_DISABLED, that kp will be registered but disabled, so, its handlers +aren't hit until calling enable_kprobe(kp). .. note:: @@ -415,17 +412,6 @@ User's post-handler (kp->post_handler):: p and regs are as described for the pre_handler. flags always seems to be zero. -User's fault-handler (kp->fault_handler):: - - #include - #include - int fault_handler(struct kprobe *p, struct pt_regs *regs, int trapnr); - -p and regs are as described for the pre_handler. trapnr is the -architecture-specific trap number associated with the fault (e.g., -on i386, 13 for a general protection fault or 14 for a page fault). -Returns 1 if it successfully handled the exception. - register_kretprobe ------------------ diff --git a/arch/arc/kernel/kprobes.c b/arch/arc/kernel/kprobes.c index cabef45f11df..9f5b39f38736 100644 --- a/arch/arc/kernel/kprobes.c +++ b/arch/arc/kernel/kprobes.c @@ -323,16 +323,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned long trapnr) */ kprobes_inc_nmissed_count(cur); - /* - * We come here because instructions in the pre/post - * handler caused the page_fault, this could happen - * if handler tries to access user space by - * copy_from_user(), get_user() etc. Let the - * user-specified handler try to fix it first. - */ - if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) - return 1; - /* * In case the user-specified fault handler returned zero, * try to fix up. diff --git a/arch/arm/probes/kprobes/core.c b/arch/arm/probes/kprobes/core.c index a9653117ca0d..7b9b9a5a409b 100644 --- a/arch/arm/probes/kprobes/core.c +++ b/arch/arm/probes/kprobes/core.c @@ -358,15 +358,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr) */ kprobes_inc_nmissed_count(cur); - /* - * We come here because instructions in the pre/post - * handler caused the page_fault, this could happen - * if handler tries to access user space by - * copy_from_user(), get_user() etc. Let the - * user-specified handler try to fix it. - */ - if (cur->fault_handler && cur->fault_handler(cur, regs, fsr)) - return 1; break; default: diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c index d607c9912025..f6b088e9fa70 100644 --- a/arch/arm64/kernel/probes/kprobes.c +++ b/arch/arm64/kernel/probes/kprobes.c @@ -283,16 +283,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr) */ kprobes_inc_nmissed_count(cur); - /* - * We come here because instructions in the pre/post - * handler caused the page_fault, this could happen - * if handler tries to access user space by - * copy_from_user(), get_user() etc. Let the - * user-specified handler try to fix it first. - */ - if (cur->fault_handler && cur->fault_handler(cur, regs, fsr)) - return 1; - /* * In case the user-specified fault handler returned * zero, try to fix up. diff --git a/arch/csky/kernel/probes/kprobes.c b/arch/csky/kernel/probes/kprobes.c index 589f090f48b9..e0e973e49770 100644 --- a/arch/csky/kernel/probes/kprobes.c +++ b/arch/csky/kernel/probes/kprobes.c @@ -301,16 +301,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int trapnr) */ kprobes_inc_nmissed_count(cur); - /* - * We come here because instructions in the pre/post - * handler caused the page_fault, this could happen - * if handler tries to access user space by - * copy_from_user(), get_user() etc. Let the - * user-specified handler try to fix it first. - */ - if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) - return 1; - /* * In case the user-specified fault handler returned * zero, try to fix up. diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index fc1ff8a4d7de..6efed4ecff9e 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c @@ -850,15 +850,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) */ kprobes_inc_nmissed_count(cur); - /* - * We come here because instructions in the pre/post - * handler caused the page_fault, this could happen - * if handler tries to access user space by - * copy_from_user(), get_user() etc. Let the - * user-specified handler try to fix it first. - */ - if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) - return 1; /* * In case the user-specified fault handler returned * zero, try to fix up. diff --git a/arch/mips/kernel/kprobes.c b/arch/mips/kernel/kprobes.c index 54dfba8fa77c..75bff0f77319 100644 --- a/arch/mips/kernel/kprobes.c +++ b/arch/mips/kernel/kprobes.c @@ -403,9 +403,6 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr) struct kprobe *cur = kprobe_running(); struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); - if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) - return 1; - if (kcb->kprobe_status & KPROBE_HIT_SS) { resume_execution(cur, regs, kcb); regs->cp0_status |= kcb->kprobe_old_SR; diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index 01ab2163659e..75b4e874269d 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -508,16 +508,6 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr) */ kprobes_inc_nmissed_count(cur); - /* - * We come here because instructions in the pre/post - * handler caused the page_fault, this could happen - * if handler tries to access user space by - * copy_from_user(), get_user() etc. Let the - * user-specified handler try to fix it first. - */ - if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) - return 1; - /* * In case the user-specified fault handler returned * zero, try to fix up. diff --git a/arch/riscv/kernel/probes/kprobes.c b/arch/riscv/kernel/probes/kprobes.c index 10b965c34536..923b5ea396ea 100644 --- a/arch/riscv/kernel/probes/kprobes.c +++ b/arch/riscv/kernel/probes/kprobes.c @@ -283,16 +283,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int trapnr) */ kprobes_inc_nmissed_count(cur); - /* - * We come here because instructions in the pre/post - * handler caused the page_fault, this could happen - * if handler tries to access user space by - * copy_from_user(), get_user() etc. Let the - * user-specified handler try to fix it first. - */ - if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) - return 1; - /* * In case the user-specified fault handler returned * zero, try to fix up. diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index aae24dc75df6..ad631e33df24 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -452,16 +452,6 @@ static int kprobe_trap_handler(struct pt_regs *regs, int trapnr) */ kprobes_inc_nmissed_count(p); - /* - * We come here because instructions in the pre/post - * handler caused the page_fault, this could happen - * if handler tries to access user space by - * copy_from_user(), get_user() etc. Let the - * user-specified handler try to fix it first. - */ - if (p->fault_handler && p->fault_handler(p, regs, trapnr)) - return 1; - /* * In case the user-specified fault handler returned * zero, try to fix up. diff --git a/arch/sh/kernel/kprobes.c b/arch/sh/kernel/kprobes.c index 756100b01e84..58263420ad2a 100644 --- a/arch/sh/kernel/kprobes.c +++ b/arch/sh/kernel/kprobes.c @@ -389,16 +389,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) */ kprobes_inc_nmissed_count(cur); - /* - * We come here because instructions in the pre/post - * handler caused the page_fault, this could happen - * if handler tries to access user space by - * copy_from_user(), get_user() etc. Let the - * user-specified handler try to fix it first. - */ - if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) - return 1; - /* * In case the user-specified fault handler returned * zero, try to fix up. diff --git a/arch/sparc/kernel/kprobes.c b/arch/sparc/kernel/kprobes.c index 217c21a6986a..db4e341b4b6e 100644 --- a/arch/sparc/kernel/kprobes.c +++ b/arch/sparc/kernel/kprobes.c @@ -352,16 +352,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) */ kprobes_inc_nmissed_count(cur); - /* - * We come here because instructions in the pre/post - * handler caused the page_fault, this could happen - * if handler tries to access user space by - * copy_from_user(), get_user() etc. Let the - * user-specified handler try to fix it first. - */ - if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) - return 1; - /* * In case the user-specified fault handler returned * zero, try to fix up. diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index d3d65545cb8b..cfcdf4b8a306 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -1110,16 +1110,6 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr) * these specific fault cases. */ kprobes_inc_nmissed_count(cur); - - /* - * We come here because instructions in the pre/post - * handler caused the page_fault, this could happen - * if handler tries to access user space by - * copy_from_user(), get_user() etc. Let the - * user-specified handler try to fix it first. - */ - if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) - return 1; } return 0; diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index 1883a4a9f16a..523ffc7bc3a8 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h @@ -54,8 +54,6 @@ struct kretprobe_instance; typedef int (*kprobe_pre_handler_t) (struct kprobe *, struct pt_regs *); typedef void (*kprobe_post_handler_t) (struct kprobe *, struct pt_regs *, unsigned long flags); -typedef int (*kprobe_fault_handler_t) (struct kprobe *, struct pt_regs *, - int trapnr); typedef int (*kretprobe_handler_t) (struct kretprobe_instance *, struct pt_regs *); @@ -83,12 +81,6 @@ struct kprobe { /* Called after addr is executed, unless... */ kprobe_post_handler_t post_handler; - /* - * ... called if executing addr causes a fault (eg. page fault). - * Return 1 if it handled fault, otherwise kernel will see it. - */ - kprobe_fault_handler_t fault_handler; - /* Saved opcode (which has been replaced with breakpoint) */ kprobe_opcode_t opcode; diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 745f08fdd7a6..e41385afe79d 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1183,23 +1183,6 @@ static void aggr_post_handler(struct kprobe *p, struct pt_regs *regs, } NOKPROBE_SYMBOL(aggr_post_handler); -static int aggr_fault_handler(struct kprobe *p, struct pt_regs *regs, - int trapnr) -{ - struct kprobe *cur = __this_cpu_read(kprobe_instance); - - /* - * if we faulted "during" the execution of a user specified - * probe handler, invoke just that probe's fault handler - */ - if (cur && cur->fault_handler) { - if (cur->fault_handler(cur, regs, trapnr)) - return 1; - } - return 0; -} -NOKPROBE_SYMBOL(aggr_fault_handler); - /* Walks the list and increments nmissed count for multiprobe case */ void kprobes_inc_nmissed_count(struct kprobe *p) { @@ -1330,7 +1313,6 @@ static void init_aggr_kprobe(struct kprobe *ap, struct kprobe *p) ap->addr = p->addr; ap->flags = p->flags & ~KPROBE_FLAG_OPTIMIZED; ap->pre_handler = aggr_pre_handler; - ap->fault_handler = aggr_fault_handler; /* We don't care the kprobe which has gone. */ if (p->post_handler && !kprobe_gone(p)) ap->post_handler = aggr_post_handler; @@ -2014,7 +1996,6 @@ int register_kretprobe(struct kretprobe *rp) rp->kp.pre_handler = pre_handler_kretprobe; rp->kp.post_handler = NULL; - rp->kp.fault_handler = NULL; /* Pre-allocate memory for max kretprobe instances */ if (rp->maxactive <= 0) { diff --git a/samples/kprobes/kprobe_example.c b/samples/kprobes/kprobe_example.c index c495664c0a9b..4b2f31828951 100644 --- a/samples/kprobes/kprobe_example.c +++ b/samples/kprobes/kprobe_example.c @@ -94,26 +94,11 @@ static void __kprobes handler_post(struct kprobe *p, struct pt_regs *regs, #endif } -/* - * fault_handler: this is called if an exception is generated for any - * instruction within the pre- or post-handler, or when Kprobes - * single-steps the probed instruction. - */ -static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr) -{ - pr_info("fault_handler: p->addr = 0x%p, trap #%dn", p->addr, trapnr); - /* Return 0 because we don't handle the fault. */ - return 0; -} -/* NOKPROBE_SYMBOL() is also available */ -NOKPROBE_SYMBOL(handler_fault); - static int __init kprobe_init(void) { int ret; kp.pre_handler = handler_pre; kp.post_handler = handler_post; - kp.fault_handler = handler_fault; ret = register_kprobe(&kp); if (ret < 0) { -- cgit v1.3.1 From 65c1d05325b71b592688590d85c5ef6b360ca3fe Mon Sep 17 00:00:00 2001 From: Hsin-Hsiung Wang Date: Wed, 26 May 2021 14:52:02 +0800 Subject: dt-bindings: mfd: Add compatible for the MediaTek MT6359 PMIC This adds compatible for the MediaTek MT6359 PMIC. Signed-off-by: Hsin-Hsiung Wang Acked-by: Rob Herring Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/mt6397.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/mt6397.txt b/Documentation/devicetree/bindings/mfd/mt6397.txt index 2661775a3825..99a84b69a29f 100644 --- a/Documentation/devicetree/bindings/mfd/mt6397.txt +++ b/Documentation/devicetree/bindings/mfd/mt6397.txt @@ -21,6 +21,7 @@ Required properties: compatible: "mediatek,mt6323" for PMIC MT6323 "mediatek,mt6358" for PMIC MT6358 + "mediatek,mt6359" for PMIC MT6359 "mediatek,mt6397" for PMIC MT6397 Optional subnodes: -- cgit v1.3.1 From 8771456635d595707307210d5aa9f8ce41598f94 Mon Sep 17 00:00:00 2001 From: Hsin-Hsiung Wang Date: Wed, 26 May 2021 14:52:03 +0800 Subject: dt-bindings: regulator: Add document for MT6359 regulator add dt-binding document for MediaTek MT6359 PMIC Signed-off-by: Hsin-Hsiung Wang Reviewed-by: Rob Herring Signed-off-by: Lee Jones --- .../bindings/regulator/mt6359-regulator.yaml | 385 +++++++++++++++++++++ 1 file changed, 385 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml b/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml new file mode 100644 index 000000000000..8cc413eb482d --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml @@ -0,0 +1,385 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/mt6359-regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MT6359 Regulator from MediaTek Integrated + +maintainers: + - Hsin-Hsiung Wang + +description: | + List of regulators provided by this controller. It is named + according to its regulator type, buck_ and ldo_. + MT6359 regulators node should be sub node of the MT6397 MFD node. + +patternProperties: + "^buck_v(s1|gpu11|modem|pu|core|s2|pa|proc2|proc1|core_sshub)$": + type: object + $ref: "regulator.yaml#" + + properties: + regulator-name: + pattern: "^v(s1|gpu11|modem|pu|core|s2|pa|proc2|proc1|core_sshub)$" + + unevaluatedProperties: false + + "^ldo_v(ibr|rf12|usb|camio|efuse|xo22)$": + type: object + $ref: "regulator.yaml#" + + properties: + regulator-name: + pattern: "^v(ibr|rf12|usb|camio|efuse|xo22)$" + + unevaluatedProperties: false + + "^ldo_v(rfck|emc|a12|a09|ufs|bbck)$": + type: object + $ref: "regulator.yaml#" + + properties: + regulator-name: + pattern: "^v(rfck|emc|a12|a09|ufs|bbck)$" + + unevaluatedProperties: false + + "^ldo_vcn(18|13|33_1_bt|13_1_wifi|33_2_bt|33_2_wifi)$": + type: object + $ref: "regulator.yaml#" + + properties: + regulator-name: + pattern: "^vcn(18|13|33_1_bt|13_1_wifi|33_2_bt|33_2_wifi)$" + + unevaluatedProperties: false + + "^ldo_vsram_(proc2|others|md|proc1|others_sshub)$": + type: object + $ref: "regulator.yaml#" + + properties: + regulator-name: + pattern: "^vsram_(proc2|others|md|proc1|others_sshub)$" + + unevaluatedProperties: false + + "^ldo_v(fe|bif|io)28$": + type: object + $ref: "regulator.yaml#" + + properties: + regulator-name: + pattern: "^v(fe|bif|io)28$" + + unevaluatedProperties: false + + "^ldo_v(aud|io|aux|rf|m)18$": + type: object + $ref: "regulator.yaml#" + + properties: + regulator-name: + pattern: "^v(aud|io|aux|rf|m)18$" + + unevaluatedProperties: false + + "^ldo_vsim[12]$": + type: object + $ref: "regulator.yaml#" + + properties: + regulator-name: + pattern: "^vsim[12]$" + + required: + - regulator-name + + unevaluatedProperties: false + +additionalProperties: false + +examples: + - | + pmic { + regulators { + mt6359_vs1_buck_reg: buck_vs1 { + regulator-name = "vs1"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <2200000>; + regulator-enable-ramp-delay = <0>; + regulator-always-on; + }; + mt6359_vgpu11_buck_reg: buck_vgpu11 { + regulator-name = "vgpu11"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1193750>; + regulator-ramp-delay = <5000>; + regulator-enable-ramp-delay = <200>; + regulator-allowed-modes = <0 1 2>; + }; + mt6359_vmodem_buck_reg: buck_vmodem { + regulator-name = "vmodem"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1100000>; + regulator-ramp-delay = <10760>; + regulator-enable-ramp-delay = <200>; + }; + mt6359_vpu_buck_reg: buck_vpu { + regulator-name = "vpu"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1193750>; + regulator-ramp-delay = <5000>; + regulator-enable-ramp-delay = <200>; + regulator-allowed-modes = <0 1 2>; + }; + mt6359_vcore_buck_reg: buck_vcore { + regulator-name = "vcore"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1300000>; + regulator-ramp-delay = <5000>; + regulator-enable-ramp-delay = <200>; + regulator-allowed-modes = <0 1 2>; + }; + mt6359_vs2_buck_reg: buck_vs2 { + regulator-name = "vs2"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1600000>; + regulator-enable-ramp-delay = <0>; + regulator-always-on; + }; + mt6359_vpa_buck_reg: buck_vpa { + regulator-name = "vpa"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <3650000>; + regulator-enable-ramp-delay = <300>; + }; + mt6359_vproc2_buck_reg: buck_vproc2 { + regulator-name = "vproc2"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1193750>; + regulator-ramp-delay = <7500>; + regulator-enable-ramp-delay = <200>; + regulator-allowed-modes = <0 1 2>; + }; + mt6359_vproc1_buck_reg: buck_vproc1 { + regulator-name = "vproc1"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1193750>; + regulator-ramp-delay = <7500>; + regulator-enable-ramp-delay = <200>; + regulator-allowed-modes = <0 1 2>; + }; + mt6359_vcore_sshub_buck_reg: buck_vcore_sshub { + regulator-name = "vcore_sshub"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1193750>; + }; + mt6359_vgpu11_sshub_buck_reg: buck_vgpu11_sshub { + regulator-name = "vgpu11_sshub"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1193750>; + }; + mt6359_vaud18_ldo_reg: ldo_vaud18 { + regulator-name = "vaud18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <240>; + }; + mt6359_vsim1_ldo_reg: ldo_vsim1 { + regulator-name = "vsim1"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <3100000>; + }; + mt6359_vibr_ldo_reg: ldo_vibr { + regulator-name = "vibr"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + }; + mt6359_vrf12_ldo_reg: ldo_vrf12 { + regulator-name = "vrf12"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + }; + mt6359_vusb_ldo_reg: ldo_vusb { + regulator-name = "vusb"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <960>; + regulator-always-on; + }; + mt6359_vsram_proc2_ldo_reg: ldo_vsram_proc2 { + regulator-name = "vsram_proc2"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1293750>; + regulator-ramp-delay = <7500>; + regulator-enable-ramp-delay = <240>; + regulator-always-on; + }; + mt6359_vio18_ldo_reg: ldo_vio18 { + regulator-name = "vio18"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + regulator-enable-ramp-delay = <960>; + regulator-always-on; + }; + mt6359_vcamio_ldo_reg: ldo_vcamio { + regulator-name = "vcamio"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + }; + mt6359_vcn18_ldo_reg: ldo_vcn18 { + regulator-name = "vcn18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <240>; + }; + mt6359_vfe28_ldo_reg: ldo_vfe28 { + regulator-name = "vfe28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <120>; + }; + mt6359_vcn13_ldo_reg: ldo_vcn13 { + regulator-name = "vcn13"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1300000>; + }; + mt6359_vcn33_1_bt_ldo_reg: ldo_vcn33_1_bt { + regulator-name = "vcn33_1_bt"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3500000>; + }; + mt6359_vcn33_1_wifi_ldo_reg: ldo_vcn33_1_wifi { + regulator-name = "vcn33_1_wifi"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3500000>; + }; + mt6359_vaux18_ldo_reg: ldo_vaux18 { + regulator-name = "vaux18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <240>; + regulator-always-on; + }; + mt6359_vsram_others_ldo_reg: ldo_vsram_others { + regulator-name = "vsram_others"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1293750>; + regulator-ramp-delay = <5000>; + regulator-enable-ramp-delay = <240>; + }; + mt6359_vefuse_ldo_reg: ldo_vefuse { + regulator-name = "vefuse"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <2000000>; + }; + mt6359_vxo22_ldo_reg: ldo_vxo22 { + regulator-name = "vxo22"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2200000>; + regulator-always-on; + }; + mt6359_vrfck_ldo_reg: ldo_vrfck { + regulator-name = "vrfck"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1700000>; + }; + mt6359_vrfck_1_ldo_reg: ldo_vrfck_1 { + regulator-name = "vrfck"; + regulator-min-microvolt = <1240000>; + regulator-max-microvolt = <1600000>; + }; + mt6359_vbif28_ldo_reg: ldo_vbif28 { + regulator-name = "vbif28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <240>; + }; + mt6359_vio28_ldo_reg: ldo_vio28 { + regulator-name = "vio28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + mt6359_vemc_ldo_reg: ldo_vemc { + regulator-name = "vemc"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <3300000>; + }; + mt6359_vemc_1_ldo_reg: ldo_vemc_1 { + regulator-name = "vemc"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3300000>; + }; + mt6359_vcn33_2_bt_ldo_reg: ldo_vcn33_2_bt { + regulator-name = "vcn33_2_bt"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3500000>; + }; + mt6359_vcn33_2_wifi_ldo_reg: ldo_vcn33_2_wifi { + regulator-name = "vcn33_2_wifi"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3500000>; + }; + mt6359_va12_ldo_reg: ldo_va12 { + regulator-name = "va12"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + }; + mt6359_va09_ldo_reg: ldo_va09 { + regulator-name = "va09"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1200000>; + }; + mt6359_vrf18_ldo_reg: ldo_vrf18 { + regulator-name = "vrf18"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1810000>; + }; + mt6359_vsram_md_ldo_reg: ldo_vsram_md { + regulator-name = "vsram_md"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1293750>; + regulator-ramp-delay = <10760>; + regulator-enable-ramp-delay = <240>; + }; + mt6359_vufs_ldo_reg: ldo_vufs { + regulator-name = "vufs"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + }; + mt6359_vm18_ldo_reg: ldo_vm18 { + regulator-name = "vm18"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + regulator-always-on; + }; + mt6359_vbbck_ldo_reg: ldo_vbbck { + regulator-name = "vbbck"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1200000>; + }; + mt6359_vsram_proc1_ldo_reg: ldo_vsram_proc1 { + regulator-name = "vsram_proc1"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1293750>; + regulator-ramp-delay = <7500>; + regulator-enable-ramp-delay = <240>; + regulator-always-on; + }; + mt6359_vsim2_ldo_reg: ldo_vsim2 { + regulator-name = "vsim2"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <3100000>; + }; + mt6359_vsram_others_sshub_ldo: ldo_vsram_others_sshub { + regulator-name = "vsram_others_sshub"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1293750>; + }; + }; + }; +... -- cgit v1.3.1 From 1434c6a1d32a3a1a77f58a03197b802b1724c740 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Fri, 14 May 2021 17:27:50 +0200 Subject: evm: Deprecate EVM_ALLOW_METADATA_WRITES This patch deprecates the usage of EVM_ALLOW_METADATA_WRITES, as it is no longer necessary. All the issues that prevent the usage of EVM portable signatures just with a public key loaded have been solved. This flag will remain available for a short time to ensure that users are able to use EVM without it. Signed-off-by: Roberto Sassu Signed-off-by: Mimi Zohar --- Documentation/ABI/testing/evm | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/evm b/Documentation/ABI/testing/evm index 2243b72e4110..553fd8a33e56 100644 --- a/Documentation/ABI/testing/evm +++ b/Documentation/ABI/testing/evm @@ -24,7 +24,7 @@ Description: 1 Enable digital signature validation 2 Permit modification of EVM-protected metadata at runtime. Not supported if HMAC validation and - creation is enabled. + creation is enabled (deprecated). 31 Disable further runtime modification of EVM policy === ================================================== @@ -47,7 +47,13 @@ Description: will enable digital signature validation, permit modification of EVM-protected metadata and - disable all further modification of policy + disable all further modification of policy. This option is now + deprecated in favor of:: + + echo 0x80000002 >/evm + + as the outstanding issues that prevent the usage of EVM portable + signatures have been solved. Echoing a value is additive, the new value is added to the existing initialization flags. -- cgit v1.3.1 From 026d7fc92a9d629630779c999fe49ecae93f9d63 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Fri, 14 May 2021 17:27:52 +0200 Subject: ima: Introduce template field evmsig and write to field sig as fallback With the patch to accept EVM portable signatures when the appraise_type=imasig requirement is specified in the policy, appraisal can be successfully done even if the file does not have an IMA signature. However, remote attestation would not see that a different signature type was used, as only IMA signatures can be included in the measurement list. This patch solves the issue by introducing the new template field 'evmsig' to show EVM portable signatures and by including its value in the existing field 'sig' if the IMA signature is not found. Suggested-by: Mimi Zohar Signed-off-by: Roberto Sassu Signed-off-by: Mimi Zohar --- Documentation/security/IMA-templates.rst | 4 +++- security/integrity/ima/ima_template.c | 2 ++ security/integrity/ima/ima_template_lib.c | 33 ++++++++++++++++++++++++++++++- security/integrity/ima/ima_template_lib.h | 2 ++ 4 files changed, 39 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst index c5a8432972ef..9f3e86ab028a 100644 --- a/Documentation/security/IMA-templates.rst +++ b/Documentation/security/IMA-templates.rst @@ -70,9 +70,11 @@ descriptors by adding their identifier to the format string prefix is shown only if the hash algorithm is not SHA1 or MD5); - 'd-modsig': the digest of the event without the appended modsig; - 'n-ng': the name of the event, without size limitations; - - 'sig': the file signature; + - 'sig': the file signature, or the EVM portable signature if the file + signature is not found; - 'modsig' the appended file signature; - 'buf': the buffer data that was used to generate the hash without size limitations; + - 'evmsig': the EVM portable signature; Below, there is the list of defined template descriptors: diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 4e081e650047..7a60848c04a5 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -45,6 +45,8 @@ static const struct ima_template_field supported_fields[] = { .field_show = ima_show_template_digest_ng}, {.field_id = "modsig", .field_init = ima_eventmodsig_init, .field_show = ima_show_template_sig}, + {.field_id = "evmsig", .field_init = ima_eventevmsig_init, + .field_show = ima_show_template_sig}, }; /* diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index c022ee9e2a4e..4314d9a3514c 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -10,6 +10,7 @@ */ #include "ima_template_lib.h" +#include static bool ima_template_hash_algo_allowed(u8 algo) { @@ -438,7 +439,7 @@ int ima_eventsig_init(struct ima_event_data *event_data, struct evm_ima_xattr_data *xattr_value = event_data->xattr_value; if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG)) - return 0; + return ima_eventevmsig_init(event_data, field_data); return ima_write_template_field_data(xattr_value, event_data->xattr_len, DATA_FMT_HEX, field_data); @@ -484,3 +485,33 @@ int ima_eventmodsig_init(struct ima_event_data *event_data, return ima_write_template_field_data(data, data_len, DATA_FMT_HEX, field_data); } + +/* + * ima_eventevmsig_init - include the EVM portable signature as part of the + * template data + */ +int ima_eventevmsig_init(struct ima_event_data *event_data, + struct ima_field_data *field_data) +{ + struct evm_ima_xattr_data *xattr_data = NULL; + int rc = 0; + + if (!event_data->file) + return 0; + + rc = vfs_getxattr_alloc(&init_user_ns, file_dentry(event_data->file), + XATTR_NAME_EVM, (char **)&xattr_data, 0, + GFP_NOFS); + if (rc <= 0) + return 0; + + if (xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG) { + kfree(xattr_data); + return 0; + } + + rc = ima_write_template_field_data((char *)xattr_data, rc, DATA_FMT_HEX, + field_data); + kfree(xattr_data); + return rc; +} diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h index 6b3b880637a0..f4b2a2056d1d 100644 --- a/security/integrity/ima/ima_template_lib.h +++ b/security/integrity/ima/ima_template_lib.h @@ -46,4 +46,6 @@ int ima_eventbuf_init(struct ima_event_data *event_data, struct ima_field_data *field_data); int ima_eventmodsig_init(struct ima_event_data *event_data, struct ima_field_data *field_data); +int ima_eventevmsig_init(struct ima_event_data *event_data, + struct ima_field_data *field_data); #endif /* __LINUX_IMA_TEMPLATE_LIB_H */ -- cgit v1.3.1 From 7dcfeacc5a9d0c130160b86de23279793a8732c8 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Fri, 28 May 2021 09:38:07 +0200 Subject: ima: Define new template fields iuid and igid This patch defines the new template fields iuid and igid, which include respectively the inode UID and GID. For idmapped mounts, still the original UID and GID are provided. These fields can be used to verify the EVM portable signature, if it was included with the template fields sig or evmsig. Signed-off-by: Roberto Sassu Acked-by: Christian Brauner Signed-off-by: Mimi Zohar --- Documentation/security/IMA-templates.rst | 2 ++ security/integrity/ima/ima_template.c | 4 +++ security/integrity/ima/ima_template_lib.c | 45 +++++++++++++++++++++++++++++++ security/integrity/ima/ima_template_lib.h | 4 +++ 4 files changed, 55 insertions(+) (limited to 'Documentation') diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst index 9f3e86ab028a..bf8ce4cf5878 100644 --- a/Documentation/security/IMA-templates.rst +++ b/Documentation/security/IMA-templates.rst @@ -75,6 +75,8 @@ descriptors by adding their identifier to the format string - 'modsig' the appended file signature; - 'buf': the buffer data that was used to generate the hash without size limitations; - 'evmsig': the EVM portable signature; + - 'iuid': the inode UID; + - 'igid': the inode GID; Below, there is the list of defined template descriptors: diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 7a60848c04a5..a5ecd9e2581b 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -47,6 +47,10 @@ static const struct ima_template_field supported_fields[] = { .field_show = ima_show_template_sig}, {.field_id = "evmsig", .field_init = ima_eventevmsig_init, .field_show = ima_show_template_sig}, + {.field_id = "iuid", .field_init = ima_eventinodeuid_init, + .field_show = ima_show_template_uint}, + {.field_id = "igid", .field_init = ima_eventinodegid_init, + .field_show = ima_show_template_uint}, }; /* diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index f23296c33da1..87b40f391739 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -551,3 +551,48 @@ int ima_eventevmsig_init(struct ima_event_data *event_data, kfree(xattr_data); return rc; } + +static int ima_eventinodedac_init_common(struct ima_event_data *event_data, + struct ima_field_data *field_data, + bool get_uid) +{ + unsigned int id; + + if (!event_data->file) + return 0; + + if (get_uid) + id = i_uid_read(file_inode(event_data->file)); + else + id = i_gid_read(file_inode(event_data->file)); + + if (ima_canonical_fmt) { + if (sizeof(id) == sizeof(u16)) + id = cpu_to_le16(id); + else + id = cpu_to_le32(id); + } + + return ima_write_template_field_data((void *)&id, sizeof(id), + DATA_FMT_UINT, field_data); +} + +/* + * ima_eventinodeuid_init - include the inode UID as part of the template + * data + */ +int ima_eventinodeuid_init(struct ima_event_data *event_data, + struct ima_field_data *field_data) +{ + return ima_eventinodedac_init_common(event_data, field_data, true); +} + +/* + * ima_eventinodegid_init - include the inode GID as part of the template + * data + */ +int ima_eventinodegid_init(struct ima_event_data *event_data, + struct ima_field_data *field_data) +{ + return ima_eventinodedac_init_common(event_data, field_data, false); +} diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h index 54b67c80b315..b0aaf109f386 100644 --- a/security/integrity/ima/ima_template_lib.h +++ b/security/integrity/ima/ima_template_lib.h @@ -50,4 +50,8 @@ int ima_eventmodsig_init(struct ima_event_data *event_data, struct ima_field_data *field_data); int ima_eventevmsig_init(struct ima_event_data *event_data, struct ima_field_data *field_data); +int ima_eventinodeuid_init(struct ima_event_data *event_data, + struct ima_field_data *field_data); +int ima_eventinodegid_init(struct ima_event_data *event_data, + struct ima_field_data *field_data); #endif /* __LINUX_IMA_TEMPLATE_LIB_H */ -- cgit v1.3.1 From f8216f6b957f5657c5f4c97f4b037120c6f236bc Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Fri, 28 May 2021 09:38:08 +0200 Subject: ima: Define new template field imode This patch defines the new template field imode, which includes the inode mode. It can be used by a remote verifier to verify the EVM portable signature, if it was included with the template fields sig or evmsig. Signed-off-by: Roberto Sassu Signed-off-by: Mimi Zohar --- Documentation/security/IMA-templates.rst | 1 + security/integrity/ima/ima_template.c | 2 ++ security/integrity/ima/ima_template_lib.c | 22 ++++++++++++++++++++++ security/integrity/ima/ima_template_lib.h | 2 ++ 4 files changed, 27 insertions(+) (limited to 'Documentation') diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst index bf8ce4cf5878..65c1ce451d08 100644 --- a/Documentation/security/IMA-templates.rst +++ b/Documentation/security/IMA-templates.rst @@ -77,6 +77,7 @@ descriptors by adding their identifier to the format string - 'evmsig': the EVM portable signature; - 'iuid': the inode UID; - 'igid': the inode GID; + - 'imode': the inode mode; Below, there is the list of defined template descriptors: diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index a5ecd9e2581b..43784f2bf8bd 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -51,6 +51,8 @@ static const struct ima_template_field supported_fields[] = { .field_show = ima_show_template_uint}, {.field_id = "igid", .field_init = ima_eventinodegid_init, .field_show = ima_show_template_uint}, + {.field_id = "imode", .field_init = ima_eventinodemode_init, + .field_show = ima_show_template_uint}, }; /* diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 87b40f391739..3156fb34b1af 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -596,3 +596,25 @@ int ima_eventinodegid_init(struct ima_event_data *event_data, { return ima_eventinodedac_init_common(event_data, field_data, false); } + +/* + * ima_eventinodemode_init - include the inode mode as part of the template + * data + */ +int ima_eventinodemode_init(struct ima_event_data *event_data, + struct ima_field_data *field_data) +{ + struct inode *inode; + umode_t mode; + + if (!event_data->file) + return 0; + + inode = file_inode(event_data->file); + mode = inode->i_mode; + if (ima_canonical_fmt) + mode = cpu_to_le16(mode); + + return ima_write_template_field_data((char *)&mode, sizeof(mode), + DATA_FMT_UINT, field_data); +} diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h index b0aaf109f386..6509af4a97ee 100644 --- a/security/integrity/ima/ima_template_lib.h +++ b/security/integrity/ima/ima_template_lib.h @@ -54,4 +54,6 @@ int ima_eventinodeuid_init(struct ima_event_data *event_data, struct ima_field_data *field_data); int ima_eventinodegid_init(struct ima_event_data *event_data, struct ima_field_data *field_data); +int ima_eventinodemode_init(struct ima_event_data *event_data, + struct ima_field_data *field_data); #endif /* __LINUX_IMA_TEMPLATE_LIB_H */ -- cgit v1.3.1 From 51568befea2aba3c75a5a929f41909c50176ca6e Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Thu, 27 May 2021 14:43:47 +0800 Subject: docs/zh_CN: add core-api symbol-namespaces.rst translation Translates Documentation/core-api/symbol-namespaces.rst into Chinese. Signed-off-by: Yanteng Si Reviewed-by: Wu XiangCheng Link: https://lore.kernel.org/r/20210527064347.3936694-1-siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/core-api/index.rst | 2 - .../zh_CN/core-api/symbol-namespaces.rst | 142 +++++++++++++++++++++ 2 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 Documentation/translations/zh_CN/core-api/symbol-namespaces.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/core-api/index.rst b/Documentation/translations/zh_CN/core-api/index.rst index 4b7efb7edb18..93162b04624d 100644 --- a/Documentation/translations/zh_CN/core-api/index.rst +++ b/Documentation/translations/zh_CN/core-api/index.rst @@ -26,8 +26,6 @@ printk-basics printk-formats workqueue - -Todolist: symbol-namespaces 数据结构和低级实用程序 diff --git a/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst b/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst new file mode 100644 index 000000000000..ce05c29c7697 --- /dev/null +++ b/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst @@ -0,0 +1,142 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/core-api/symbol-namespaces.rst +:Translator: Yanteng Si + +.. _cn_symbol-namespaces.rst: + + +================================= +符号命名空间(Symbol Namespaces) +================================= + +本文档描述了如何使用符号命名空间来构造通过EXPORT_SYMBOL()系列宏导出的内核内符号的导出面。 + +.. 目录 + + === 1 简介 + === 2 如何定义符号命名空间 + --- 2.1 使用EXPORT_SYMBOL宏 + --- 2.2 使用DEFAULT_SYMBOL_NAMESPACE定义 + === 3 如何使用命名空间中导出的符号 + === 4 加载使用命名空间符号的模块 + === 5 自动创建MODULE_IMPORT_NS声明 + +1. 简介 +======= + +符号命名空间已经被引入,作为构造内核内API的导出面的一种手段。它允许子系统维护者将 +他们导出的符号划分进独立的命名空间。这对于文档的编写非常有用(想想SUBSYSTEM_DEBUG +命名空间),也可以限制一组符号在内核其他部分的使用。今后,使用导出到命名空间的符号 +的模块必须导入命名空间。否则,内核将根据其配置,拒绝加载该模块或警告说缺少 +导入。 + +2. 如何定义符号命名空间 +======================= + +符号可以用不同的方法导出到命名空间。所有这些都在改变 EXPORT_SYMBOL 和与之类似的那些宏 +被检测到的方式,以创建 ksymtab 条目。 + +2.1 使用EXPORT_SYMBOL宏 +======================= + +除了允许将内核符号导出到内核符号表的宏EXPORT_SYMBOL()和EXPORT_SYMBOL_GPL()之外, +这些宏的变体还可以将符号导出到某个命名空间:EXPORT_SYMBOL_NS() 和 EXPORT_SYMBOL_NS_GPL()。 +它们需要一个额外的参数:命名空间(the namespace)。请注意,由于宏扩展,该参数需 +要是一个预处理器符号。例如,要把符号 ``usb_stor_suspend`` 导出到命名空间 ``USB_STORAGE``, +请使用:: + + EXPORT_SYMBOL_NS(usb_stor_suspend, USB_STORAGE); + +相应的 ksymtab 条目结构体 ``kernel_symbol`` 将有相应的成员 ``命名空间`` 集。 +导出时未指明命名空间的符号将指向 ``NULL`` 。如果没有定义命名空间,则默认没有。 +``modpost`` 和kernel/module.c分别在构建时或模块加载时使用名称空间。 + +2.2 使用DEFAULT_SYMBOL_NAMESPACE定义 +==================================== + +为一个子系统的所有符号定义命名空间可能会非常冗长,并可能变得难以维护。因此,我 +们提供了一个默认定义(DEFAULT_SYMBOL_NAMESPACE),如果设置了这个定义, 它将成 +为所有没有指定命名空间的 EXPORT_SYMBOL() 和 EXPORT_SYMBOL_GPL() 宏扩展的默认 +定义。 + +有多种方法来指定这个定义,使用哪种方法取决于子系统和维护者的喜好。第一种方法是在 +子系统的 ``Makefile`` 中定义默认命名空间。例如,如果要将usb-common中定义的所有符号导 +出到USB_COMMON命名空间,可以在drivers/usb/common/Makefile中添加这样一行:: + + ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=USB_COMMON + +这将影响所有 EXPORT_SYMBOL() 和 EXPORT_SYMBOL_GPL() 语句。当这个定义存在时, +用EXPORT_SYMBOL_NS()导出的符号仍然会被导出到作为命名空间参数传递的命名空间中, +因为这个参数优先于默认的符号命名空间。 + +定义默认命名空间的第二个选项是直接在编译单元中作为预处理声明。上面的例子就会变 +成:: + + #undef DEFAULT_SYMBOL_NAMESPACE + #define DEFAULT_SYMBOL_NAMESPACE USB_COMMON + +应置于相关编译单元中任何 EXPORT_SYMBOL 宏之前 + +3. 如何使用命名空间中导出的符号 +=============================== + +为了使用被导出到命名空间的符号,内核模块需要明确地导入这些命名空间。 +否则内核可能会拒绝加载该模块。模块代码需要使用宏MODULE_IMPORT_NS来 +表示它所使用的命名空间的符号。例如,一个使用usb_stor_suspend符号的 +模块,需要使用如下语句导入命名空间USB_STORAGE:: + + MODULE_IMPORT_NS(USB_STORAGE); + +这将在模块中为每个导入的命名空间创建一个 ``modinfo`` 标签。这也顺带 +使得可以用modinfo检查模块已导入的命名空间:: + + $ modinfo drivers/usb/storage/ums-karma.ko + [...] + import_ns: USB_STORAGE + [...] + + +建议将 MODULE_IMPORT_NS() 语句添加到靠近其他模块元数据定义的地方, +如 MODULE_AUTHOR() 或 MODULE_LICENSE() 。关于自动创建缺失的导入 +语句的方法,请参考第5节。 + +4. 加载使用命名空间符号的模块 +============================= + +在模块加载时(比如 ``insmod`` ),内核将检查每个从模块中引用的符号是否可 +用,以及它可能被导出到的名字空间是否被模块导入。内核的默认行为是拒绝 +加载那些没有指明足以导入的模块。此错误会被记录下来,并且加载将以 +EINVAL方式失败。要允许加载不满足这个前提条件的模块,可以使用此配置选项: +设置 MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y 将使加载不受影响,但会 +发出警告。 + +5. 自动创建MODULE_IMPORT_NS声明 +=============================== + +缺少命名空间的导入可以在构建时很容易被检测到。事实上,如果一个模块 +使用了一个命名空间的符号而没有导入它,modpost会发出警告。 +MODULE_IMPORT_NS()语句通常会被添加到一个明确的位置(和其他模块元 +数据一起)。为了使模块作者(和子系统维护者)的生活更加轻松,我们提 +供了一个脚本和make目标来修复丢失的导入。修复丢失的导入可以用:: + + $ make nsdeps + +对模块作者来说,以下情况可能很典型:: + + - 编写依赖未导入命名空间的符号的代码 + - ``make`` + - 注意 ``modpost`` 的警告,提醒你有一个丢失的导入。 + - 运行 ``make nsdeps``将导入添加到正确的代码位置。 + +对于引入命名空间的子系统维护者来说,其步骤非常相似。同样,make nsdeps最终将 +为树内模块添加缺失的命名空间导入:: + + - 向命名空间转移或添加符号(例如,使用EXPORT_SYMBOL_NS())。 + - `make e`(最好是用allmodconfig来覆盖所有的内核模块)。 + - 注意 ``modpost`` 的警告,提醒你有一个丢失的导入。 + - 运行 ``maknsdeps``将导入添加到正确的代码位置。 + +你也可以为外部模块的构建运行nsdeps。典型的用法是:: + + $ make -C M=$PWD nsdeps -- cgit v1.3.1 From cbae918b2c4b6d1c4577d35659196b4f75b5c376 Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Mon, 31 May 2021 20:41:05 +0800 Subject: docs/zh_CN:add core-api padata translation Translate Documentation/core-api/padata.rst into Chinese. Signed-off-by: Yanteng Si Reviewed-by: Wu XiangCheng Link: https://lore.kernel.org/r/20210531124105.946859-1-siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/core-api/index.rst | 2 +- .../translations/zh_CN/core-api/padata.rst | 158 +++++++++++++++++++++ 2 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/core-api/padata.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/core-api/index.rst b/Documentation/translations/zh_CN/core-api/index.rst index 93162b04624d..a8b2afcbf5bc 100644 --- a/Documentation/translations/zh_CN/core-api/index.rst +++ b/Documentation/translations/zh_CN/core-api/index.rst @@ -65,10 +65,10 @@ Linux如何让一切同时发生。 详情请参阅 irq/index refcount-vs-atomic local_ops + padata Todolist: - padata ../RCU/index 低级硬件管理 diff --git a/Documentation/translations/zh_CN/core-api/padata.rst b/Documentation/translations/zh_CN/core-api/padata.rst new file mode 100644 index 000000000000..c627f8f131f9 --- /dev/null +++ b/Documentation/translations/zh_CN/core-api/padata.rst @@ -0,0 +1,158 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/core-api/padata.rst +:Translator: Yanteng Si + +.. _cn_core_api_padata.rst: + +================== +padata并行执行机制 +================== + +:日期: 2020年5月 + +Padata是一种机制,内核可以通过此机制将工作分散到多个CPU上并行完成,同时 +可以选择保持它们的顺序。 + +它最初是为IPsec开发的,它需要在不对这些数据包重新排序的其前提下,为大量的数 +据包进行加密和解密。这是目前padata的序列化作业支持的唯一用途。 + +Padata还支持多线程作业,将作业平均分割,同时在线程之间进行负载均衡和协调。 + +执行序列化作业 +============== + +初始化 +------ + +使用padata执行序列化作业的第一步是建立一个padata_instance结构体,以全面 +控制作业的运行方式:: + + #include + + struct padata_instance *padata_alloc(const char *name); + +'name'即标识了这个实例。 + +然后,通过分配一个padata_shell来完成padata的初始化:: + + struct padata_shell *padata_alloc_shell(struct padata_instance *pinst); + +一个padata_shell用于向padata提交一个作业,并允许一系列这样的作业被独立地 +序列化。一个padata_instance可以有一个或多个padata_shell与之相关联,每个 +都允许一系列独立的作业。 + +修改cpumasks +------------ + +用于运行作业的CPU可以通过两种方式改变,通过padata_set_cpumask()编程或通 +过sysfs。前者的定义是:: + + int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type, + cpumask_var_t cpumask); + +这里cpumask_type是PADATA_CPU_PARALLEL(并行)或PADATA_CPU_SERIAL(串行)之一,其中并 +行cpumask描述了哪些处理器将被用来并行执行提交给这个实例的作业,串行cpumask +定义了哪些处理器被允许用作串行化回调处理器。 cpumask指定了要使用的新cpumask。 + +一个实例的cpumasks可能有sysfs文件。例如,pcrypt的文件在 +/sys/kernel/pcrypt/。在一个实例的目录中,有两个文件,parallel_cpumask +和serial_cpumask,任何一个cpumask都可以通过在文件中回显(echo)一个bitmask +来改变,比如说:: + + echo f > /sys/kernel/pcrypt/pencrypt/parallel_cpumask + +读取其中一个文件会显示用户提供的cpumask,它可能与“可用”的cpumask不同。 + +Padata内部维护着两对cpumask,用户提供的cpumask和“可用的”cpumask(每一对由一个 +并行和一个串行cpumask组成)。用户提供的cpumasks在实例分配时默认为所有可能的CPU, +并且可以如上所述进行更改。可用的cpumasks总是用户提供的cpumasks的一个子集,只包 +含用户提供的掩码中的在线CPU;这些是padata实际使用的cpumasks。因此,向padata提 +供一个包含离线CPU的cpumask是合法的。一旦用户提供的cpumask中的一个离线CPU上线, +padata就会使用它。 + +改变CPU掩码的操作代价很高,所以不应频繁更改。 + +运行一个作业 +------------- + +实际上向padata实例提交工作需要创建一个padata_priv结构体,它代表一个作业:: + + struct padata_priv { + /* Other stuff here... */ + void (*parallel)(struct padata_priv *padata); + void (*serial)(struct padata_priv *padata); + }; + +这个结构体几乎肯定会被嵌入到一些针对要做的工作的大结构体中。它的大部分字段对 +padata来说是私有的,但是这个结构在初始化时应该被清零,并且应该提供parallel()和 +serial()函数。在完成工作的过程中,这些函数将被调用,我们马上就会遇到。 + +工作的提交是通过:: + + int padata_do_parallel(struct padata_shell *ps, + struct padata_priv *padata, int *cb_cpu); + +ps和padata结构体必须如上所述进行设置;cb_cpu指向作业完成后用于最终回调的首选CPU; +它必须在当前实例的CPU掩码中(如果不是,cb_cpu指针将被更新为指向实际选择的CPU)。 +padata_do_parallel()的返回值在成功时为0,表示工作正在进行中。-EBUSY意味着有人 +在其他地方正在搞乱实例的CPU掩码,而当cb_cpu不在串行cpumask中、并行或串行cpumasks +中无在线CPU,或实例停止时,则会出现-EINVAL反馈。 + +每个提交给padata_do_parallel()的作业将依次传递给一个CPU上的上述parallel()函数 +的一个调用,所以真正的并行是通过提交多个作业来实现的。parallel()在运行时禁用软 +件中断,因此不能睡眠。parallel()函数把获得的padata_priv结构体指针作为其唯一的参 +数;关于实际要做的工作的信息可能是通过使用container_of()找到封装结构体来获得的。 + +请注意,parallel()没有返回值;padata子系统假定parallel()将从此时开始负责这项工 +作。作业不需要在这次调用中完成,但是,如果parallel()留下了未完成的工作,它应该准 +备在前一个作业完成之前,被以新的作业再次调用 + +序列化作业 +---------- + +当一个作业完成时,parallel()(或任何实际完成该工作的函数)应该通过调用通知padata此 +事:: + + void padata_do_serial(struct padata_priv *padata); + +在未来的某个时刻,padata_do_serial()将触发对padata_priv结构体中serial()函数的调 +用。这个调用将发生在最初要求调用padata_do_parallel()的CPU上;它也是在本地软件中断 +被禁用的情况下运行的。 +请注意,这个调用可能会被推迟一段时间,因为padata代码会努力确保作业按照提交的顺序完 +成。 + +销毁 +---- + +清理一个padata实例时,可以预见的是调用两个free函数,这两个函数对应于分配的逆过程:: + + void padata_free_shell(struct padata_shell *ps); + void padata_free(struct padata_instance *pinst); + +用户有责任确保在调用上述任何一项之前,所有未完成的工作都已完成。 + +运行多线程作业 +============== + +一个多线程作业有一个主线程和零个或多个辅助线程,主线程参与作业,然后等待所有辅助线 +程完成。padata将作业分割成称为chunk的单元,其中chunk是一个线程在一次调用线程函数 +中完成的作业片段。 + +用户必须做三件事来运行一个多线程作业。首先,通过定义一个padata_mt_job结构体来描述 +作业,这在接口部分有解释。这包括一个指向线程函数的指针,padata每次将作业块分配给线 +程时都会调用这个函数。然后,定义线程函数,它接受三个参数: ``start`` 、 ``end`` 和 ``arg`` , +其中前两个参数限定了线程操作的范围,最后一个是指向作业共享状态的指针,如果有的话。 +准备好共享状态,它通常被分配在主线程的堆栈中。最后,调用padata_do_multithreaded(), +它将在作业完成后返回。 + +接口 +==== + +该API在以下内核代码中: + +include/linux/padata.h + +kernel/padata.c -- cgit v1.3.1 From 0afd4df0d16a5ae894b087562ffef4e5ec43fe24 Mon Sep 17 00:00:00 2001 From: Akira Yokosawa Date: Sun, 30 May 2021 00:19:14 +0900 Subject: docs: pdfdocs: Prevent column squeezing by tabulary Setting a reasonable width to \tymin prevents column squeezing by tabulary. Width of 20em works well in almost all the tables still in the ascii-art format. Excerpt from tabulary package documentation at [1]: To stop very narrow columns being too 'squeezed' by this process any columns that are narrower than \tymin are set to their natural width. [1]: https://mirrors.ctan.org/macros/latex/contrib/tabulary/tabulary.pdf Note: Sphinx has its own default value of \tymin set in sphinxlatextables.sty (Sphinx 4.0.2) and sphinxmulticell.sty (Sphinx 2.4.4) as follows: \setlength{\tymin}{3\fontcharwd\font`0 } , which is not sufficient for kernel-doc. Tested against Sphinx versions 2.4.4 and 4.0.2. Signed-off-by: Akira Yokosawa Link: https://lore.kernel.org/r/277d68fa-c96a-0ccb-6ce0-4d314851d9fe@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/conf.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/conf.py b/Documentation/conf.py index 25aa00c707b0..a05225056e08 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -353,6 +353,8 @@ latex_elements = { # Additional stuff for the LaTeX preamble. 'preamble': ''' + % Prevent column squeezing of tabulary. + \\setlength{\\tymin}{20em} % Use some font with UTF-8 support with XeLaTeX \\usepackage{fontspec} \\setsansfont{DejaVu Sans} -- cgit v1.3.1 From 6ad1800071e80ade38b6287792a6ad678e6085ed Mon Sep 17 00:00:00 2001 From: Haocheng Xie Date: Mon, 31 May 2021 16:39:05 +0800 Subject: docs: Fix typos in Documentation/trace/ftrace.rst Fix the usage of "a/the" and improve the readability. Signed-off-by: Haocheng Xie Link: https://lore.kernel.org/r/20210531083905.25763-1-xiehaocheng.cn@gmail.com [jc: tweaked wording slightly] Signed-off-by: Jonathan Corbet --- Documentation/trace/ftrace.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst index 62c98e9bbdd9..b88c6b79db3e 100644 --- a/Documentation/trace/ftrace.rst +++ b/Documentation/trace/ftrace.rst @@ -354,8 +354,8 @@ of ftrace. Here is a list of some of the key files: is being directly called by the function. If the count is greater than 1 it most likely will be ftrace_ops_list_func(). - If the callback of the function jumps to a trampoline that is - specific to a the callback and not the standard trampoline, + If the callback of a function jumps to a trampoline that is + specific to the callback and which is not the standard trampoline, its address will be printed as well as the function that the trampoline calls. -- cgit v1.3.1 From dc794d3d24246588d4db88c9d2c2ad67273027fd Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 12 Apr 2021 13:04:33 +0200 Subject: media: staging: ipu3-imgu: Move the UAPI header from include under include/uapi The header defines the user space interface but may be mistaken as kernel-only header due to its location. Add "uapi" directory under driver's include directory and move the header there. Suggested-by: Greg KH Signed-off-by: Sakari Ailus Reviewed-by: Bingbu Cao Signed-off-by: Mauro Carvalho Chehab --- Documentation/admin-guide/media/ipu3.rst | 35 +- .../media/v4l/pixfmt-meta-intel-ipu3.rst | 2 +- drivers/staging/media/ipu3/include/intel-ipu3.h | 2786 -------------------- .../staging/media/ipu3/include/uapi/intel-ipu3.h | 2786 ++++++++++++++++++++ drivers/staging/media/ipu3/ipu3-abi.h | 2 +- 5 files changed, 2806 insertions(+), 2805 deletions(-) delete mode 100644 drivers/staging/media/ipu3/include/intel-ipu3.h create mode 100644 drivers/staging/media/ipu3/include/uapi/intel-ipu3.h (limited to 'Documentation') diff --git a/Documentation/admin-guide/media/ipu3.rst b/Documentation/admin-guide/media/ipu3.rst index f59697c7b374..d6454f637ff4 100644 --- a/Documentation/admin-guide/media/ipu3.rst +++ b/Documentation/admin-guide/media/ipu3.rst @@ -234,22 +234,23 @@ The IPU3 ImgU pipelines can be configured using the Media Controller, defined at Running mode and firmware binary selection ------------------------------------------ -ImgU works based on firmware, currently the ImgU firmware support run 2 pipes in -time-sharing with single input frame data. Each pipe can run at certain mode - -"VIDEO" or "STILL", "VIDEO" mode is commonly used for video frames capture, and -"STILL" is used for still frame capture. However, you can also select "VIDEO" to -capture still frames if you want to capture images with less system load and -power. For "STILL" mode, ImgU will try to use smaller BDS factor and output -larger bayer frame for further YUV processing than "VIDEO" mode to get high -quality images. Besides, "STILL" mode need XNR3 to do noise reduction, hence -"STILL" mode will need more power and memory bandwidth than "VIDEO" mode. TNR -will be enabled in "VIDEO" mode and bypassed by "STILL" mode. ImgU is running at -“VIDEO” mode by default, the user can use v4l2 control V4L2_CID_INTEL_IPU3_MODE -(currently defined in drivers/staging/media/ipu3/include/intel-ipu3.h) to query -and set the running mode. For user, there is no difference for buffer queueing -between the "VIDEO" and "STILL" mode, mandatory input and main output node -should be enabled and buffers need be queued, the statistics and the view-finder -queues are optional. +ImgU works based on firmware, currently the ImgU firmware support run 2 pipes +in time-sharing with single input frame data. Each pipe can run at certain mode +- "VIDEO" or "STILL", "VIDEO" mode is commonly used for video frames capture, +and "STILL" is used for still frame capture. However, you can also select +"VIDEO" to capture still frames if you want to capture images with less system +load and power. For "STILL" mode, ImgU will try to use smaller BDS factor and +output larger bayer frame for further YUV processing than "VIDEO" mode to get +high quality images. Besides, "STILL" mode need XNR3 to do noise reduction, +hence "STILL" mode will need more power and memory bandwidth than "VIDEO" mode. +TNR will be enabled in "VIDEO" mode and bypassed by "STILL" mode. ImgU is +running at “VIDEO” mode by default, the user can use v4l2 control +V4L2_CID_INTEL_IPU3_MODE (currently defined in +drivers/staging/media/ipu3/include/uapi/intel-ipu3.h) to query and set the +running mode. For user, there is no difference for buffer queueing between the +"VIDEO" and "STILL" mode, mandatory input and main output node should be +enabled and buffers need be queued, the statistics and the view-finder queues +are optional. The firmware binary will be selected according to current running mode, such log "using binary if_to_osys_striped " or "using binary if_to_osys_primary_striped" @@ -586,7 +587,7 @@ preserved. References ========== -.. [#f5] drivers/staging/media/ipu3/include/intel-ipu3.h +.. [#f5] drivers/staging/media/ipu3/include/uapi/intel-ipu3.h .. [#f1] https://github.com/intel/nvt diff --git a/Documentation/userspace-api/media/v4l/pixfmt-meta-intel-ipu3.rst b/Documentation/userspace-api/media/v4l/pixfmt-meta-intel-ipu3.rst index 5f33d35532ef..84d81dd7a7b5 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-meta-intel-ipu3.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-meta-intel-ipu3.rst @@ -78,4 +78,4 @@ hardware and algorithm details. Intel IPU3 ImgU uAPI data types =============================== -.. kernel-doc:: drivers/staging/media/ipu3/include/intel-ipu3.h +.. kernel-doc:: drivers/staging/media/ipu3/include/uapi/intel-ipu3.h diff --git a/drivers/staging/media/ipu3/include/intel-ipu3.h b/drivers/staging/media/ipu3/include/intel-ipu3.h deleted file mode 100644 index fa3d6ee5adf2..000000000000 --- a/drivers/staging/media/ipu3/include/intel-ipu3.h +++ /dev/null @@ -1,2786 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* Copyright (C) 2017 - 2018 Intel Corporation */ - -#ifndef __IPU3_UAPI_H -#define __IPU3_UAPI_H - -#include - -/* from /drivers/staging/media/ipu3/include/videodev2.h */ - -/* Vendor specific - used for IPU3 camera sub-system */ -/* IPU3 processing parameters */ -#define V4L2_META_FMT_IPU3_PARAMS v4l2_fourcc('i', 'p', '3', 'p') -/* IPU3 3A statistics */ -#define V4L2_META_FMT_IPU3_STAT_3A v4l2_fourcc('i', 'p', '3', 's') - -/* from include/uapi/linux/v4l2-controls.h */ -#define V4L2_CID_INTEL_IPU3_BASE (V4L2_CID_USER_BASE + 0x10c0) -#define V4L2_CID_INTEL_IPU3_MODE (V4L2_CID_INTEL_IPU3_BASE + 1) - -/******************* ipu3_uapi_stats_3a *******************/ - -#define IPU3_UAPI_MAX_STRIPES 2 -#define IPU3_UAPI_MAX_BUBBLE_SIZE 10 - -#define IPU3_UAPI_GRID_START_MASK ((1 << 12) - 1) -#define IPU3_UAPI_GRID_Y_START_EN (1 << 15) - -/* controls generation of meta_data (like FF enable/disable) */ -#define IPU3_UAPI_AWB_RGBS_THR_B_EN (1 << 14) -#define IPU3_UAPI_AWB_RGBS_THR_B_INCL_SAT (1 << 15) - -/** - * struct ipu3_uapi_grid_config - Grid plane config - * - * @width: Grid horizontal dimensions, in number of grid blocks(cells). - * @height: Grid vertical dimensions, in number of grid cells. - * @block_width_log2: Log2 of the width of each cell in pixels. - * for (2^3, 2^4, 2^5, 2^6, 2^7), values [3, 7]. - * @block_height_log2: Log2 of the height of each cell in pixels. - * for (2^3, 2^4, 2^5, 2^6, 2^7), values [3, 7]. - * @height_per_slice: The number of blocks in vertical axis per slice. - * Default 2. - * @x_start: X value of top left corner of Region of Interest(ROI). - * @y_start: Y value of top left corner of ROI - * @x_end: X value of bottom right corner of ROI - * @y_end: Y value of bottom right corner of ROI - * - * Due to the size of total amount of collected data, most statistics - * create a grid-based output, and the data is then divided into "slices". - */ -struct ipu3_uapi_grid_config { - __u8 width; - __u8 height; - __u16 block_width_log2:3; - __u16 block_height_log2:3; - __u16 height_per_slice:8; - __u16 x_start; - __u16 y_start; - __u16 x_end; - __u16 y_end; -} __packed; - -/* - * The grid based data is divided into "slices" called set, each slice of setX - * refers to ipu3_uapi_grid_config width * height_per_slice. - */ -#define IPU3_UAPI_AWB_MAX_SETS 60 -/* Based on grid size 80 * 60 and cell size 16 x 16 */ -#define IPU3_UAPI_AWB_SET_SIZE 1280 -#define IPU3_UAPI_AWB_MD_ITEM_SIZE 8 -#define IPU3_UAPI_AWB_SPARE_FOR_BUBBLES \ - (IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \ - IPU3_UAPI_AWB_MD_ITEM_SIZE) -#define IPU3_UAPI_AWB_MAX_BUFFER_SIZE \ - (IPU3_UAPI_AWB_MAX_SETS * \ - (IPU3_UAPI_AWB_SET_SIZE + IPU3_UAPI_AWB_SPARE_FOR_BUBBLES)) - -/** - * struct ipu3_uapi_awb_raw_buffer - AWB raw buffer - * - * @meta_data: buffer to hold auto white balance meta data which is - * the average values for each color channel. - */ -struct ipu3_uapi_awb_raw_buffer { - __u8 meta_data[IPU3_UAPI_AWB_MAX_BUFFER_SIZE] - __attribute__((aligned(32))); -} __packed; - -/** - * struct ipu3_uapi_awb_config_s - AWB config - * - * @rgbs_thr_gr: gr threshold value. - * @rgbs_thr_r: Red threshold value. - * @rgbs_thr_gb: gb threshold value. - * @rgbs_thr_b: Blue threshold value. - * @grid: &ipu3_uapi_grid_config, the default grid resolution is 16x16 cells. - * - * The threshold is a saturation measure range [0, 8191], 8191 is default. - * Values over threshold may be optionally rejected for averaging. - */ -struct ipu3_uapi_awb_config_s { - __u16 rgbs_thr_gr; - __u16 rgbs_thr_r; - __u16 rgbs_thr_gb; - __u16 rgbs_thr_b; - struct ipu3_uapi_grid_config grid; -} __attribute__((aligned(32))) __packed; - -/** - * struct ipu3_uapi_awb_config - AWB config wrapper - * - * @config: config for auto white balance as defined by &ipu3_uapi_awb_config_s - */ -struct ipu3_uapi_awb_config { - struct ipu3_uapi_awb_config_s config __attribute__((aligned(32))); -} __packed; - -#define IPU3_UAPI_AE_COLORS 4 /* R, G, B, Y */ -#define IPU3_UAPI_AE_BINS 256 -#define IPU3_UAPI_AE_WEIGHTS 96 - -/** - * struct ipu3_uapi_ae_raw_buffer - AE global weighted histogram - * - * @vals: Sum of IPU3_UAPI_AE_COLORS in cell - * - * Each histogram contains IPU3_UAPI_AE_BINS bins. Each bin has 24 bit unsigned - * for counting the number of the pixel. - */ -struct ipu3_uapi_ae_raw_buffer { - __u32 vals[IPU3_UAPI_AE_BINS * IPU3_UAPI_AE_COLORS]; -} __packed; - -/** - * struct ipu3_uapi_ae_raw_buffer_aligned - AE raw buffer - * - * @buff: &ipu3_uapi_ae_raw_buffer to hold full frame meta data. - */ -struct ipu3_uapi_ae_raw_buffer_aligned { - struct ipu3_uapi_ae_raw_buffer buff __attribute__((aligned(32))); -} __packed; - -/** - * struct ipu3_uapi_ae_grid_config - AE weight grid - * - * @width: Grid horizontal dimensions. Value: [16, 32], default 16. - * @height: Grid vertical dimensions. Value: [16, 24], default 16. - * @block_width_log2: Log2 of the width of the grid cell, value: [3, 7]. - * @block_height_log2: Log2 of the height of the grid cell, value: [3, 7]. - * default is 3 (cell size 8x8), 4 cell per grid. - * @reserved0: reserved - * @ae_en: 0: does not write to &ipu3_uapi_ae_raw_buffer_aligned array, - * 1: write normally. - * @rst_hist_array: write 1 to trigger histogram array reset. - * @done_rst_hist_array: flag for histogram array reset done. - * @x_start: X value of top left corner of ROI, default 0. - * @y_start: Y value of top left corner of ROI, default 0. - * @x_end: X value of bottom right corner of ROI - * @y_end: Y value of bottom right corner of ROI - * - * The AE block accumulates 4 global weighted histograms(R, G, B, Y) over - * a defined ROI within the frame. The contribution of each pixel into the - * histogram, defined by &ipu3_uapi_ae_weight_elem LUT, is indexed by a grid. - */ -struct ipu3_uapi_ae_grid_config { - __u8 width; - __u8 height; - __u8 block_width_log2:4; - __u8 block_height_log2:4; - __u8 reserved0:5; - __u8 ae_en:1; - __u8 rst_hist_array:1; - __u8 done_rst_hist_array:1; - __u16 x_start; - __u16 y_start; - __u16 x_end; - __u16 y_end; -} __packed; - -/** - * struct ipu3_uapi_ae_weight_elem - AE weights LUT - * - * @cell0: weighted histogram grid value. - * @cell1: weighted histogram grid value. - * @cell2: weighted histogram grid value. - * @cell3: weighted histogram grid value. - * @cell4: weighted histogram grid value. - * @cell5: weighted histogram grid value. - * @cell6: weighted histogram grid value. - * @cell7: weighted histogram grid value. - * - * Use weighted grid value to give a different contribution factor to each cell. - * Precision u4, range [0, 15]. - */ -struct ipu3_uapi_ae_weight_elem { - __u32 cell0:4; - __u32 cell1:4; - __u32 cell2:4; - __u32 cell3:4; - __u32 cell4:4; - __u32 cell5:4; - __u32 cell6:4; - __u32 cell7:4; -} __packed; - -/** - * struct ipu3_uapi_ae_ccm - AE coefficients for WB and CCM - * - * @gain_gr: WB gain factor for the gr channels. Default 256. - * @gain_r: WB gain factor for the r channel. Default 256. - * @gain_b: WB gain factor for the b channel. Default 256. - * @gain_gb: WB gain factor for the gb channels. Default 256. - * @mat: 4x4 matrix that transforms Bayer quad output from WB to RGB+Y. - * - * Default: - * 128, 0, 0, 0, - * 0, 128, 0, 0, - * 0, 0, 128, 0, - * 0, 0, 0, 128, - * - * As part of the raw frame pre-process stage, the WB and color conversion need - * to be applied to expose the impact of these gain operations. - */ -struct ipu3_uapi_ae_ccm { - __u16 gain_gr; - __u16 gain_r; - __u16 gain_b; - __u16 gain_gb; - __s16 mat[16]; -} __packed; - -/** - * struct ipu3_uapi_ae_config - AE config - * - * @grid_cfg: config for auto exposure statistics grid. See struct - * &ipu3_uapi_ae_grid_config - * @weights: &IPU3_UAPI_AE_WEIGHTS is based on 32x24 blocks in the grid. - * Each grid cell has a corresponding value in weights LUT called - * grid value, global histogram is updated based on grid value and - * pixel value. - * @ae_ccm: Color convert matrix pre-processing block. - * - * Calculate AE grid from image resolution, resample ae weights. - */ -struct ipu3_uapi_ae_config { - struct ipu3_uapi_ae_grid_config grid_cfg __attribute__((aligned(32))); - struct ipu3_uapi_ae_weight_elem weights[IPU3_UAPI_AE_WEIGHTS] - __attribute__((aligned(32))); - struct ipu3_uapi_ae_ccm ae_ccm __attribute__((aligned(32))); -} __packed; - -/** - * struct ipu3_uapi_af_filter_config - AF 2D filter for contrast measurements - * - * @y1_coeff_0: filter Y1, structure: 3x11, support both symmetry and - * anti-symmetry type. A12 is center, A1-A11 are neighbours. - * for analyzing low frequency content, used to calculate sum - * of gradients in x direction. - * @y1_coeff_0.a1: filter1 coefficients A1, u8, default 0. - * @y1_coeff_0.a2: filter1 coefficients A2, u8, default 0. - * @y1_coeff_0.a3: filter1 coefficients A3, u8, default 0. - * @y1_coeff_0.a4: filter1 coefficients A4, u8, default 0. - * @y1_coeff_1: Struct - * @y1_coeff_1.a5: filter1 coefficients A5, u8, default 0. - * @y1_coeff_1.a6: filter1 coefficients A6, u8, default 0. - * @y1_coeff_1.a7: filter1 coefficients A7, u8, default 0. - * @y1_coeff_1.a8: filter1 coefficients A8, u8, default 0. - * @y1_coeff_2: Struct - * @y1_coeff_2.a9: filter1 coefficients A9, u8, default 0. - * @y1_coeff_2.a10: filter1 coefficients A10, u8, default 0. - * @y1_coeff_2.a11: filter1 coefficients A11, u8, default 0. - * @y1_coeff_2.a12: filter1 coefficients A12, u8, default 128. - * @y1_sign_vec: Each bit corresponds to one coefficient sign bit, - * 0: positive, 1: negative, default 0. - * @y2_coeff_0: Y2, same structure as Y1. For analyzing high frequency content. - * @y2_coeff_0.a1: filter2 coefficients A1, u8, default 0. - * @y2_coeff_0.a2: filter2 coefficients A2, u8, default 0. - * @y2_coeff_0.a3: filter2 coefficients A3, u8, default 0. - * @y2_coeff_0.a4: filter2 coefficients A4, u8, default 0. - * @y2_coeff_1: Struct - * @y2_coeff_1.a5: filter2 coefficients A5, u8, default 0. - * @y2_coeff_1.a6: filter2 coefficients A6, u8, default 0. - * @y2_coeff_1.a7: filter2 coefficients A7, u8, default 0. - * @y2_coeff_1.a8: filter2 coefficients A8, u8, default 0. - * @y2_coeff_2: Struct - * @y2_coeff_2.a9: filter1 coefficients A9, u8, default 0. - * @y2_coeff_2.a10: filter1 coefficients A10, u8, default 0. - * @y2_coeff_2.a11: filter1 coefficients A11, u8, default 0. - * @y2_coeff_2.a12: filter1 coefficients A12, u8, default 128. - * @y2_sign_vec: Each bit corresponds to one coefficient sign bit, - * 0: positive, 1: negative, default 0. - * @y_calc: Pre-processing that converts Bayer quad to RGB+Y values to be - * used for building histogram. Range [0, 32], default 8. - * Rule: - * y_gen_rate_gr + y_gen_rate_r + y_gen_rate_b + y_gen_rate_gb = 32 - * A single Y is calculated based on sum of Gr/R/B/Gb based on - * their contribution ratio. - * @y_calc.y_gen_rate_gr: Contribution ratio Gr for Y - * @y_calc.y_gen_rate_r: Contribution ratio R for Y - * @y_calc.y_gen_rate_b: Contribution ratio B for Y - * @y_calc.y_gen_rate_gb: Contribution ratio Gb for Y - * @nf: The shift right value that should be applied during the Y1/Y2 filter to - * make sure the total memory needed is 2 bytes per grid cell. - * @nf.reserved0: reserved - * @nf.y1_nf: Normalization factor for the convolution coeffs of y1, - * should be log2 of the sum of the abs values of the filter - * coeffs, default 7 (2^7 = 128). - * @nf.reserved1: reserved - * @nf.y2_nf: Normalization factor for y2, should be log2 of the sum of the - * abs values of the filter coeffs. - * @nf.reserved2: reserved - */ -struct ipu3_uapi_af_filter_config { - struct { - __u8 a1; - __u8 a2; - __u8 a3; - __u8 a4; - } y1_coeff_0; - struct { - __u8 a5; - __u8 a6; - __u8 a7; - __u8 a8; - } y1_coeff_1; - struct { - __u8 a9; - __u8 a10; - __u8 a11; - __u8 a12; - } y1_coeff_2; - - __u32 y1_sign_vec; - - struct { - __u8 a1; - __u8 a2; - __u8 a3; - __u8 a4; - } y2_coeff_0; - struct { - __u8 a5; - __u8 a6; - __u8 a7; - __u8 a8; - } y2_coeff_1; - struct { - __u8 a9; - __u8 a10; - __u8 a11; - __u8 a12; - } y2_coeff_2; - - __u32 y2_sign_vec; - - struct { - __u8 y_gen_rate_gr; - __u8 y_gen_rate_r; - __u8 y_gen_rate_b; - __u8 y_gen_rate_gb; - } y_calc; - - struct { - __u32 reserved0:8; - __u32 y1_nf:4; - __u32 reserved1:4; - __u32 y2_nf:4; - __u32 reserved2:12; - } nf; -} __packed; - -#define IPU3_UAPI_AF_MAX_SETS 24 -#define IPU3_UAPI_AF_MD_ITEM_SIZE 4 -#define IPU3_UAPI_AF_SPARE_FOR_BUBBLES \ - (IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \ - IPU3_UAPI_AF_MD_ITEM_SIZE) -#define IPU3_UAPI_AF_Y_TABLE_SET_SIZE 128 -#define IPU3_UAPI_AF_Y_TABLE_MAX_SIZE \ - (IPU3_UAPI_AF_MAX_SETS * \ - (IPU3_UAPI_AF_Y_TABLE_SET_SIZE + IPU3_UAPI_AF_SPARE_FOR_BUBBLES) * \ - IPU3_UAPI_MAX_STRIPES) - -/** - * struct ipu3_uapi_af_raw_buffer - AF meta data - * - * @y_table: Each color component will be convolved separately with filter1 - * and filter2 and the result will be summed out and averaged for - * each cell. - */ -struct ipu3_uapi_af_raw_buffer { - __u8 y_table[IPU3_UAPI_AF_Y_TABLE_MAX_SIZE] __attribute__((aligned(32))); -} __packed; - -/** - * struct ipu3_uapi_af_config_s - AF config - * - * @filter_config: AF uses Y1 and Y2 filters as configured in - * &ipu3_uapi_af_filter_config - * @padding: paddings - * @grid_cfg: See &ipu3_uapi_grid_config, default resolution 16x16. Use large - * grid size for large image and vice versa. - */ -struct ipu3_uapi_af_config_s { - struct ipu3_uapi_af_filter_config filter_config __attribute__((aligned(32))); - __u8 padding[4]; - struct ipu3_uapi_grid_config grid_cfg __attribute__((aligned(32))); -} __packed; - -#define IPU3_UAPI_AWB_FR_MAX_SETS 24 -#define IPU3_UAPI_AWB_FR_MD_ITEM_SIZE 8 -#define IPU3_UAPI_AWB_FR_BAYER_TBL_SIZE 256 -#define IPU3_UAPI_AWB_FR_SPARE_FOR_BUBBLES \ - (IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \ - IPU3_UAPI_AWB_FR_MD_ITEM_SIZE) -#define IPU3_UAPI_AWB_FR_BAYER_TABLE_MAX_SIZE \ - (IPU3_UAPI_AWB_FR_MAX_SETS * \ - (IPU3_UAPI_AWB_FR_BAYER_TBL_SIZE + \ - IPU3_UAPI_AWB_FR_SPARE_FOR_BUBBLES) * IPU3_UAPI_MAX_STRIPES) - -/** - * struct ipu3_uapi_awb_fr_raw_buffer - AWB filter response meta data - * - * @meta_data: Statistics output on the grid after convolving with 1D filter. - */ -struct ipu3_uapi_awb_fr_raw_buffer { - __u8 meta_data[IPU3_UAPI_AWB_FR_BAYER_TABLE_MAX_SIZE] - __attribute__((aligned(32))); -} __packed; - -/** - * struct ipu3_uapi_awb_fr_config_s - AWB filter response config - * - * @grid_cfg: grid config, default 16x16. - * @bayer_coeff: 1D Filter 1x11 center symmetry/anti-symmetry. - * coefficients defaults { 0, 0, 0, 0, 0, 128 }. - * Applied on whole image for each Bayer channel separately - * by a weighted sum of its 11x1 neighbors. - * @reserved1: reserved - * @bayer_sign: sign of filter coefficients, default 0. - * @bayer_nf: normalization factor for the convolution coeffs, to make sure - * total memory needed is within pre-determined range. - * NF should be the log2 of the sum of the abs values of the - * filter coeffs, range [7, 14], default 7. - * @reserved2: reserved - */ -struct ipu3_uapi_awb_fr_config_s { - struct ipu3_uapi_grid_config grid_cfg; - __u8 bayer_coeff[6]; - __u16 reserved1; - __u32 bayer_sign; - __u8 bayer_nf; - __u8 reserved2[7]; -} __packed; - -/** - * struct ipu3_uapi_4a_config - 4A config - * - * @awb_config: &ipu3_uapi_awb_config_s, default resolution 16x16 - * @ae_grd_config: auto exposure statistics &ipu3_uapi_ae_grid_config - * @padding: paddings - * @af_config: auto focus config &ipu3_uapi_af_config_s - * @awb_fr_config: &ipu3_uapi_awb_fr_config_s, default resolution 16x16 - */ -struct ipu3_uapi_4a_config { - struct ipu3_uapi_awb_config_s awb_config __attribute__((aligned(32))); - struct ipu3_uapi_ae_grid_config ae_grd_config; - __u8 padding[20]; - struct ipu3_uapi_af_config_s af_config; - struct ipu3_uapi_awb_fr_config_s awb_fr_config - __attribute__((aligned(32))); -} __packed; - -/** - * struct ipu3_uapi_bubble_info - Bubble info for host side debugging - * - * @num_of_stripes: A single frame is divided into several parts called stripes - * due to limitation on line buffer memory. - * The separation between the stripes is vertical. Each such - * stripe is processed as a single frame by the ISP pipe. - * @padding: padding bytes. - * @num_sets: number of sets. - * @padding1: padding bytes. - * @size_of_set: set size. - * @padding2: padding bytes. - * @bubble_size: is the amount of padding in the bubble expressed in "sets". - * @padding3: padding bytes. - */ -struct ipu3_uapi_bubble_info { - __u32 num_of_stripes __attribute__((aligned(32))); - __u8 padding[28]; - __u32 num_sets; - __u8 padding1[28]; - __u32 size_of_set; - __u8 padding2[28]; - __u32 bubble_size; - __u8 padding3[28]; -} __packed; - -/* - * struct ipu3_uapi_stats_3a_bubble_info_per_stripe - */ -struct ipu3_uapi_stats_3a_bubble_info_per_stripe { - struct ipu3_uapi_bubble_info awb[IPU3_UAPI_MAX_STRIPES]; - struct ipu3_uapi_bubble_info af[IPU3_UAPI_MAX_STRIPES]; - struct ipu3_uapi_bubble_info awb_fr[IPU3_UAPI_MAX_STRIPES]; -} __packed; - -/** - * struct ipu3_uapi_ff_status - Enable bits for each 3A fixed function - * - * @awb_en: auto white balance enable - * @padding: padding config - * @ae_en: auto exposure enable - * @padding1: padding config - * @af_en: auto focus enable - * @padding2: padding config - * @awb_fr_en: awb filter response enable bit - * @padding3: padding config - */ -struct ipu3_uapi_ff_status { - __u32 awb_en __attribute__((aligned(32))); - __u8 padding[28]; - __u32 ae_en; - __u8 padding1[28]; - __u32 af_en; - __u8 padding2[28]; - __u32 awb_fr_en; - __u8 padding3[28]; -} __packed; - -/** - * struct ipu3_uapi_stats_3a - 3A statistics - * - * @awb_raw_buffer: auto white balance meta data &ipu3_uapi_awb_raw_buffer - * @ae_raw_buffer: auto exposure raw data &ipu3_uapi_ae_raw_buffer_aligned - * @af_raw_buffer: &ipu3_uapi_af_raw_buffer for auto focus meta data - * @awb_fr_raw_buffer: value as specified by &ipu3_uapi_awb_fr_raw_buffer - * @stats_4a_config: 4a statistics config as defined by &ipu3_uapi_4a_config. - * @ae_join_buffers: 1 to use ae_raw_buffer. - * @padding: padding config - * @stats_3a_bubble_per_stripe: a &ipu3_uapi_stats_3a_bubble_info_per_stripe - * @stats_3a_status: 3a statistics status set in &ipu3_uapi_ff_status - */ -struct ipu3_uapi_stats_3a { - struct ipu3_uapi_awb_raw_buffer awb_raw_buffer; - struct ipu3_uapi_ae_raw_buffer_aligned - ae_raw_buffer[IPU3_UAPI_MAX_STRIPES]; - struct ipu3_uapi_af_raw_buffer af_raw_buffer; - struct ipu3_uapi_awb_fr_raw_buffer awb_fr_raw_buffer; - struct ipu3_uapi_4a_config stats_4a_config; - __u32 ae_join_buffers; - __u8 padding[28]; - struct ipu3_uapi_stats_3a_bubble_info_per_stripe - stats_3a_bubble_per_stripe; - struct ipu3_uapi_ff_status stats_3a_status; -} __packed; - -/******************* ipu3_uapi_acc_param *******************/ - -#define IPU3_UAPI_ISP_VEC_ELEMS 64 -#define IPU3_UAPI_ISP_TNR3_VMEM_LEN 9 - -#define IPU3_UAPI_BNR_LUT_SIZE 32 - -/* number of elements in gamma correction LUT */ -#define IPU3_UAPI_GAMMA_CORR_LUT_ENTRIES 256 - -/* largest grid is 73x56, for grid_height_per_slice of 2, 73x2 = 146 */ -#define IPU3_UAPI_SHD_MAX_CELLS_PER_SET 146 -#define IPU3_UAPI_SHD_MAX_CFG_SETS 28 -/* Normalization shift aka nf */ -#define IPU3_UAPI_SHD_BLGR_NF_SHIFT 13 -#define IPU3_UAPI_SHD_BLGR_NF_MASK 7 - -#define IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS 16 -#define IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS 14 -#define IPU3_UAPI_YUVP2_TCC_GAIN_PCWL_LUT_ELEMENTS 258 -#define IPU3_UAPI_YUVP2_TCC_R_SQR_LUT_ELEMENTS 24 - -#define IPU3_UAPI_ANR_LUT_SIZE 26 -#define IPU3_UAPI_ANR_PYRAMID_SIZE 22 - -#define IPU3_UAPI_LIN_LUT_SIZE 64 - -/* Bayer Noise Reduction related structs */ - -/** - * struct ipu3_uapi_bnr_static_config_wb_gains_config - White balance gains - * - * @gr: white balance gain for Gr channel. - * @r: white balance gain for R channel. - * @b: white balance gain for B channel. - * @gb: white balance gain for Gb channel. - * - * Precision u3.13, range [0, 8). White balance correction is done by applying - * a multiplicative gain to each color channels prior to BNR. - */ -struct ipu3_uapi_bnr_static_config_wb_gains_config { - __u16 gr; - __u16 r; - __u16 b; - __u16 gb; -} __packed; - -/** - * struct ipu3_uapi_bnr_static_config_wb_gains_thr_config - Threshold config - * - * @gr: white balance threshold gain for Gr channel. - * @r: white balance threshold gain for R channel. - * @b: white balance threshold gain for B channel. - * @gb: white balance threshold gain for Gb channel. - * - * Defines the threshold that specifies how different a defect pixel can be from - * its neighbors.(used by dynamic defect pixel correction sub block) - * Precision u4.4 range [0, 8]. - */ -struct ipu3_uapi_bnr_static_config_wb_gains_thr_config { - __u8 gr; - __u8 r; - __u8 b; - __u8 gb; -} __packed; - -/** - * struct ipu3_uapi_bnr_static_config_thr_coeffs_config - Noise model - * coefficients that controls noise threshold - * - * @cf: Free coefficient for threshold calculation, range [0, 8191], default 0. - * @reserved0: reserved - * @cg: Gain coefficient for threshold calculation, [0, 31], default 8. - * @ci: Intensity coefficient for threshold calculation. range [0, 0x1f] - * default 6. - * format: u3.2 (3 most significant bits represent whole number, - * 2 least significant bits represent the fractional part - * with each count representing 0.25) - * e.g. 6 in binary format is 00110, that translates to 1.5 - * @reserved1: reserved - * @r_nf: Normalization shift value for r^2 calculation, range [12, 20] - * where r is a radius of pixel [row, col] from centor of sensor. - * default 14. - * - * Threshold used to distinguish between noise and details. - */ -struct ipu3_uapi_bnr_static_config_thr_coeffs_config { - __u32 cf:13; - __u32 reserved0:3; - __u32 cg:5; - __u32 ci:5; - __u32 reserved1:1; - __u32 r_nf:5; -} __packed; - -/** - * struct ipu3_uapi_bnr_static_config_thr_ctrl_shd_config - Shading config - * - * @gr: Coefficient defines lens shading gain approximation for gr channel - * @r: Coefficient defines lens shading gain approximation for r channel - * @b: Coefficient defines lens shading gain approximation for b channel - * @gb: Coefficient defines lens shading gain approximation for gb channel - * - * Parameters for noise model (NM) adaptation of BNR due to shading correction. - * All above have precision of u3.3, default to 0. - */ -struct ipu3_uapi_bnr_static_config_thr_ctrl_shd_config { - __u8 gr; - __u8 r; - __u8 b; - __u8 gb; -} __packed; - -/** - * struct ipu3_uapi_bnr_static_config_opt_center_config - Optical center config - * - * @x_reset: Reset value of X (col start - X center). Precision s12.0. - * @reserved0: reserved - * @y_reset: Reset value of Y (row start - Y center). Precision s12.0. - * @reserved2: reserved - * - * Distance from corner to optical center for NM adaptation due to shading - * correction (should be calculated based on shading tables) - */ -struct ipu3_uapi_bnr_static_config_opt_center_config { - __s32 x_reset:13; - __u32 reserved0:3; - __s32 y_reset:13; - __u32 reserved2:3; -} __packed; - -/** - * struct ipu3_uapi_bnr_static_config_lut_config - BNR square root lookup table - * - * @values: pre-calculated values of square root function. - * - * LUT implementation of square root operation. - */ -struct ipu3_uapi_bnr_static_config_lut_config { - __u8 values[IPU3_UAPI_BNR_LUT_SIZE]; -} __packed; - -/** - * struct ipu3_uapi_bnr_static_config_bp_ctrl_config - Detect bad pixels (bp) - * - * @bp_thr_gain: Defines the threshold that specifies how different a - * defect pixel can be from its neighbors. Threshold is - * dependent on de-noise threshold calculated by algorithm. - * Range [4, 31], default 4. - * @reserved0: reserved - * @defect_mode: Mode of addressed defect pixels, - * 0 - single defect pixel is expected, - * 1 - 2 adjacent defect pixels are expected, default 1. - * @bp_gain: Defines how 2nd derivation that passes through a defect pixel - * is different from 2nd derivations that pass through - * neighbor pixels. u4.2, range [0, 256], default 8. - * @reserved1: reserved - * @w0_coeff: Blending coefficient of defect pixel correction. - * Precision u4, range [0, 8], default 8. - * @reserved2: reserved - * @w1_coeff: Enable influence of incorrect defect pixel correction to be - * avoided. Precision u4, range [1, 8], default 8. - * @reserved3: reserved - */ -struct ipu3_uapi_bnr_static_config_bp_ctrl_config { - __u32 bp_thr_gain:5; - __u32 reserved0:2; - __u32 defect_mode:1; - __u32 bp_gain:6; - __u32 reserved1:18; - __u32 w0_coeff:4; - __u32 reserved2:4; - __u32 w1_coeff:4; - __u32 reserved3:20; -} __packed; - -/** - * struct ipu3_uapi_bnr_static_config_dn_detect_ctrl_config - Denoising config - * - * @alpha: Weight of central element of smoothing filter. - * @beta: Weight of peripheral elements of smoothing filter, default 4. - * @gamma: Weight of diagonal elements of smoothing filter, default 4. - * - * beta and gamma parameter define the strength of the noise removal filter. - * All above has precision u0.4, range [0, 0xf] - * format: u0.4 (no / zero bits represent whole number, - * 4 bits represent the fractional part - * with each count representing 0.0625) - * e.g. 0xf translates to 0.0625x15 = 0.9375 - * - * @reserved0: reserved - * @max_inf: Maximum increase of peripheral or diagonal element influence - * relative to the pre-defined value range: [0x5, 0xa] - * @reserved1: reserved - * @gd_enable: Green disparity enable control, 0 - disable, 1 - enable. - * @bpc_enable: Bad pixel correction enable control, 0 - disable, 1 - enable. - * @bnr_enable: Bayer noise removal enable control, 0 - disable, 1 - enable. - * @ff_enable: Fixed function enable, 0 - disable, 1 - enable. - * @reserved2: reserved - */ -struct ipu3_uapi_bnr_static_config_dn_detect_ctrl_config { - __u32 alpha:4; - __u32 beta:4; - __u32 gamma:4; - __u32 reserved0:4; - __u32 max_inf:4; - __u32 reserved1:7; - __u32 gd_enable:1; - __u32 bpc_enable:1; - __u32 bnr_enable:1; - __u32 ff_enable:1; - __u32 reserved2:1; -} __packed; - -/** - * struct ipu3_uapi_bnr_static_config_opt_center_sqr_config - BNR optical square - * - * @x_sqr_reset: Reset value of X^2. - * @y_sqr_reset: Reset value of Y^2. - * - * Please note: - * - * #. X and Y ref to - * &ipu3_uapi_bnr_static_config_opt_center_config - * #. Both structs are used in threshold formula to calculate r^2, where r - * is a radius of pixel [row, col] from centor of sensor. - */ -struct ipu3_uapi_bnr_static_config_opt_center_sqr_config { - __u32 x_sqr_reset; - __u32 y_sqr_reset; -} __packed; - -/** - * struct ipu3_uapi_bnr_static_config - BNR static config - * - * @wb_gains: white balance gains &ipu3_uapi_bnr_static_config_wb_gains_config - * @wb_gains_thr: white balance gains threshold as defined by - * &ipu3_uapi_bnr_static_config_wb_gains_thr_config - * @thr_coeffs: coefficients of threshold - * &ipu3_uapi_bnr_static_config_thr_coeffs_config - * @thr_ctrl_shd: control of shading threshold - * &ipu3_uapi_bnr_static_config_thr_ctrl_shd_config - * @opt_center: optical center &ipu3_uapi_bnr_static_config_opt_center_config - * - * Above parameters and opt_center_sqr are used for white balance and shading. - * - * @lut: lookup table &ipu3_uapi_bnr_static_config_lut_config - * @bp_ctrl: detect and remove bad pixels as defined in struct - * &ipu3_uapi_bnr_static_config_bp_ctrl_config - * @dn_detect_ctrl: detect and remove noise. - * &ipu3_uapi_bnr_static_config_dn_detect_ctrl_config - * @column_size: The number of pixels in column. - * @opt_center_sqr: Reset value of r^2 to optical center, see - * &ipu3_uapi_bnr_static_config_opt_center_sqr_config. - */ -struct ipu3_uapi_bnr_static_config { - struct ipu3_uapi_bnr_static_config_wb_gains_config wb_gains; - struct ipu3_uapi_bnr_static_config_wb_gains_thr_config wb_gains_thr; - struct ipu3_uapi_bnr_static_config_thr_coeffs_config thr_coeffs; - struct ipu3_uapi_bnr_static_config_thr_ctrl_shd_config thr_ctrl_shd; - struct ipu3_uapi_bnr_static_config_opt_center_config opt_center; - struct ipu3_uapi_bnr_static_config_lut_config lut; - struct ipu3_uapi_bnr_static_config_bp_ctrl_config bp_ctrl; - struct ipu3_uapi_bnr_static_config_dn_detect_ctrl_config dn_detect_ctrl; - __u32 column_size; - struct ipu3_uapi_bnr_static_config_opt_center_sqr_config opt_center_sqr; -} __packed; - -/** - * struct ipu3_uapi_bnr_static_config_green_disparity - Correct green disparity - * - * @gd_red: Shading gain coeff for gr disparity level in bright red region. - * Precision u0.6, default 4(0.0625). - * @reserved0: reserved - * @gd_green: Shading gain coeff for gr disparity level in bright green - * region. Precision u0.6, default 4(0.0625). - * @reserved1: reserved - * @gd_blue: Shading gain coeff for gr disparity level in bright blue region. - * Precision u0.6, default 4(0.0625). - * @reserved2: reserved - * @gd_black: Maximal green disparity level in dark region (stronger disparity - * assumed to be image detail). Precision u14, default 80. - * @reserved3: reserved - * @gd_shading: Change maximal green disparity level according to square - * distance from image center. - * @reserved4: reserved - * @gd_support: Lower bound for the number of second green color pixels in - * current pixel neighborhood with less than threshold difference - * from it. - * - * The shading gain coeff of red, green, blue and black are used to calculate - * threshold given a pixel's color value and its coordinates in the image. - * - * @reserved5: reserved - * @gd_clip: Turn green disparity clip on/off, [0, 1], default 1. - * @gd_central_weight: Central pixel weight in 9 pixels weighted sum. - */ -struct ipu3_uapi_bnr_static_config_green_disparity { - __u32 gd_red:6; - __u32 reserved0:2; - __u32 gd_green:6; - __u32 reserved1:2; - __u32 gd_blue:6; - __u32 reserved2:10; - __u32 gd_black:14; - __u32 reserved3:2; - __u32 gd_shading:7; - __u32 reserved4:1; - __u32 gd_support:2; - __u32 reserved5:1; - __u32 gd_clip:1; - __u32 gd_central_weight:4; -} __packed; - -/** - * struct ipu3_uapi_dm_config - De-mosaic parameters - * - * @dm_en: de-mosaic enable. - * @ch_ar_en: Checker artifacts removal enable flag. Default 0. - * @fcc_en: False color correction (FCC) enable flag. Default 0. - * @reserved0: reserved - * @frame_width: do not care - * @gamma_sc: Sharpening coefficient (coefficient of 2-d derivation of - * complementary color in Hamilton-Adams interpolation). - * u5, range [0, 31], default 8. - * @reserved1: reserved - * @lc_ctrl: Parameter that controls weights of Chroma Homogeneity metric - * in calculation of final homogeneity metric. - * u5, range [0, 31], default 7. - * @reserved2: reserved - * @cr_param1: First parameter that defines Checker artifact removal - * feature gain. Precision u5, range [0, 31], default 8. - * @reserved3: reserved - * @cr_param2: Second parameter that defines Checker artifact removal - * feature gain. Precision u5, range [0, 31], default 8. - * @reserved4: reserved - * @coring_param: Defines power of false color correction operation. - * low for preserving edge colors, high for preserving gray - * edge artifacts. - * Precision u1.4, range [0, 1.9375], default 4 (0.25). - * @reserved5: reserved - * - * The demosaic fixed function block is responsible to covert Bayer(mosaiced) - * images into color images based on demosaicing algorithm. - */ -struct ipu3_uapi_dm_config { - __u32 dm_en:1; - __u32 ch_ar_en:1; - __u32 fcc_en:1; - __u32 reserved0:13; - __u32 frame_width:16; - - __u32 gamma_sc:5; - __u32 reserved1:3; - __u32 lc_ctrl:5; - __u32 reserved2:3; - __u32 cr_param1:5; - __u32 reserved3:3; - __u32 cr_param2:5; - __u32 reserved4:3; - - __u32 coring_param:5; - __u32 reserved5:27; -} __packed; - -/** - * struct ipu3_uapi_ccm_mat_config - Color correction matrix - * - * @coeff_m11: CCM 3x3 coefficient, range [-65536, 65535] - * @coeff_m12: CCM 3x3 coefficient, range [-8192, 8191] - * @coeff_m13: CCM 3x3 coefficient, range [-32768, 32767] - * @coeff_o_r: Bias 3x1 coefficient, range [-8191, 8181] - * @coeff_m21: CCM 3x3 coefficient, range [-32767, 32767] - * @coeff_m22: CCM 3x3 coefficient, range [-8192, 8191] - * @coeff_m23: CCM 3x3 coefficient, range [-32768, 32767] - * @coeff_o_g: Bias 3x1 coefficient, range [-8191, 8181] - * @coeff_m31: CCM 3x3 coefficient, range [-32768, 32767] - * @coeff_m32: CCM 3x3 coefficient, range [-8192, 8191] - * @coeff_m33: CCM 3x3 coefficient, range [-32768, 32767] - * @coeff_o_b: Bias 3x1 coefficient, range [-8191, 8181] - * - * Transform sensor specific color space to standard sRGB by applying 3x3 matrix - * and adding a bias vector O. The transformation is basically a rotation and - * translation in the 3-dimensional color spaces. Here are the defaults: - * - * 9775, -2671, 1087, 0 - * -1071, 8303, 815, 0 - * -23, -7887, 16103, 0 - */ -struct ipu3_uapi_ccm_mat_config { - __s16 coeff_m11; - __s16 coeff_m12; - __s16 coeff_m13; - __s16 coeff_o_r; - __s16 coeff_m21; - __s16 coeff_m22; - __s16 coeff_m23; - __s16 coeff_o_g; - __s16 coeff_m31; - __s16 coeff_m32; - __s16 coeff_m33; - __s16 coeff_o_b; -} __packed; - -/** - * struct ipu3_uapi_gamma_corr_ctrl - Gamma correction - * - * @enable: gamma correction enable. - * @reserved: reserved - */ -struct ipu3_uapi_gamma_corr_ctrl { - __u32 enable:1; - __u32 reserved:31; -} __packed; - -/** - * struct ipu3_uapi_gamma_corr_lut - Per-pixel tone mapping implemented as LUT. - * - * @lut: 256 tabulated values of the gamma function. LUT[1].. LUT[256] - * format u13.0, range [0, 8191]. - * - * The tone mapping operation is done by a Piece wise linear graph - * that is implemented as a lookup table(LUT). The pixel component input - * intensity is the X-axis of the graph which is the table entry. - */ -struct ipu3_uapi_gamma_corr_lut { - __u16 lut[IPU3_UAPI_GAMMA_CORR_LUT_ENTRIES]; -} __packed; - -/** - * struct ipu3_uapi_gamma_config - Gamma config - * - * @gc_ctrl: control of gamma correction &ipu3_uapi_gamma_corr_ctrl - * @gc_lut: lookup table of gamma correction &ipu3_uapi_gamma_corr_lut - */ -struct ipu3_uapi_gamma_config { - struct ipu3_uapi_gamma_corr_ctrl gc_ctrl __attribute__((aligned(32))); - struct ipu3_uapi_gamma_corr_lut gc_lut __attribute__((aligned(32))); -} __packed; - -/** - * struct ipu3_uapi_csc_mat_config - Color space conversion matrix config - * - * @coeff_c11: Conversion matrix value, format s0.14, range [-16384, 16383]. - * @coeff_c12: Conversion matrix value, format s0.14, range [-8192, 8191]. - * @coeff_c13: Conversion matrix value, format s0.14, range [-16384, 16383]. - * @coeff_b1: Bias 3x1 coefficient, s13.0 range [-8192, 8191]. - * @coeff_c21: Conversion matrix value, format s0.14, range [-16384, 16383]. - * @coeff_c22: Conversion matrix value, format s0.14, range [-8192, 8191]. - * @coeff_c23: Conversion matrix value, format s0.14, range [-16384, 16383]. - * @coeff_b2: Bias 3x1 coefficient, s13.0 range [-8192, 8191]. - * @coeff_c31: Conversion matrix value, format s0.14, range [-16384, 16383]. - * @coeff_c32: Conversion matrix value, format s0.14, range [-8192, 8191]. - * @coeff_c33: Conversion matrix value, format s0.14, range [-16384, 16383]. - * @coeff_b3: Bias 3x1 coefficient, s13.0 range [-8192, 8191]. - * - * To transform each pixel from RGB to YUV (Y - brightness/luminance, - * UV -chroma) by applying the pixel's values by a 3x3 matrix and adding an - * optional bias 3x1 vector. Here are the default values for the matrix: - * - * 4898, 9617, 1867, 0, - * -2410, -4732, 7143, 0, - * 10076, -8437, -1638, 0, - * - * (i.e. for real number 0.299, 0.299 * 2^14 becomes 4898.) - */ -struct ipu3_uapi_csc_mat_config { - __s16 coeff_c11; - __s16 coeff_c12; - __s16 coeff_c13; - __s16 coeff_b1; - __s16 coeff_c21; - __s16 coeff_c22; - __s16 coeff_c23; - __s16 coeff_b2; - __s16 coeff_c31; - __s16 coeff_c32; - __s16 coeff_c33; - __s16 coeff_b3; -} __packed; - -/** - * struct ipu3_uapi_cds_params - Chroma down-scaling - * - * @ds_c00: range [0, 3] - * @ds_c01: range [0, 3] - * @ds_c02: range [0, 3] - * @ds_c03: range [0, 3] - * @ds_c10: range [0, 3] - * @ds_c11: range [0, 3] - * @ds_c12: range [0, 3] - * @ds_c13: range [0, 3] - * - * In case user does not provide, above 4x2 filter will use following defaults: - * 1, 3, 3, 1, - * 1, 3, 3, 1, - * - * @ds_nf: Normalization factor for Chroma output downscaling filter, - * range 0,4, default 2. - * @reserved0: reserved - * @csc_en: Color space conversion enable - * @uv_bin_output: 0: output YUV 4.2.0, 1: output YUV 4.2.2(default). - * @reserved1: reserved - */ -struct ipu3_uapi_cds_params { - __u32 ds_c00:2; - __u32 ds_c01:2; - __u32 ds_c02:2; - __u32 ds_c03:2; - __u32 ds_c10:2; - __u32 ds_c11:2; - __u32 ds_c12:2; - __u32 ds_c13:2; - __u32 ds_nf:5; - __u32 reserved0:3; - __u32 csc_en:1; - __u32 uv_bin_output:1; - __u32 reserved1:6; -} __packed; - -/** - * struct ipu3_uapi_shd_grid_config - Bayer shading(darkening) correction - * - * @width: Grid horizontal dimensions, u8, [8, 128], default 73 - * @height: Grid vertical dimensions, u8, [8, 128], default 56 - * @block_width_log2: Log2 of the width of the grid cell in pixel count - * u4, [0, 15], default value 5. - * @reserved0: reserved - * @block_height_log2: Log2 of the height of the grid cell in pixel count - * u4, [0, 15], default value 6. - * @reserved1: reserved - * @grid_height_per_slice: SHD_MAX_CELLS_PER_SET/width. - * (with SHD_MAX_CELLS_PER_SET = 146). - * @x_start: X value of top left corner of sensor relative to ROI - * s13, [-4096, 0], default 0, only negative values. - * @y_start: Y value of top left corner of sensor relative to ROI - * s13, [-4096, 0], default 0, only negative values. - */ -struct ipu3_uapi_shd_grid_config { - /* reg 0 */ - __u8 width; - __u8 height; - __u8 block_width_log2:3; - __u8 reserved0:1; - __u8 block_height_log2:3; - __u8 reserved1:1; - __u8 grid_height_per_slice; - /* reg 1 */ - __s16 x_start; - __s16 y_start; -} __packed; - -/** - * struct ipu3_uapi_shd_general_config - Shading general config - * - * @init_set_vrt_offst_ul: set vertical offset, - * y_start >> block_height_log2 % grid_height_per_slice. - * @shd_enable: shading enable. - * @gain_factor: Gain factor. Shift calculated anti shading value. Precision u2. - * 0x0 - gain factor [1, 5], means no shift interpolated value. - * 0x1 - gain factor [1, 9], means shift interpolated by 1. - * 0x2 - gain factor [1, 17], means shift interpolated by 2. - * @reserved: reserved - * - * Correction is performed by multiplying a gain factor for each of the 4 Bayer - * channels as a function of the pixel location in the sensor. - */ -struct ipu3_uapi_shd_general_config { - __u32 init_set_vrt_offst_ul:8; - __u32 shd_enable:1; - __u32 gain_factor:2; - __u32 reserved:21; -} __packed; - -/** - * struct ipu3_uapi_shd_black_level_config - Black level correction - * - * @bl_r: Bios values for green red. s11 range [-2048, 2047]. - * @bl_gr: Bios values for green blue. s11 range [-2048, 2047]. - * @bl_gb: Bios values for red. s11 range [-2048, 2047]. - * @bl_b: Bios values for blue. s11 range [-2048, 2047]. - */ -struct ipu3_uapi_shd_black_level_config { - __s16 bl_r; - __s16 bl_gr; - __s16 bl_gb; - __s16 bl_b; -} __packed; - -/** - * struct ipu3_uapi_shd_config_static - Shading config static - * - * @grid: shading grid config &ipu3_uapi_shd_grid_config - * @general: shading general config &ipu3_uapi_shd_general_config - * @black_level: black level config for shading correction as defined by - * &ipu3_uapi_shd_black_level_config - */ -struct ipu3_uapi_shd_config_static { - struct ipu3_uapi_shd_grid_config grid; - struct ipu3_uapi_shd_general_config general; - struct ipu3_uapi_shd_black_level_config black_level; -} __packed; - -/** - * struct ipu3_uapi_shd_lut - Shading gain factor lookup table. - * - * @sets: array - * @sets.r_and_gr: Red and GreenR Lookup table. - * @sets.r_and_gr.r: Red shading factor. - * @sets.r_and_gr.gr: GreenR shading factor. - * @sets.reserved1: reserved - * @sets.gb_and_b: GreenB and Blue Lookup table. - * @sets.gb_and_b.gb: GreenB shading factor. - * @sets.gb_and_b.b: Blue shading factor. - * @sets.reserved2: reserved - * - * Map to shading correction LUT register set. - */ -struct ipu3_uapi_shd_lut { - struct { - struct { - __u16 r; - __u16 gr; - } r_and_gr[IPU3_UAPI_SHD_MAX_CELLS_PER_SET]; - __u8 reserved1[24]; - struct { - __u16 gb; - __u16 b; - } gb_and_b[IPU3_UAPI_SHD_MAX_CELLS_PER_SET]; - __u8 reserved2[24]; - } sets[IPU3_UAPI_SHD_MAX_CFG_SETS]; -} __packed; - -/** - * struct ipu3_uapi_shd_config - Shading config - * - * @shd: shading static config, see &ipu3_uapi_shd_config_static - * @shd_lut: shading lookup table &ipu3_uapi_shd_lut - */ -struct ipu3_uapi_shd_config { - struct ipu3_uapi_shd_config_static shd __attribute__((aligned(32))); - struct ipu3_uapi_shd_lut shd_lut __attribute__((aligned(32))); -} __packed; - -/* Image Enhancement Filter directed */ - -/** - * struct ipu3_uapi_iefd_cux2 - IEFd Config Unit 2 parameters - * - * @x0: X0 point of Config Unit, u9.0, default 0. - * @x1: X1 point of Config Unit, u9.0, default 0. - * @a01: Slope A of Config Unit, s4.4, default 0. - * @b01: Slope B, always 0. - * - * Calculate weight for blending directed and non-directed denoise elements - * - * Note: - * Each instance of Config Unit needs X coordinate of n points and - * slope A factor between points calculated by driver based on calibration - * parameters. - * - * All CU inputs are unsigned, they will be converted to signed when written - * to register, i.e. a01 will be written to 9 bit register in s4.4 format. - * The data precision s4.4 means 4 bits for integer parts and 4 bits for the - * fractional part, the first bit indicates positive or negative value. - * For userspace software (commonly the imaging library), the computation for - * the CU slope values should be based on the slope resolution 1/16 (binary - * 0.0001 - the minimal interval value), the slope value range is [-256, +255]. - * This applies to &ipu3_uapi_iefd_cux6_ed, &ipu3_uapi_iefd_cux2_1, - * &ipu3_uapi_iefd_cux2_1, &ipu3_uapi_iefd_cux4 and &ipu3_uapi_iefd_cux6_rad. - */ -struct ipu3_uapi_iefd_cux2 { - __u32 x0:9; - __u32 x1:9; - __u32 a01:9; - __u32 b01:5; -} __packed; - -/** - * struct ipu3_uapi_iefd_cux6_ed - Calculate power of non-directed sharpening - * element, Config Unit 6 for edge detail (ED). - * - * @x0: X coordinate of point 0, u9.0, default 0. - * @x1: X coordinate of point 1, u9.0, default 0. - * @x2: X coordinate of point 2, u9.0, default 0. - * @reserved0: reserved - * @x3: X coordinate of point 3, u9.0, default 0. - * @x4: X coordinate of point 4, u9.0, default 0. - * @x5: X coordinate of point 5, u9.0, default 0. - * @reserved1: reserved - * @a01: slope A points 01, s4.4, default 0. - * @a12: slope A points 12, s4.4, default 0. - * @a23: slope A points 23, s4.4, default 0. - * @reserved2: reserved - * @a34: slope A points 34, s4.4, default 0. - * @a45: slope A points 45, s4.4, default 0. - * @reserved3: reserved - * @b01: slope B points 01, s4.4, default 0. - * @b12: slope B points 12, s4.4, default 0. - * @b23: slope B points 23, s4.4, default 0. - * @reserved4: reserved - * @b34: slope B points 34, s4.4, default 0. - * @b45: slope B points 45, s4.4, default 0. - * @reserved5: reserved. - */ -struct ipu3_uapi_iefd_cux6_ed { - __u32 x0:9; - __u32 x1:9; - __u32 x2:9; - __u32 reserved0:5; - - __u32 x3:9; - __u32 x4:9; - __u32 x5:9; - __u32 reserved1:5; - - __u32 a01:9; - __u32 a12:9; - __u32 a23:9; - __u32 reserved2:5; - - __u32 a34:9; - __u32 a45:9; - __u32 reserved3:14; - - __u32 b01:9; - __u32 b12:9; - __u32 b23:9; - __u32 reserved4:5; - - __u32 b34:9; - __u32 b45:9; - __u32 reserved5:14; -} __packed; - -/** - * struct ipu3_uapi_iefd_cux2_1 - Calculate power of non-directed denoise - * element apply. - * @x0: X0 point of Config Unit, u9.0, default 0. - * @x1: X1 point of Config Unit, u9.0, default 0. - * @a01: Slope A of Config Unit, s4.4, default 0. - * @reserved1: reserved - * @b01: offset B0 of Config Unit, u7.0, default 0. - * @reserved2: reserved - */ -struct ipu3_uapi_iefd_cux2_1 { - __u32 x0:9; - __u32 x1:9; - __u32 a01:9; - __u32 reserved1:5; - - __u32 b01:8; - __u32 reserved2:24; -} __packed; - -/** - * struct ipu3_uapi_iefd_cux4 - Calculate power of non-directed sharpening - * element. - * - * @x0: X0 point of Config Unit, u9.0, default 0. - * @x1: X1 point of Config Unit, u9.0, default 0. - * @x2: X2 point of Config Unit, u9.0, default 0. - * @reserved0: reserved - * @x3: X3 point of Config Unit, u9.0, default 0. - * @a01: Slope A0 of Config Unit, s4.4, default 0. - * @a12: Slope A1 of Config Unit, s4.4, default 0. - * @reserved1: reserved - * @a23: Slope A2 of Config Unit, s4.4, default 0. - * @b01: Offset B0 of Config Unit, s7.0, default 0. - * @b12: Offset B1 of Config Unit, s7.0, default 0. - * @reserved2: reserved - * @b23: Offset B2 of Config Unit, s7.0, default 0. - * @reserved3: reserved - */ -struct ipu3_uapi_iefd_cux4 { - __u32 x0:9; - __u32 x1:9; - __u32 x2:9; - __u32 reserved0:5; - - __u32 x3:9; - __u32 a01:9; - __u32 a12:9; - __u32 reserved1:5; - - __u32 a23:9; - __u32 b01:8; - __u32 b12:8; - __u32 reserved2:7; - - __u32 b23:8; - __u32 reserved3:24; -} __packed; - -/** - * struct ipu3_uapi_iefd_cux6_rad - Radial Config Unit (CU) - * - * @x0: x0 points of Config Unit radial, u8.0 - * @x1: x1 points of Config Unit radial, u8.0 - * @x2: x2 points of Config Unit radial, u8.0 - * @x3: x3 points of Config Unit radial, u8.0 - * @x4: x4 points of Config Unit radial, u8.0 - * @x5: x5 points of Config Unit radial, u8.0 - * @reserved1: reserved - * @a01: Slope A of Config Unit radial, s7.8 - * @a12: Slope A of Config Unit radial, s7.8 - * @a23: Slope A of Config Unit radial, s7.8 - * @a34: Slope A of Config Unit radial, s7.8 - * @a45: Slope A of Config Unit radial, s7.8 - * @reserved2: reserved - * @b01: Slope B of Config Unit radial, s9.0 - * @b12: Slope B of Config Unit radial, s9.0 - * @b23: Slope B of Config Unit radial, s9.0 - * @reserved4: reserved - * @b34: Slope B of Config Unit radial, s9.0 - * @b45: Slope B of Config Unit radial, s9.0 - * @reserved5: reserved - */ -struct ipu3_uapi_iefd_cux6_rad { - __u32 x0:8; - __u32 x1:8; - __u32 x2:8; - __u32 x3:8; - - __u32 x4:8; - __u32 x5:8; - __u32 reserved1:16; - - __u32 a01:16; - __u32 a12:16; - - __u32 a23:16; - __u32 a34:16; - - __u32 a45:16; - __u32 reserved2:16; - - __u32 b01:10; - __u32 b12:10; - __u32 b23:10; - __u32 reserved4:2; - - __u32 b34:10; - __u32 b45:10; - __u32 reserved5:12; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_iefd_cfg_units - IEFd Config Units parameters - * - * @cu_1: calculate weight for blending directed and - * non-directed denoise elements. See &ipu3_uapi_iefd_cux2 - * @cu_ed: calculate power of non-directed sharpening element, see - * &ipu3_uapi_iefd_cux6_ed - * @cu_3: calculate weight for blending directed and - * non-directed denoise elements. A &ipu3_uapi_iefd_cux2 - * @cu_5: calculate power of non-directed denoise element apply, use - * &ipu3_uapi_iefd_cux2_1 - * @cu_6: calculate power of non-directed sharpening element. See - * &ipu3_uapi_iefd_cux4 - * @cu_7: calculate weight for blending directed and - * non-directed denoise elements. Use &ipu3_uapi_iefd_cux2 - * @cu_unsharp: Config Unit of unsharp &ipu3_uapi_iefd_cux4 - * @cu_radial: Config Unit of radial &ipu3_uapi_iefd_cux6_rad - * @cu_vssnlm: Config Unit of vssnlm &ipu3_uapi_iefd_cux2 - */ -struct ipu3_uapi_yuvp1_iefd_cfg_units { - struct ipu3_uapi_iefd_cux2 cu_1; - struct ipu3_uapi_iefd_cux6_ed cu_ed; - struct ipu3_uapi_iefd_cux2 cu_3; - struct ipu3_uapi_iefd_cux2_1 cu_5; - struct ipu3_uapi_iefd_cux4 cu_6; - struct ipu3_uapi_iefd_cux2 cu_7; - struct ipu3_uapi_iefd_cux4 cu_unsharp; - struct ipu3_uapi_iefd_cux6_rad cu_radial; - struct ipu3_uapi_iefd_cux2 cu_vssnlm; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_iefd_config_s - IEFd config - * - * @horver_diag_coeff: Gradient compensation. Compared with vertical / - * horizontal (0 / 90 degree), coefficient of diagonal (45 / - * 135 degree) direction should be corrected by approx. - * 1/sqrt(2). - * @reserved0: reserved - * @clamp_stitch: Slope to stitch between clamped and unclamped edge values - * @reserved1: reserved - * @direct_metric_update: Update coeff for direction metric - * @reserved2: reserved - * @ed_horver_diag_coeff: Radial Coefficient that compensates for - * different distance for vertical/horizontal and - * diagonal gradient calculation (approx. 1/sqrt(2)) - * @reserved3: reserved - */ -struct ipu3_uapi_yuvp1_iefd_config_s { - __u32 horver_diag_coeff:7; - __u32 reserved0:1; - __u32 clamp_stitch:6; - __u32 reserved1:2; - __u32 direct_metric_update:5; - __u32 reserved2:3; - __u32 ed_horver_diag_coeff:7; - __u32 reserved3:1; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_iefd_control - IEFd control - * - * @iefd_en: Enable IEFd - * @denoise_en: Enable denoise - * @direct_smooth_en: Enable directional smooth - * @rad_en: Enable radial update - * @vssnlm_en: Enable VSSNLM output filter - * @reserved: reserved - */ -struct ipu3_uapi_yuvp1_iefd_control { - __u32 iefd_en:1; - __u32 denoise_en:1; - __u32 direct_smooth_en:1; - __u32 rad_en:1; - __u32 vssnlm_en:1; - __u32 reserved:27; -} __packed; - -/** - * struct ipu3_uapi_sharp_cfg - Sharpening config - * - * @nega_lmt_txt: Sharpening limit for negative overshoots for texture. - * @reserved0: reserved - * @posi_lmt_txt: Sharpening limit for positive overshoots for texture. - * @reserved1: reserved - * @nega_lmt_dir: Sharpening limit for negative overshoots for direction (edge). - * @reserved2: reserved - * @posi_lmt_dir: Sharpening limit for positive overshoots for direction (edge). - * @reserved3: reserved - * - * Fixed point type u13.0, range [0, 8191]. - */ -struct ipu3_uapi_sharp_cfg { - __u32 nega_lmt_txt:13; - __u32 reserved0:19; - __u32 posi_lmt_txt:13; - __u32 reserved1:19; - __u32 nega_lmt_dir:13; - __u32 reserved2:19; - __u32 posi_lmt_dir:13; - __u32 reserved3:19; -} __packed; - -/** - * struct ipu3_uapi_far_w - Sharpening config for far sub-group - * - * @dir_shrp: Weight of wide direct sharpening, u1.6, range [0, 64], default 64. - * @reserved0: reserved - * @dir_dns: Weight of wide direct denoising, u1.6, range [0, 64], default 0. - * @reserved1: reserved - * @ndir_dns_powr: Power of non-direct denoising, - * Precision u1.6, range [0, 64], default 64. - * @reserved2: reserved - */ -struct ipu3_uapi_far_w { - __u32 dir_shrp:7; - __u32 reserved0:1; - __u32 dir_dns:7; - __u32 reserved1:1; - __u32 ndir_dns_powr:7; - __u32 reserved2:9; -} __packed; - -/** - * struct ipu3_uapi_unsharp_cfg - Unsharp config - * - * @unsharp_weight: Unsharp mask blending weight. - * u1.6, range [0, 64], default 16. - * 0 - disabled, 64 - use only unsharp. - * @reserved0: reserved - * @unsharp_amount: Unsharp mask amount, u4.5, range [0, 511], default 0. - * @reserved1: reserved - */ -struct ipu3_uapi_unsharp_cfg { - __u32 unsharp_weight:7; - __u32 reserved0:1; - __u32 unsharp_amount:9; - __u32 reserved1:15; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_iefd_shrp_cfg - IEFd sharpness config - * - * @cfg: sharpness config &ipu3_uapi_sharp_cfg - * @far_w: wide range config, value as specified by &ipu3_uapi_far_w: - * The 5x5 environment is separated into 2 sub-groups, the 3x3 nearest - * neighbors (8 pixels called Near), and the second order neighborhood - * around them (16 pixels called Far). - * @unshrp_cfg: unsharpness config. &ipu3_uapi_unsharp_cfg - */ -struct ipu3_uapi_yuvp1_iefd_shrp_cfg { - struct ipu3_uapi_sharp_cfg cfg; - struct ipu3_uapi_far_w far_w; - struct ipu3_uapi_unsharp_cfg unshrp_cfg; -} __packed; - -/** - * struct ipu3_uapi_unsharp_coef0 - Unsharp mask coefficients - * - * @c00: Coeff11, s0.8, range [-255, 255], default 1. - * @c01: Coeff12, s0.8, range [-255, 255], default 5. - * @c02: Coeff13, s0.8, range [-255, 255], default 9. - * @reserved: reserved - * - * Configurable registers for common sharpening support. - */ -struct ipu3_uapi_unsharp_coef0 { - __u32 c00:9; - __u32 c01:9; - __u32 c02:9; - __u32 reserved:5; -} __packed; - -/** - * struct ipu3_uapi_unsharp_coef1 - Unsharp mask coefficients - * - * @c11: Coeff22, s0.8, range [-255, 255], default 29. - * @c12: Coeff23, s0.8, range [-255, 255], default 55. - * @c22: Coeff33, s0.8, range [-255, 255], default 96. - * @reserved: reserved - */ -struct ipu3_uapi_unsharp_coef1 { - __u32 c11:9; - __u32 c12:9; - __u32 c22:9; - __u32 reserved:5; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_iefd_unshrp_cfg - Unsharp mask config - * - * @unsharp_coef0: unsharp coefficient 0 config. See &ipu3_uapi_unsharp_coef0 - * @unsharp_coef1: unsharp coefficient 1 config. See &ipu3_uapi_unsharp_coef1 - */ -struct ipu3_uapi_yuvp1_iefd_unshrp_cfg { - struct ipu3_uapi_unsharp_coef0 unsharp_coef0; - struct ipu3_uapi_unsharp_coef1 unsharp_coef1; -} __packed; - -/** - * struct ipu3_uapi_radial_reset_xy - Radial coordinate reset - * - * @x: Radial reset of x coordinate. Precision s12, [-4095, 4095], default 0. - * @reserved0: reserved - * @y: Radial center y coordinate. Precision s12, [-4095, 4095], default 0. - * @reserved1: reserved - */ -struct ipu3_uapi_radial_reset_xy { - __s32 x:13; - __u32 reserved0:3; - __s32 y:13; - __u32 reserved1:3; -} __packed; - -/** - * struct ipu3_uapi_radial_reset_x2 - Radial X^2 reset - * - * @x2: Radial reset of x^2 coordinate. Precision u24, default 0. - * @reserved: reserved - */ -struct ipu3_uapi_radial_reset_x2 { - __u32 x2:24; - __u32 reserved:8; -} __packed; - -/** - * struct ipu3_uapi_radial_reset_y2 - Radial Y^2 reset - * - * @y2: Radial reset of y^2 coordinate. Precision u24, default 0. - * @reserved: reserved - */ -struct ipu3_uapi_radial_reset_y2 { - __u32 y2:24; - __u32 reserved:8; -} __packed; - -/** - * struct ipu3_uapi_radial_cfg - Radial config - * - * @rad_nf: Radial. R^2 normalization factor is scale down by 2^ - (15 + scale) - * @reserved0: reserved - * @rad_inv_r2: Radial R^-2 normelized to (0.5..1). - * Precision u7, range [0, 127]. - * @reserved1: reserved - */ -struct ipu3_uapi_radial_cfg { - __u32 rad_nf:4; - __u32 reserved0:4; - __u32 rad_inv_r2:7; - __u32 reserved1:17; -} __packed; - -/** - * struct ipu3_uapi_rad_far_w - Radial FAR sub-group - * - * @rad_dir_far_sharp_w: Weight of wide direct sharpening, u1.6, range [0, 64], - * default 64. - * @rad_dir_far_dns_w: Weight of wide direct denoising, u1.6, range [0, 64], - * default 0. - * @rad_ndir_far_dns_power: power of non-direct sharpening, u1.6, range [0, 64], - * default 0. - * @reserved: reserved - */ -struct ipu3_uapi_rad_far_w { - __u32 rad_dir_far_sharp_w:8; - __u32 rad_dir_far_dns_w:8; - __u32 rad_ndir_far_dns_power:8; - __u32 reserved:8; -} __packed; - -/** - * struct ipu3_uapi_cu_cfg0 - Radius Config Unit cfg0 register - * - * @cu6_pow: Power of CU6. Power of non-direct sharpening, u3.4. - * @reserved0: reserved - * @cu_unsharp_pow: Power of unsharp mask, u2.4. - * @reserved1: reserved - * @rad_cu6_pow: Radial/corner CU6. Directed sharpening power, u3.4. - * @reserved2: reserved - * @rad_cu_unsharp_pow: Radial power of unsharp mask, u2.4. - * @reserved3: reserved - */ -struct ipu3_uapi_cu_cfg0 { - __u32 cu6_pow:7; - __u32 reserved0:1; - __u32 cu_unsharp_pow:7; - __u32 reserved1:1; - __u32 rad_cu6_pow:7; - __u32 reserved2:1; - __u32 rad_cu_unsharp_pow:6; - __u32 reserved3:2; -} __packed; - -/** - * struct ipu3_uapi_cu_cfg1 - Radius Config Unit cfg1 register - * - * @rad_cu6_x1: X1 point of Config Unit 6, precision u9.0. - * @reserved0: reserved - * @rad_cu_unsharp_x1: X1 point for Config Unit unsharp for radial/corner point - * precision u9.0. - * @reserved1: reserved - */ -struct ipu3_uapi_cu_cfg1 { - __u32 rad_cu6_x1:9; - __u32 reserved0:1; - __u32 rad_cu_unsharp_x1:9; - __u32 reserved1:13; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_iefd_rad_cfg - IEFd parameters changed radially over - * the picture plane. - * - * @reset_xy: reset xy value in radial calculation. &ipu3_uapi_radial_reset_xy - * @reset_x2: reset x square value in radial calculation. See struct - * &ipu3_uapi_radial_reset_x2 - * @reset_y2: reset y square value in radial calculation. See struct - * &ipu3_uapi_radial_reset_y2 - * @cfg: radial config defined in &ipu3_uapi_radial_cfg - * @rad_far_w: weight for wide range radial. &ipu3_uapi_rad_far_w - * @cu_cfg0: configuration unit 0. See &ipu3_uapi_cu_cfg0 - * @cu_cfg1: configuration unit 1. See &ipu3_uapi_cu_cfg1 - */ -struct ipu3_uapi_yuvp1_iefd_rad_cfg { - struct ipu3_uapi_radial_reset_xy reset_xy; - struct ipu3_uapi_radial_reset_x2 reset_x2; - struct ipu3_uapi_radial_reset_y2 reset_y2; - struct ipu3_uapi_radial_cfg cfg; - struct ipu3_uapi_rad_far_w rad_far_w; - struct ipu3_uapi_cu_cfg0 cu_cfg0; - struct ipu3_uapi_cu_cfg1 cu_cfg1; -} __packed; - -/* Vssnlm - Very small scale non-local mean algorithm */ - -/** - * struct ipu3_uapi_vss_lut_x - Vssnlm LUT x0/x1/x2 - * - * @vs_x0: Vssnlm LUT x0, precision u8, range [0, 255], default 16. - * @vs_x1: Vssnlm LUT x1, precision u8, range [0, 255], default 32. - * @vs_x2: Vssnlm LUT x2, precision u8, range [0, 255], default 64. - * @reserved2: reserved - */ -struct ipu3_uapi_vss_lut_x { - __u32 vs_x0:8; - __u32 vs_x1:8; - __u32 vs_x2:8; - __u32 reserved2:8; -} __packed; - -/** - * struct ipu3_uapi_vss_lut_y - Vssnlm LUT y0/y1/y2 - * - * @vs_y1: Vssnlm LUT y1, precision u4, range [0, 8], default 1. - * @reserved0: reserved - * @vs_y2: Vssnlm LUT y2, precision u4, range [0, 8], default 3. - * @reserved1: reserved - * @vs_y3: Vssnlm LUT y3, precision u4, range [0, 8], default 8. - * @reserved2: reserved - */ -struct ipu3_uapi_vss_lut_y { - __u32 vs_y1:4; - __u32 reserved0:4; - __u32 vs_y2:4; - __u32 reserved1:4; - __u32 vs_y3:4; - __u32 reserved2:12; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_iefd_vssnlm_cfg - IEFd Vssnlm Lookup table - * - * @vss_lut_x: vss lookup table. See &ipu3_uapi_vss_lut_x description - * @vss_lut_y: vss lookup table. See &ipu3_uapi_vss_lut_y description - */ -struct ipu3_uapi_yuvp1_iefd_vssnlm_cfg { - struct ipu3_uapi_vss_lut_x vss_lut_x; - struct ipu3_uapi_vss_lut_y vss_lut_y; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_iefd_config - IEFd config - * - * @units: configuration unit setting, &ipu3_uapi_yuvp1_iefd_cfg_units - * @config: configuration, as defined by &ipu3_uapi_yuvp1_iefd_config_s - * @control: control setting, as defined by &ipu3_uapi_yuvp1_iefd_control - * @sharp: sharpness setting, as defined by &ipu3_uapi_yuvp1_iefd_shrp_cfg - * @unsharp: unsharpness setting, as defined by &ipu3_uapi_yuvp1_iefd_unshrp_cfg - * @rad: radial setting, as defined by &ipu3_uapi_yuvp1_iefd_rad_cfg - * @vsslnm: vsslnm setting, as defined by &ipu3_uapi_yuvp1_iefd_vssnlm_cfg - */ -struct ipu3_uapi_yuvp1_iefd_config { - struct ipu3_uapi_yuvp1_iefd_cfg_units units; - struct ipu3_uapi_yuvp1_iefd_config_s config; - struct ipu3_uapi_yuvp1_iefd_control control; - struct ipu3_uapi_yuvp1_iefd_shrp_cfg sharp; - struct ipu3_uapi_yuvp1_iefd_unshrp_cfg unsharp; - struct ipu3_uapi_yuvp1_iefd_rad_cfg rad; - struct ipu3_uapi_yuvp1_iefd_vssnlm_cfg vsslnm; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_yds_config - Y Down-Sampling config - * - * @c00: range [0, 3], default 0x0 - * @c01: range [0, 3], default 0x1 - * @c02: range [0, 3], default 0x1 - * @c03: range [0, 3], default 0x0 - * @c10: range [0, 3], default 0x0 - * @c11: range [0, 3], default 0x1 - * @c12: range [0, 3], default 0x1 - * @c13: range [0, 3], default 0x0 - * - * Above are 4x2 filter coefficients for chroma output downscaling. - * - * @norm_factor: Normalization factor, range [0, 4], default 2 - * 0 - divide by 1 - * 1 - divide by 2 - * 2 - divide by 4 - * 3 - divide by 8 - * 4 - divide by 16 - * @reserved0: reserved - * @bin_output: Down sampling on Luma channel in two optional modes - * 0 - Bin output 4.2.0 (default), 1 output 4.2.2. - * @reserved1: reserved - */ -struct ipu3_uapi_yuvp1_yds_config { - __u32 c00:2; - __u32 c01:2; - __u32 c02:2; - __u32 c03:2; - __u32 c10:2; - __u32 c11:2; - __u32 c12:2; - __u32 c13:2; - __u32 norm_factor:5; - __u32 reserved0:4; - __u32 bin_output:1; - __u32 reserved1:6; -} __packed; - -/* Chroma Noise Reduction */ - -/** - * struct ipu3_uapi_yuvp1_chnr_enable_config - Chroma noise reduction enable - * - * @enable: enable/disable chroma noise reduction - * @yuv_mode: 0 - YUV420, 1 - YUV422 - * @reserved0: reserved - * @col_size: number of columns in the frame, max width is 2560 - * @reserved1: reserved - */ -struct ipu3_uapi_yuvp1_chnr_enable_config { - __u32 enable:1; - __u32 yuv_mode:1; - __u32 reserved0:14; - __u32 col_size:12; - __u32 reserved1:4; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_chnr_coring_config - Coring thresholds for UV - * - * @u: U coring level, u0.13, range [0.0, 1.0], default 0.0 - * @reserved0: reserved - * @v: V coring level, u0.13, range [0.0, 1.0], default 0.0 - * @reserved1: reserved - */ -struct ipu3_uapi_yuvp1_chnr_coring_config { - __u32 u:13; - __u32 reserved0:3; - __u32 v:13; - __u32 reserved1:3; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_chnr_sense_gain_config - Chroma noise reduction gains - * - * All sensitivity gain parameters have precision u13.0, range [0, 8191]. - * - * @vy: Sensitivity of horizontal edge of Y, default 100 - * @vu: Sensitivity of horizontal edge of U, default 100 - * @vv: Sensitivity of horizontal edge of V, default 100 - * @reserved0: reserved - * @hy: Sensitivity of vertical edge of Y, default 50 - * @hu: Sensitivity of vertical edge of U, default 50 - * @hv: Sensitivity of vertical edge of V, default 50 - * @reserved1: reserved - */ -struct ipu3_uapi_yuvp1_chnr_sense_gain_config { - __u32 vy:8; - __u32 vu:8; - __u32 vv:8; - __u32 reserved0:8; - - __u32 hy:8; - __u32 hu:8; - __u32 hv:8; - __u32 reserved1:8; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_chnr_iir_fir_config - Chroma IIR/FIR filter config - * - * @fir_0h: Value of center tap in horizontal FIR, range [0, 32], default 8. - * @reserved0: reserved - * @fir_1h: Value of distance 1 in horizontal FIR, range [0, 32], default 12. - * @reserved1: reserved - * @fir_2h: Value of distance 2 tap in horizontal FIR, range [0, 32], default 0. - * @dalpha_clip_val: weight for previous row in IIR, range [1, 256], default 0. - * @reserved2: reserved - */ -struct ipu3_uapi_yuvp1_chnr_iir_fir_config { - __u32 fir_0h:6; - __u32 reserved0:2; - __u32 fir_1h:6; - __u32 reserved1:2; - __u32 fir_2h:6; - __u32 dalpha_clip_val:9; - __u32 reserved2:1; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_chnr_config - Chroma noise reduction config - * - * @enable: chroma noise reduction enable, see - * &ipu3_uapi_yuvp1_chnr_enable_config - * @coring: coring config for chroma noise reduction, see - * &ipu3_uapi_yuvp1_chnr_coring_config - * @sense_gain: sensitivity config for chroma noise reduction, see - * ipu3_uapi_yuvp1_chnr_sense_gain_config - * @iir_fir: iir and fir config for chroma noise reduction, see - * ipu3_uapi_yuvp1_chnr_iir_fir_config - */ -struct ipu3_uapi_yuvp1_chnr_config { - struct ipu3_uapi_yuvp1_chnr_enable_config enable; - struct ipu3_uapi_yuvp1_chnr_coring_config coring; - struct ipu3_uapi_yuvp1_chnr_sense_gain_config sense_gain; - struct ipu3_uapi_yuvp1_chnr_iir_fir_config iir_fir; -} __packed; - -/* Edge Enhancement and Noise Reduction */ - -/** - * struct ipu3_uapi_yuvp1_y_ee_nr_lpf_config - Luma(Y) edge enhancement low-pass - * filter coefficients - * - * @a_diag: Smoothing diagonal coefficient, u5.0. - * @reserved0: reserved - * @a_periph: Image smoothing perpherial, u5.0. - * @reserved1: reserved - * @a_cent: Image Smoothing center coefficient, u5.0. - * @reserved2: reserved - * @enable: 0: Y_EE_NR disabled, output = input; 1: Y_EE_NR enabled. - */ -struct ipu3_uapi_yuvp1_y_ee_nr_lpf_config { - __u32 a_diag:5; - __u32 reserved0:3; - __u32 a_periph:5; - __u32 reserved1:3; - __u32 a_cent:5; - __u32 reserved2:9; - __u32 enable:1; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_y_ee_nr_sense_config - Luma(Y) edge enhancement - * noise reduction sensitivity gains - * - * @edge_sense_0: Sensitivity of edge in dark area. u13.0, default 8191. - * @reserved0: reserved - * @delta_edge_sense: Difference in the sensitivity of edges between - * the bright and dark areas. u13.0, default 0. - * @reserved1: reserved - * @corner_sense_0: Sensitivity of corner in dark area. u13.0, default 0. - * @reserved2: reserved - * @delta_corner_sense: Difference in the sensitivity of corners between - * the bright and dark areas. u13.0, default 8191. - * @reserved3: reserved - */ -struct ipu3_uapi_yuvp1_y_ee_nr_sense_config { - __u32 edge_sense_0:13; - __u32 reserved0:3; - __u32 delta_edge_sense:13; - __u32 reserved1:3; - __u32 corner_sense_0:13; - __u32 reserved2:3; - __u32 delta_corner_sense:13; - __u32 reserved3:3; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_y_ee_nr_gain_config - Luma(Y) edge enhancement - * noise reduction gain config - * - * @gain_pos_0: Gain for positive edge in dark area. u5.0, [0, 16], default 2. - * @reserved0: reserved - * @delta_gain_posi: Difference in the gain of edges between the bright and - * dark areas for positive edges. u5.0, [0, 16], default 0. - * @reserved1: reserved - * @gain_neg_0: Gain for negative edge in dark area. u5.0, [0, 16], default 8. - * @reserved2: reserved - * @delta_gain_neg: Difference in the gain of edges between the bright and - * dark areas for negative edges. u5.0, [0, 16], default 0. - * @reserved3: reserved - */ -struct ipu3_uapi_yuvp1_y_ee_nr_gain_config { - __u32 gain_pos_0:5; - __u32 reserved0:3; - __u32 delta_gain_posi:5; - __u32 reserved1:3; - __u32 gain_neg_0:5; - __u32 reserved2:3; - __u32 delta_gain_neg:5; - __u32 reserved3:3; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_y_ee_nr_clip_config - Luma(Y) edge enhancement - * noise reduction clipping config - * - * @clip_pos_0: Limit of positive edge in dark area - * u5, value [0, 16], default 8. - * @reserved0: reserved - * @delta_clip_posi: Difference in the limit of edges between the bright - * and dark areas for positive edges. - * u5, value [0, 16], default 8. - * @reserved1: reserved - * @clip_neg_0: Limit of negative edge in dark area - * u5, value [0, 16], default 8. - * @reserved2: reserved - * @delta_clip_neg: Difference in the limit of edges between the bright - * and dark areas for negative edges. - * u5, value [0, 16], default 8. - * @reserved3: reserved - */ -struct ipu3_uapi_yuvp1_y_ee_nr_clip_config { - __u32 clip_pos_0:5; - __u32 reserved0:3; - __u32 delta_clip_posi:5; - __u32 reserved1:3; - __u32 clip_neg_0:5; - __u32 reserved2:3; - __u32 delta_clip_neg:5; - __u32 reserved3:3; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_y_ee_nr_frng_config - Luma(Y) edge enhancement - * noise reduction fringe config - * - * @gain_exp: Common exponent of gains, u4, [0, 8], default 2. - * @reserved0: reserved - * @min_edge: Threshold for edge and smooth stitching, u13. - * @reserved1: reserved - * @lin_seg_param: Power of LinSeg, u4. - * @reserved2: reserved - * @t1: Parameter for enabling/disabling the edge enhancement, u1.0, [0, 1], - * default 1. - * @t2: Parameter for enabling/disabling the smoothing, u1.0, [0, 1], - * default 1. - * @reserved3: reserved - */ -struct ipu3_uapi_yuvp1_y_ee_nr_frng_config { - __u32 gain_exp:4; - __u32 reserved0:28; - __u32 min_edge:13; - __u32 reserved1:3; - __u32 lin_seg_param:4; - __u32 reserved2:4; - __u32 t1:1; - __u32 t2:1; - __u32 reserved3:6; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_y_ee_nr_diag_config - Luma(Y) edge enhancement - * noise reduction diagonal config - * - * @diag_disc_g: Coefficient that prioritize diagonal edge direction on - * horizontal or vertical for final enhancement. - * u4.0, [1, 15], default 1. - * @reserved0: reserved - * @hvw_hor: Weight of horizontal/vertical edge enhancement for hv edge. - * u2.2, [1, 15], default 4. - * @dw_hor: Weight of diagonal edge enhancement for hv edge. - * u2.2, [1, 15], default 1. - * @hvw_diag: Weight of horizontal/vertical edge enhancement for diagonal edge. - * u2.2, [1, 15], default 1. - * @dw_diag: Weight of diagonal edge enhancement for diagonal edge. - * u2.2, [1, 15], default 4. - * @reserved1: reserved - */ -struct ipu3_uapi_yuvp1_y_ee_nr_diag_config { - __u32 diag_disc_g:4; - __u32 reserved0:4; - __u32 hvw_hor:4; - __u32 dw_hor:4; - __u32 hvw_diag:4; - __u32 dw_diag:4; - __u32 reserved1:8; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config - Luma(Y) edge enhancement - * noise reduction false color correction (FCC) coring config - * - * @pos_0: Gain for positive edge in dark, u13.0, [0, 16], default 0. - * @reserved0: reserved - * @pos_delta: Gain for positive edge in bright, value: pos_0 + pos_delta <=16 - * u13.0, default 0. - * @reserved1: reserved - * @neg_0: Gain for negative edge in dark area, u13.0, range [0, 16], default 0. - * @reserved2: reserved - * @neg_delta: Gain for negative edge in bright area. neg_0 + neg_delta <=16 - * u13.0, default 0. - * @reserved3: reserved - * - * Coring is a simple soft thresholding technique. - */ -struct ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config { - __u32 pos_0:13; - __u32 reserved0:3; - __u32 pos_delta:13; - __u32 reserved1:3; - __u32 neg_0:13; - __u32 reserved2:3; - __u32 neg_delta:13; - __u32 reserved3:3; -} __packed; - -/** - * struct ipu3_uapi_yuvp1_y_ee_nr_config - Edge enhancement and noise reduction - * - * @lpf: low-pass filter config. See &ipu3_uapi_yuvp1_y_ee_nr_lpf_config - * @sense: sensitivity config. See &ipu3_uapi_yuvp1_y_ee_nr_sense_config - * @gain: gain config as defined in &ipu3_uapi_yuvp1_y_ee_nr_gain_config - * @clip: clip config as defined in &ipu3_uapi_yuvp1_y_ee_nr_clip_config - * @frng: fringe config as defined in &ipu3_uapi_yuvp1_y_ee_nr_frng_config - * @diag: diagonal edge config. See &ipu3_uapi_yuvp1_y_ee_nr_diag_config - * @fc_coring: coring config for fringe control. See - * &ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config - */ -struct ipu3_uapi_yuvp1_y_ee_nr_config { - struct ipu3_uapi_yuvp1_y_ee_nr_lpf_config lpf; - struct ipu3_uapi_yuvp1_y_ee_nr_sense_config sense; - struct ipu3_uapi_yuvp1_y_ee_nr_gain_config gain; - struct ipu3_uapi_yuvp1_y_ee_nr_clip_config clip; - struct ipu3_uapi_yuvp1_y_ee_nr_frng_config frng; - struct ipu3_uapi_yuvp1_y_ee_nr_diag_config diag; - struct ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config fc_coring; -} __packed; - -/* Total Color Correction */ - -/** - * struct ipu3_uapi_yuvp2_tcc_gen_control_static_config - Total color correction - * general control config - * - * @en: 0 - TCC disabled. Output = input 1 - TCC enabled. - * @blend_shift: blend shift, Range[3, 4], default NA. - * @gain_according_to_y_only: 0: Gain is calculated according to YUV, - * 1: Gain is calculated according to Y only - * @reserved0: reserved - * @gamma: Final blending coefficients. Values[-16, 16], default NA. - * @reserved1: reserved - * @delta: Final blending coefficients. Values[-16, 16], default NA. - * @reserved2: reserved - */ -struct ipu3_uapi_yuvp2_tcc_gen_control_static_config { - __u32 en:1; - __u32 blend_shift:3; - __u32 gain_according_to_y_only:1; - __u32 reserved0:11; - __s32 gamma:5; - __u32 reserved1:3; - __s32 delta:5; - __u32 reserved2:3; -} __packed; - -/** - * struct ipu3_uapi_yuvp2_tcc_macc_elem_static_config - Total color correction - * multi-axis color control (MACC) config - * - * @a: a coefficient for 2x2 MACC conversion matrix. - * @reserved0: reserved - * @b: b coefficient 2x2 MACC conversion matrix. - * @reserved1: reserved - * @c: c coefficient for 2x2 MACC conversion matrix. - * @reserved2: reserved - * @d: d coefficient for 2x2 MACC conversion matrix. - * @reserved3: reserved - */ -struct ipu3_uapi_yuvp2_tcc_macc_elem_static_config { - __s32 a:12; - __u32 reserved0:4; - __s32 b:12; - __u32 reserved1:4; - __s32 c:12; - __u32 reserved2:4; - __s32 d:12; - __u32 reserved3:4; -} __packed; - -/** - * struct ipu3_uapi_yuvp2_tcc_macc_table_static_config - Total color correction - * multi-axis color control (MACC) table array - * - * @entries: config for multi axis color correction, as specified by - * &ipu3_uapi_yuvp2_tcc_macc_elem_static_config - */ -struct ipu3_uapi_yuvp2_tcc_macc_table_static_config { - struct ipu3_uapi_yuvp2_tcc_macc_elem_static_config - entries[IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS]; -} __packed; - -/** - * struct ipu3_uapi_yuvp2_tcc_inv_y_lut_static_config - Total color correction - * inverse y lookup table - * - * @entries: lookup table for inverse y estimation, and use it to estimate the - * ratio between luma and chroma. Chroma by approximate the absolute - * value of the radius on the chroma plane (R = sqrt(u^2+v^2) ) and - * luma by approximate by 1/Y. - */ -struct ipu3_uapi_yuvp2_tcc_inv_y_lut_static_config { - __u16 entries[IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS]; -} __packed; - -/** - * struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config - Total color - * correction lookup table for PCWL - * - * @entries: lookup table for gain piece wise linear transformation (PCWL) - */ -struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config { - __u16 entries[IPU3_UAPI_YUVP2_TCC_GAIN_PCWL_LUT_ELEMENTS]; -} __packed; - -/** - * struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config - Total color correction - * lookup table for r square root - * - * @entries: lookup table for r square root estimation - */ -struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config { - __s16 entries[IPU3_UAPI_YUVP2_TCC_R_SQR_LUT_ELEMENTS]; -} __packed; - -/** - * struct ipu3_uapi_yuvp2_tcc_static_config- Total color correction static - * - * @gen_control: general config for Total Color Correction - * @macc_table: config for multi axis color correction - * @inv_y_lut: lookup table for inverse y estimation - * @gain_pcwl: lookup table for gain PCWL - * @r_sqr_lut: lookup table for r square root estimation. - */ -struct ipu3_uapi_yuvp2_tcc_static_config { - struct ipu3_uapi_yuvp2_tcc_gen_control_static_config gen_control; - struct ipu3_uapi_yuvp2_tcc_macc_table_static_config macc_table; - struct ipu3_uapi_yuvp2_tcc_inv_y_lut_static_config inv_y_lut; - struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config gain_pcwl; - struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config r_sqr_lut; -} __packed; - -/* Advanced Noise Reduction related structs */ - -/* - * struct ipu3_uapi_anr_alpha - Advanced noise reduction alpha - * - * Tunable parameters that are subject to modification according to the - * total gain used. - */ -struct ipu3_uapi_anr_alpha { - __u16 gr; - __u16 r; - __u16 b; - __u16 gb; - __u16 dc_gr; - __u16 dc_r; - __u16 dc_b; - __u16 dc_gb; -} __packed; - -/* - * struct ipu3_uapi_anr_beta - Advanced noise reduction beta - * - * Tunable parameters that are subject to modification according to the - * total gain used. - */ -struct ipu3_uapi_anr_beta { - __u16 beta_gr; - __u16 beta_r; - __u16 beta_b; - __u16 beta_gb; -} __packed; - -/* - * struct ipu3_uapi_anr_plane_color - Advanced noise reduction per plane R, Gr, - * Gb and B register settings - * - * Tunable parameters that are subject to modification according to the - * total gain used. - */ -struct ipu3_uapi_anr_plane_color { - __u16 reg_w_gr[16]; - __u16 reg_w_r[16]; - __u16 reg_w_b[16]; - __u16 reg_w_gb[16]; -} __packed; - -/** - * struct ipu3_uapi_anr_transform_config - Advanced noise reduction transform - * - * @enable: advanced noise reduction enabled. - * @adaptive_treshhold_en: On IPU3, adaptive threshold is always enabled. - * @reserved1: reserved - * @reserved2: reserved - * @alpha: using following defaults: - * 13, 13, 13, 13, 0, 0, 0, 0 - * 11, 11, 11, 11, 0, 0, 0, 0 - * 14, 14, 14, 14, 0, 0, 0, 0 - * @beta: use following defaults: - * 24, 24, 24, 24 - * 21, 20, 20, 21 - * 25, 25, 25, 25 - * @color: use defaults defined in driver/media/pci/intel/ipu3-tables.c - * @sqrt_lut: 11 bits per element, values = - * [724 768 810 849 887 - * 923 958 991 1024 1056 - * 1116 1145 1173 1201 1086 - * 1228 1254 1280 1305 1330 - * 1355 1379 1402 1425 1448] - * @xreset: Reset value of X for r^2 calculation Value: col_start-X_center - * Constraint: Xreset + FrameWdith=4095 Xreset= -4095, default -1632. - * @reserved3: reserved - * @yreset: Reset value of Y for r^2 calculation Value: row_start-Y_center - * Constraint: Yreset + FrameHeight=4095 Yreset= -4095, default -1224. - * @reserved4: reserved - * @x_sqr_reset: Reset value of X^2 for r^2 calculation Value = (Xreset)^2 - * @r_normfactor: Normalization factor for R. Default 14. - * @reserved5: reserved - * @y_sqr_reset: Reset value of Y^2 for r^2 calculation Value = (Yreset)^2 - * @gain_scale: Parameter describing shading gain as a function of distance - * from the image center. - * A single value per frame, loaded by the driver. Default 115. - */ -struct ipu3_uapi_anr_transform_config { - __u32 enable:1; /* 0 or 1, disabled or enabled */ - __u32 adaptive_treshhold_en:1; /* On IPU3, always enabled */ - - __u32 reserved1:30; - __u8 reserved2[44]; - - struct ipu3_uapi_anr_alpha alpha[3]; - struct ipu3_uapi_anr_beta beta[3]; - struct ipu3_uapi_anr_plane_color color[3]; - - __u16 sqrt_lut[IPU3_UAPI_ANR_LUT_SIZE]; /* 11 bits per element */ - - __s16 xreset:13; - __u16 reserved3:3; - __s16 yreset:13; - __u16 reserved4:3; - - __u32 x_sqr_reset:24; - __u32 r_normfactor:5; - __u32 reserved5:3; - - __u32 y_sqr_reset:24; - __u32 gain_scale:8; -} __packed; - -/** - * struct ipu3_uapi_anr_stitch_pyramid - ANR stitch pyramid - * - * @entry0: pyramid LUT entry0, range [0x0, 0x3f] - * @entry1: pyramid LUT entry1, range [0x0, 0x3f] - * @entry2: pyramid LUT entry2, range [0x0, 0x3f] - * @reserved: reserved - */ -struct ipu3_uapi_anr_stitch_pyramid { - __u32 entry0:6; - __u32 entry1:6; - __u32 entry2:6; - __u32 reserved:14; -} __packed; - -/** - * struct ipu3_uapi_anr_stitch_config - ANR stitch config - * - * @anr_stitch_en: enable stitch. Enabled with 1. - * @reserved: reserved - * @pyramid: pyramid table as defined by &ipu3_uapi_anr_stitch_pyramid - * default values: - * { 1, 3, 5 }, { 7, 7, 5 }, { 3, 1, 3 }, - * { 9, 15, 21 }, { 21, 15, 9 }, { 3, 5, 15 }, - * { 25, 35, 35 }, { 25, 15, 5 }, { 7, 21, 35 }, - * { 49, 49, 35 }, { 21, 7, 7 }, { 21, 35, 49 }, - * { 49, 35, 21 }, { 7, 5, 15 }, { 25, 35, 35 }, - * { 25, 15, 5 }, { 3, 9, 15 }, { 21, 21, 15 }, - * { 9, 3, 1 }, { 3, 5, 7 }, { 7, 5, 3}, { 1 } - */ -struct ipu3_uapi_anr_stitch_config { - __u32 anr_stitch_en; - __u8 reserved[44]; - struct ipu3_uapi_anr_stitch_pyramid pyramid[IPU3_UAPI_ANR_PYRAMID_SIZE]; -} __packed; - -/** - * struct ipu3_uapi_anr_config - ANR config - * - * @transform: advanced noise reduction transform config as specified by - * &ipu3_uapi_anr_transform_config - * @stitch: create 4x4 patch from 4 surrounding 8x8 patches. - */ -struct ipu3_uapi_anr_config { - struct ipu3_uapi_anr_transform_config transform __attribute__((aligned(32))); - struct ipu3_uapi_anr_stitch_config stitch __attribute__((aligned(32))); -} __packed; - -/** - * struct ipu3_uapi_acc_param - Accelerator cluster parameters - * - * ACC refers to the HW cluster containing all Fixed Functions (FFs). Each FF - * implements a specific algorithm. - * - * @bnr: parameters for bayer noise reduction static config. See - * &ipu3_uapi_bnr_static_config - * @green_disparity: disparity static config between gr and gb channel. - * See &ipu3_uapi_bnr_static_config_green_disparity - * @dm: de-mosaic config. See &ipu3_uapi_dm_config - * @ccm: color correction matrix. See &ipu3_uapi_ccm_mat_config - * @gamma: gamma correction config. See &ipu3_uapi_gamma_config - * @csc: color space conversion matrix. See &ipu3_uapi_csc_mat_config - * @cds: color down sample config. See &ipu3_uapi_cds_params - * @shd: lens shading correction config. See &ipu3_uapi_shd_config - * @iefd: Image enhancement filter and denoise config. - * &ipu3_uapi_yuvp1_iefd_config - * @yds_c0: y down scaler config. &ipu3_uapi_yuvp1_yds_config - * @chnr_c0: chroma noise reduction config. &ipu3_uapi_yuvp1_chnr_config - * @y_ee_nr: y edge enhancement and noise reduction config. - * &ipu3_uapi_yuvp1_y_ee_nr_config - * @yds: y down scaler config. See &ipu3_uapi_yuvp1_yds_config - * @chnr: chroma noise reduction config. See &ipu3_uapi_yuvp1_chnr_config - * @reserved1: reserved - * @yds2: y channel down scaler config. See &ipu3_uapi_yuvp1_yds_config - * @tcc: total color correction config as defined in struct - * &ipu3_uapi_yuvp2_tcc_static_config - * @reserved2: reserved - * @anr: advanced noise reduction config.See &ipu3_uapi_anr_config - * @awb_fr: AWB filter response config. See ipu3_uapi_awb_fr_config - * @ae: auto exposure config As specified by &ipu3_uapi_ae_config - * @af: auto focus config. As specified by &ipu3_uapi_af_config - * @awb: auto white balance config. As specified by &ipu3_uapi_awb_config - */ -struct ipu3_uapi_acc_param { - struct ipu3_uapi_bnr_static_config bnr; - struct ipu3_uapi_bnr_static_config_green_disparity - green_disparity __attribute__((aligned(32))); - struct ipu3_uapi_dm_config dm __attribute__((aligned(32))); - struct ipu3_uapi_ccm_mat_config ccm __attribute__((aligned(32))); - struct ipu3_uapi_gamma_config gamma __attribute__((aligned(32))); - struct ipu3_uapi_csc_mat_config csc __attribute__((aligned(32))); - struct ipu3_uapi_cds_params cds __attribute__((aligned(32))); - struct ipu3_uapi_shd_config shd __attribute__((aligned(32))); - struct ipu3_uapi_yuvp1_iefd_config iefd __attribute__((aligned(32))); - struct ipu3_uapi_yuvp1_yds_config yds_c0 __attribute__((aligned(32))); - struct ipu3_uapi_yuvp1_chnr_config chnr_c0 __attribute__((aligned(32))); - struct ipu3_uapi_yuvp1_y_ee_nr_config y_ee_nr __attribute__((aligned(32))); - struct ipu3_uapi_yuvp1_yds_config yds __attribute__((aligned(32))); - struct ipu3_uapi_yuvp1_chnr_config chnr __attribute__((aligned(32))); - struct ipu3_uapi_yuvp1_yds_config yds2 __attribute__((aligned(32))); - struct ipu3_uapi_yuvp2_tcc_static_config tcc __attribute__((aligned(32))); - struct ipu3_uapi_anr_config anr; - struct ipu3_uapi_awb_fr_config_s awb_fr; - struct ipu3_uapi_ae_config ae; - struct ipu3_uapi_af_config_s af; - struct ipu3_uapi_awb_config awb; -} __packed; - -/** - * struct ipu3_uapi_isp_lin_vmem_params - Linearization parameters - * - * @lin_lutlow_gr: linearization look-up table for GR channel interpolation. - * @lin_lutlow_r: linearization look-up table for R channel interpolation. - * @lin_lutlow_b: linearization look-up table for B channel interpolation. - * @lin_lutlow_gb: linearization look-up table for GB channel interpolation. - * lin_lutlow_gr / lin_lutlow_r / lin_lutlow_b / - * lin_lutlow_gb <= LIN_MAX_VALUE - 1. - * @lin_lutdif_gr: lin_lutlow_gr[i+1] - lin_lutlow_gr[i]. - * @lin_lutdif_r: lin_lutlow_r[i+1] - lin_lutlow_r[i]. - * @lin_lutdif_b: lin_lutlow_b[i+1] - lin_lutlow_b[i]. - * @lin_lutdif_gb: lin_lutlow_gb[i+1] - lin_lutlow_gb[i]. - */ -struct ipu3_uapi_isp_lin_vmem_params { - __s16 lin_lutlow_gr[IPU3_UAPI_LIN_LUT_SIZE]; - __s16 lin_lutlow_r[IPU3_UAPI_LIN_LUT_SIZE]; - __s16 lin_lutlow_b[IPU3_UAPI_LIN_LUT_SIZE]; - __s16 lin_lutlow_gb[IPU3_UAPI_LIN_LUT_SIZE]; - __s16 lin_lutdif_gr[IPU3_UAPI_LIN_LUT_SIZE]; - __s16 lin_lutdif_r[IPU3_UAPI_LIN_LUT_SIZE]; - __s16 lin_lutdif_b[IPU3_UAPI_LIN_LUT_SIZE]; - __s16 lin_lutdif_gb[IPU3_UAPI_LIN_LUT_SIZE]; -} __packed; - -/* Temporal Noise Reduction */ - -/** - * struct ipu3_uapi_isp_tnr3_vmem_params - Temporal noise reduction vector - * memory parameters - * - * @slope: slope setting in interpolation curve for temporal noise reduction. - * @reserved1: reserved - * @sigma: knee point setting in interpolation curve for temporal - * noise reduction. - * @reserved2: reserved - */ -struct ipu3_uapi_isp_tnr3_vmem_params { - __u16 slope[IPU3_UAPI_ISP_TNR3_VMEM_LEN]; - __u16 reserved1[IPU3_UAPI_ISP_VEC_ELEMS - - IPU3_UAPI_ISP_TNR3_VMEM_LEN]; - __u16 sigma[IPU3_UAPI_ISP_TNR3_VMEM_LEN]; - __u16 reserved2[IPU3_UAPI_ISP_VEC_ELEMS - - IPU3_UAPI_ISP_TNR3_VMEM_LEN]; -} __packed; - -/** - * struct ipu3_uapi_isp_tnr3_params - Temporal noise reduction v3 parameters - * - * @knee_y1: Knee point TNR3 assumes standard deviation of Y,U and - * V at Y1 are TnrY1_Sigma_Y, U and V. - * @knee_y2: Knee point TNR3 assumes standard deviation of Y,U and - * V at Y2 are TnrY2_Sigma_Y, U and V. - * @maxfb_y: Max feedback gain for Y - * @maxfb_u: Max feedback gain for U - * @maxfb_v: Max feedback gain for V - * @round_adj_y: rounding Adjust for Y - * @round_adj_u: rounding Adjust for U - * @round_adj_v: rounding Adjust for V - * @ref_buf_select: selection of the reference frame buffer to be used. - */ -struct ipu3_uapi_isp_tnr3_params { - __u32 knee_y1; - __u32 knee_y2; - __u32 maxfb_y; - __u32 maxfb_u; - __u32 maxfb_v; - __u32 round_adj_y; - __u32 round_adj_u; - __u32 round_adj_v; - __u32 ref_buf_select; -} __packed; - -/* Extreme Noise Reduction version 3 */ - -/** - * struct ipu3_uapi_isp_xnr3_vmem_params - Extreme noise reduction v3 - * vector memory parameters - * - * @x: xnr3 parameters. - * @a: xnr3 parameters. - * @b: xnr3 parameters. - * @c: xnr3 parameters. - */ -struct ipu3_uapi_isp_xnr3_vmem_params { - __u16 x[IPU3_UAPI_ISP_VEC_ELEMS]; - __u16 a[IPU3_UAPI_ISP_VEC_ELEMS]; - __u16 b[IPU3_UAPI_ISP_VEC_ELEMS]; - __u16 c[IPU3_UAPI_ISP_VEC_ELEMS]; -} __packed; - -/** - * struct ipu3_uapi_xnr3_alpha_params - Extreme noise reduction v3 - * alpha tuning parameters - * - * @y0: Sigma for Y range similarity in dark area. - * @u0: Sigma for U range similarity in dark area. - * @v0: Sigma for V range similarity in dark area. - * @ydiff: Sigma difference for Y between bright area and dark area. - * @udiff: Sigma difference for U between bright area and dark area. - * @vdiff: Sigma difference for V between bright area and dark area. - */ -struct ipu3_uapi_xnr3_alpha_params { - __u32 y0; - __u32 u0; - __u32 v0; - __u32 ydiff; - __u32 udiff; - __u32 vdiff; -} __packed; - -/** - * struct ipu3_uapi_xnr3_coring_params - Extreme noise reduction v3 - * coring parameters - * - * @u0: Coring Threshold of U channel in dark area. - * @v0: Coring Threshold of V channel in dark area. - * @udiff: Threshold difference of U channel between bright and dark area. - * @vdiff: Threshold difference of V channel between bright and dark area. - */ -struct ipu3_uapi_xnr3_coring_params { - __u32 u0; - __u32 v0; - __u32 udiff; - __u32 vdiff; -} __packed; - -/** - * struct ipu3_uapi_xnr3_blending_params - Blending factor - * - * @strength: The factor for blending output with input. This is tuning - * parameterHigher values lead to more aggressive XNR operation. - */ -struct ipu3_uapi_xnr3_blending_params { - __u32 strength; -} __packed; - -/** - * struct ipu3_uapi_isp_xnr3_params - Extreme noise reduction v3 parameters - * - * @alpha: parameters for xnr3 alpha. See &ipu3_uapi_xnr3_alpha_params - * @coring: parameters for xnr3 coring. See &ipu3_uapi_xnr3_coring_params - * @blending: parameters for xnr3 blending. See &ipu3_uapi_xnr3_blending_params - */ -struct ipu3_uapi_isp_xnr3_params { - struct ipu3_uapi_xnr3_alpha_params alpha; - struct ipu3_uapi_xnr3_coring_params coring; - struct ipu3_uapi_xnr3_blending_params blending; -} __packed; - -/***** Obgrid (optical black level compensation) table entry *****/ - -/** - * struct ipu3_uapi_obgrid_param - Optical black level compensation parameters - * - * @gr: Grid table values for color GR - * @r: Grid table values for color R - * @b: Grid table values for color B - * @gb: Grid table values for color GB - * - * Black level is different for red, green, and blue channels. So black level - * compensation is different per channel. - */ -struct ipu3_uapi_obgrid_param { - __u16 gr; - __u16 r; - __u16 b; - __u16 gb; -} __packed; - -/******************* V4L2_META_FMT_IPU3_PARAMS *******************/ - -/** - * struct ipu3_uapi_flags - bits to indicate which pipeline needs update - * - * @gdc: 0 = no update, 1 = update. - * @obgrid: 0 = no update, 1 = update. - * @reserved1: Not used. - * @acc_bnr: 0 = no update, 1 = update. - * @acc_green_disparity: 0 = no update, 1 = update. - * @acc_dm: 0 = no update, 1 = update. - * @acc_ccm: 0 = no update, 1 = update. - * @acc_gamma: 0 = no update, 1 = update. - * @acc_csc: 0 = no update, 1 = update. - * @acc_cds: 0 = no update, 1 = update. - * @acc_shd: 0 = no update, 1 = update. - * @reserved2: Not used. - * @acc_iefd: 0 = no update, 1 = update. - * @acc_yds_c0: 0 = no update, 1 = update. - * @acc_chnr_c0: 0 = no update, 1 = update. - * @acc_y_ee_nr: 0 = no update, 1 = update. - * @acc_yds: 0 = no update, 1 = update. - * @acc_chnr: 0 = no update, 1 = update. - * @acc_ytm: 0 = no update, 1 = update. - * @acc_yds2: 0 = no update, 1 = update. - * @acc_tcc: 0 = no update, 1 = update. - * @acc_dpc: 0 = no update, 1 = update. - * @acc_bds: 0 = no update, 1 = update. - * @acc_anr: 0 = no update, 1 = update. - * @acc_awb_fr: 0 = no update, 1 = update. - * @acc_ae: 0 = no update, 1 = update. - * @acc_af: 0 = no update, 1 = update. - * @acc_awb: 0 = no update, 1 = update. - * @__acc_osys: 0 = no update, 1 = update. - * @reserved3: Not used. - * @lin_vmem_params: 0 = no update, 1 = update. - * @tnr3_vmem_params: 0 = no update, 1 = update. - * @xnr3_vmem_params: 0 = no update, 1 = update. - * @tnr3_dmem_params: 0 = no update, 1 = update. - * @xnr3_dmem_params: 0 = no update, 1 = update. - * @reserved4: Not used. - * @obgrid_param: 0 = no update, 1 = update. - * @reserved5: Not used. - */ -struct ipu3_uapi_flags { - __u32 gdc:1; - __u32 obgrid:1; - __u32 reserved1:30; - - __u32 acc_bnr:1; - __u32 acc_green_disparity:1; - __u32 acc_dm:1; - __u32 acc_ccm:1; - __u32 acc_gamma:1; - __u32 acc_csc:1; - __u32 acc_cds:1; - __u32 acc_shd:1; - __u32 reserved2:2; - __u32 acc_iefd:1; - __u32 acc_yds_c0:1; - __u32 acc_chnr_c0:1; - __u32 acc_y_ee_nr:1; - __u32 acc_yds:1; - __u32 acc_chnr:1; - __u32 acc_ytm:1; - __u32 acc_yds2:1; - __u32 acc_tcc:1; - __u32 acc_dpc:1; - __u32 acc_bds:1; - __u32 acc_anr:1; - __u32 acc_awb_fr:1; - __u32 acc_ae:1; - __u32 acc_af:1; - __u32 acc_awb:1; - __u32 reserved3:4; - - __u32 lin_vmem_params:1; - __u32 tnr3_vmem_params:1; - __u32 xnr3_vmem_params:1; - __u32 tnr3_dmem_params:1; - __u32 xnr3_dmem_params:1; - __u32 reserved4:1; - __u32 obgrid_param:1; - __u32 reserved5:25; -} __packed; - -/** - * struct ipu3_uapi_params - V4L2_META_FMT_IPU3_PARAMS - * - * @use: select which parameters to apply, see &ipu3_uapi_flags - * @acc_param: ACC parameters, as specified by &ipu3_uapi_acc_param - * @lin_vmem_params: linearization VMEM, as specified by - * &ipu3_uapi_isp_lin_vmem_params - * @tnr3_vmem_params: tnr3 VMEM as specified by - * &ipu3_uapi_isp_tnr3_vmem_params - * @xnr3_vmem_params: xnr3 VMEM as specified by - * &ipu3_uapi_isp_xnr3_vmem_params - * @tnr3_dmem_params: tnr3 DMEM as specified by &ipu3_uapi_isp_tnr3_params - * @xnr3_dmem_params: xnr3 DMEM as specified by &ipu3_uapi_isp_xnr3_params - * @obgrid_param: obgrid parameters as specified by - * &ipu3_uapi_obgrid_param - * - * The video queue "parameters" is of format V4L2_META_FMT_IPU3_PARAMS. - * This is a "single plane" v4l2_meta_format using V4L2_BUF_TYPE_META_OUTPUT. - * - * struct ipu3_uapi_params as defined below contains a lot of parameters and - * ipu3_uapi_flags selects which parameters to apply. - */ -struct ipu3_uapi_params { - /* Flags which of the settings below are to be applied */ - struct ipu3_uapi_flags use __attribute__((aligned(32))); - - /* Accelerator cluster parameters */ - struct ipu3_uapi_acc_param acc_param; - - /* ISP vector address space parameters */ - struct ipu3_uapi_isp_lin_vmem_params lin_vmem_params; - struct ipu3_uapi_isp_tnr3_vmem_params tnr3_vmem_params; - struct ipu3_uapi_isp_xnr3_vmem_params xnr3_vmem_params; - - /* ISP data memory (DMEM) parameters */ - struct ipu3_uapi_isp_tnr3_params tnr3_dmem_params; - struct ipu3_uapi_isp_xnr3_params xnr3_dmem_params; - - /* Optical black level compensation */ - struct ipu3_uapi_obgrid_param obgrid_param; -} __packed; - -#endif /* __IPU3_UAPI_H */ diff --git a/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h b/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h new file mode 100644 index 000000000000..fa3d6ee5adf2 --- /dev/null +++ b/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h @@ -0,0 +1,2786 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* Copyright (C) 2017 - 2018 Intel Corporation */ + +#ifndef __IPU3_UAPI_H +#define __IPU3_UAPI_H + +#include + +/* from /drivers/staging/media/ipu3/include/videodev2.h */ + +/* Vendor specific - used for IPU3 camera sub-system */ +/* IPU3 processing parameters */ +#define V4L2_META_FMT_IPU3_PARAMS v4l2_fourcc('i', 'p', '3', 'p') +/* IPU3 3A statistics */ +#define V4L2_META_FMT_IPU3_STAT_3A v4l2_fourcc('i', 'p', '3', 's') + +/* from include/uapi/linux/v4l2-controls.h */ +#define V4L2_CID_INTEL_IPU3_BASE (V4L2_CID_USER_BASE + 0x10c0) +#define V4L2_CID_INTEL_IPU3_MODE (V4L2_CID_INTEL_IPU3_BASE + 1) + +/******************* ipu3_uapi_stats_3a *******************/ + +#define IPU3_UAPI_MAX_STRIPES 2 +#define IPU3_UAPI_MAX_BUBBLE_SIZE 10 + +#define IPU3_UAPI_GRID_START_MASK ((1 << 12) - 1) +#define IPU3_UAPI_GRID_Y_START_EN (1 << 15) + +/* controls generation of meta_data (like FF enable/disable) */ +#define IPU3_UAPI_AWB_RGBS_THR_B_EN (1 << 14) +#define IPU3_UAPI_AWB_RGBS_THR_B_INCL_SAT (1 << 15) + +/** + * struct ipu3_uapi_grid_config - Grid plane config + * + * @width: Grid horizontal dimensions, in number of grid blocks(cells). + * @height: Grid vertical dimensions, in number of grid cells. + * @block_width_log2: Log2 of the width of each cell in pixels. + * for (2^3, 2^4, 2^5, 2^6, 2^7), values [3, 7]. + * @block_height_log2: Log2 of the height of each cell in pixels. + * for (2^3, 2^4, 2^5, 2^6, 2^7), values [3, 7]. + * @height_per_slice: The number of blocks in vertical axis per slice. + * Default 2. + * @x_start: X value of top left corner of Region of Interest(ROI). + * @y_start: Y value of top left corner of ROI + * @x_end: X value of bottom right corner of ROI + * @y_end: Y value of bottom right corner of ROI + * + * Due to the size of total amount of collected data, most statistics + * create a grid-based output, and the data is then divided into "slices". + */ +struct ipu3_uapi_grid_config { + __u8 width; + __u8 height; + __u16 block_width_log2:3; + __u16 block_height_log2:3; + __u16 height_per_slice:8; + __u16 x_start; + __u16 y_start; + __u16 x_end; + __u16 y_end; +} __packed; + +/* + * The grid based data is divided into "slices" called set, each slice of setX + * refers to ipu3_uapi_grid_config width * height_per_slice. + */ +#define IPU3_UAPI_AWB_MAX_SETS 60 +/* Based on grid size 80 * 60 and cell size 16 x 16 */ +#define IPU3_UAPI_AWB_SET_SIZE 1280 +#define IPU3_UAPI_AWB_MD_ITEM_SIZE 8 +#define IPU3_UAPI_AWB_SPARE_FOR_BUBBLES \ + (IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \ + IPU3_UAPI_AWB_MD_ITEM_SIZE) +#define IPU3_UAPI_AWB_MAX_BUFFER_SIZE \ + (IPU3_UAPI_AWB_MAX_SETS * \ + (IPU3_UAPI_AWB_SET_SIZE + IPU3_UAPI_AWB_SPARE_FOR_BUBBLES)) + +/** + * struct ipu3_uapi_awb_raw_buffer - AWB raw buffer + * + * @meta_data: buffer to hold auto white balance meta data which is + * the average values for each color channel. + */ +struct ipu3_uapi_awb_raw_buffer { + __u8 meta_data[IPU3_UAPI_AWB_MAX_BUFFER_SIZE] + __attribute__((aligned(32))); +} __packed; + +/** + * struct ipu3_uapi_awb_config_s - AWB config + * + * @rgbs_thr_gr: gr threshold value. + * @rgbs_thr_r: Red threshold value. + * @rgbs_thr_gb: gb threshold value. + * @rgbs_thr_b: Blue threshold value. + * @grid: &ipu3_uapi_grid_config, the default grid resolution is 16x16 cells. + * + * The threshold is a saturation measure range [0, 8191], 8191 is default. + * Values over threshold may be optionally rejected for averaging. + */ +struct ipu3_uapi_awb_config_s { + __u16 rgbs_thr_gr; + __u16 rgbs_thr_r; + __u16 rgbs_thr_gb; + __u16 rgbs_thr_b; + struct ipu3_uapi_grid_config grid; +} __attribute__((aligned(32))) __packed; + +/** + * struct ipu3_uapi_awb_config - AWB config wrapper + * + * @config: config for auto white balance as defined by &ipu3_uapi_awb_config_s + */ +struct ipu3_uapi_awb_config { + struct ipu3_uapi_awb_config_s config __attribute__((aligned(32))); +} __packed; + +#define IPU3_UAPI_AE_COLORS 4 /* R, G, B, Y */ +#define IPU3_UAPI_AE_BINS 256 +#define IPU3_UAPI_AE_WEIGHTS 96 + +/** + * struct ipu3_uapi_ae_raw_buffer - AE global weighted histogram + * + * @vals: Sum of IPU3_UAPI_AE_COLORS in cell + * + * Each histogram contains IPU3_UAPI_AE_BINS bins. Each bin has 24 bit unsigned + * for counting the number of the pixel. + */ +struct ipu3_uapi_ae_raw_buffer { + __u32 vals[IPU3_UAPI_AE_BINS * IPU3_UAPI_AE_COLORS]; +} __packed; + +/** + * struct ipu3_uapi_ae_raw_buffer_aligned - AE raw buffer + * + * @buff: &ipu3_uapi_ae_raw_buffer to hold full frame meta data. + */ +struct ipu3_uapi_ae_raw_buffer_aligned { + struct ipu3_uapi_ae_raw_buffer buff __attribute__((aligned(32))); +} __packed; + +/** + * struct ipu3_uapi_ae_grid_config - AE weight grid + * + * @width: Grid horizontal dimensions. Value: [16, 32], default 16. + * @height: Grid vertical dimensions. Value: [16, 24], default 16. + * @block_width_log2: Log2 of the width of the grid cell, value: [3, 7]. + * @block_height_log2: Log2 of the height of the grid cell, value: [3, 7]. + * default is 3 (cell size 8x8), 4 cell per grid. + * @reserved0: reserved + * @ae_en: 0: does not write to &ipu3_uapi_ae_raw_buffer_aligned array, + * 1: write normally. + * @rst_hist_array: write 1 to trigger histogram array reset. + * @done_rst_hist_array: flag for histogram array reset done. + * @x_start: X value of top left corner of ROI, default 0. + * @y_start: Y value of top left corner of ROI, default 0. + * @x_end: X value of bottom right corner of ROI + * @y_end: Y value of bottom right corner of ROI + * + * The AE block accumulates 4 global weighted histograms(R, G, B, Y) over + * a defined ROI within the frame. The contribution of each pixel into the + * histogram, defined by &ipu3_uapi_ae_weight_elem LUT, is indexed by a grid. + */ +struct ipu3_uapi_ae_grid_config { + __u8 width; + __u8 height; + __u8 block_width_log2:4; + __u8 block_height_log2:4; + __u8 reserved0:5; + __u8 ae_en:1; + __u8 rst_hist_array:1; + __u8 done_rst_hist_array:1; + __u16 x_start; + __u16 y_start; + __u16 x_end; + __u16 y_end; +} __packed; + +/** + * struct ipu3_uapi_ae_weight_elem - AE weights LUT + * + * @cell0: weighted histogram grid value. + * @cell1: weighted histogram grid value. + * @cell2: weighted histogram grid value. + * @cell3: weighted histogram grid value. + * @cell4: weighted histogram grid value. + * @cell5: weighted histogram grid value. + * @cell6: weighted histogram grid value. + * @cell7: weighted histogram grid value. + * + * Use weighted grid value to give a different contribution factor to each cell. + * Precision u4, range [0, 15]. + */ +struct ipu3_uapi_ae_weight_elem { + __u32 cell0:4; + __u32 cell1:4; + __u32 cell2:4; + __u32 cell3:4; + __u32 cell4:4; + __u32 cell5:4; + __u32 cell6:4; + __u32 cell7:4; +} __packed; + +/** + * struct ipu3_uapi_ae_ccm - AE coefficients for WB and CCM + * + * @gain_gr: WB gain factor for the gr channels. Default 256. + * @gain_r: WB gain factor for the r channel. Default 256. + * @gain_b: WB gain factor for the b channel. Default 256. + * @gain_gb: WB gain factor for the gb channels. Default 256. + * @mat: 4x4 matrix that transforms Bayer quad output from WB to RGB+Y. + * + * Default: + * 128, 0, 0, 0, + * 0, 128, 0, 0, + * 0, 0, 128, 0, + * 0, 0, 0, 128, + * + * As part of the raw frame pre-process stage, the WB and color conversion need + * to be applied to expose the impact of these gain operations. + */ +struct ipu3_uapi_ae_ccm { + __u16 gain_gr; + __u16 gain_r; + __u16 gain_b; + __u16 gain_gb; + __s16 mat[16]; +} __packed; + +/** + * struct ipu3_uapi_ae_config - AE config + * + * @grid_cfg: config for auto exposure statistics grid. See struct + * &ipu3_uapi_ae_grid_config + * @weights: &IPU3_UAPI_AE_WEIGHTS is based on 32x24 blocks in the grid. + * Each grid cell has a corresponding value in weights LUT called + * grid value, global histogram is updated based on grid value and + * pixel value. + * @ae_ccm: Color convert matrix pre-processing block. + * + * Calculate AE grid from image resolution, resample ae weights. + */ +struct ipu3_uapi_ae_config { + struct ipu3_uapi_ae_grid_config grid_cfg __attribute__((aligned(32))); + struct ipu3_uapi_ae_weight_elem weights[IPU3_UAPI_AE_WEIGHTS] + __attribute__((aligned(32))); + struct ipu3_uapi_ae_ccm ae_ccm __attribute__((aligned(32))); +} __packed; + +/** + * struct ipu3_uapi_af_filter_config - AF 2D filter for contrast measurements + * + * @y1_coeff_0: filter Y1, structure: 3x11, support both symmetry and + * anti-symmetry type. A12 is center, A1-A11 are neighbours. + * for analyzing low frequency content, used to calculate sum + * of gradients in x direction. + * @y1_coeff_0.a1: filter1 coefficients A1, u8, default 0. + * @y1_coeff_0.a2: filter1 coefficients A2, u8, default 0. + * @y1_coeff_0.a3: filter1 coefficients A3, u8, default 0. + * @y1_coeff_0.a4: filter1 coefficients A4, u8, default 0. + * @y1_coeff_1: Struct + * @y1_coeff_1.a5: filter1 coefficients A5, u8, default 0. + * @y1_coeff_1.a6: filter1 coefficients A6, u8, default 0. + * @y1_coeff_1.a7: filter1 coefficients A7, u8, default 0. + * @y1_coeff_1.a8: filter1 coefficients A8, u8, default 0. + * @y1_coeff_2: Struct + * @y1_coeff_2.a9: filter1 coefficients A9, u8, default 0. + * @y1_coeff_2.a10: filter1 coefficients A10, u8, default 0. + * @y1_coeff_2.a11: filter1 coefficients A11, u8, default 0. + * @y1_coeff_2.a12: filter1 coefficients A12, u8, default 128. + * @y1_sign_vec: Each bit corresponds to one coefficient sign bit, + * 0: positive, 1: negative, default 0. + * @y2_coeff_0: Y2, same structure as Y1. For analyzing high frequency content. + * @y2_coeff_0.a1: filter2 coefficients A1, u8, default 0. + * @y2_coeff_0.a2: filter2 coefficients A2, u8, default 0. + * @y2_coeff_0.a3: filter2 coefficients A3, u8, default 0. + * @y2_coeff_0.a4: filter2 coefficients A4, u8, default 0. + * @y2_coeff_1: Struct + * @y2_coeff_1.a5: filter2 coefficients A5, u8, default 0. + * @y2_coeff_1.a6: filter2 coefficients A6, u8, default 0. + * @y2_coeff_1.a7: filter2 coefficients A7, u8, default 0. + * @y2_coeff_1.a8: filter2 coefficients A8, u8, default 0. + * @y2_coeff_2: Struct + * @y2_coeff_2.a9: filter1 coefficients A9, u8, default 0. + * @y2_coeff_2.a10: filter1 coefficients A10, u8, default 0. + * @y2_coeff_2.a11: filter1 coefficients A11, u8, default 0. + * @y2_coeff_2.a12: filter1 coefficients A12, u8, default 128. + * @y2_sign_vec: Each bit corresponds to one coefficient sign bit, + * 0: positive, 1: negative, default 0. + * @y_calc: Pre-processing that converts Bayer quad to RGB+Y values to be + * used for building histogram. Range [0, 32], default 8. + * Rule: + * y_gen_rate_gr + y_gen_rate_r + y_gen_rate_b + y_gen_rate_gb = 32 + * A single Y is calculated based on sum of Gr/R/B/Gb based on + * their contribution ratio. + * @y_calc.y_gen_rate_gr: Contribution ratio Gr for Y + * @y_calc.y_gen_rate_r: Contribution ratio R for Y + * @y_calc.y_gen_rate_b: Contribution ratio B for Y + * @y_calc.y_gen_rate_gb: Contribution ratio Gb for Y + * @nf: The shift right value that should be applied during the Y1/Y2 filter to + * make sure the total memory needed is 2 bytes per grid cell. + * @nf.reserved0: reserved + * @nf.y1_nf: Normalization factor for the convolution coeffs of y1, + * should be log2 of the sum of the abs values of the filter + * coeffs, default 7 (2^7 = 128). + * @nf.reserved1: reserved + * @nf.y2_nf: Normalization factor for y2, should be log2 of the sum of the + * abs values of the filter coeffs. + * @nf.reserved2: reserved + */ +struct ipu3_uapi_af_filter_config { + struct { + __u8 a1; + __u8 a2; + __u8 a3; + __u8 a4; + } y1_coeff_0; + struct { + __u8 a5; + __u8 a6; + __u8 a7; + __u8 a8; + } y1_coeff_1; + struct { + __u8 a9; + __u8 a10; + __u8 a11; + __u8 a12; + } y1_coeff_2; + + __u32 y1_sign_vec; + + struct { + __u8 a1; + __u8 a2; + __u8 a3; + __u8 a4; + } y2_coeff_0; + struct { + __u8 a5; + __u8 a6; + __u8 a7; + __u8 a8; + } y2_coeff_1; + struct { + __u8 a9; + __u8 a10; + __u8 a11; + __u8 a12; + } y2_coeff_2; + + __u32 y2_sign_vec; + + struct { + __u8 y_gen_rate_gr; + __u8 y_gen_rate_r; + __u8 y_gen_rate_b; + __u8 y_gen_rate_gb; + } y_calc; + + struct { + __u32 reserved0:8; + __u32 y1_nf:4; + __u32 reserved1:4; + __u32 y2_nf:4; + __u32 reserved2:12; + } nf; +} __packed; + +#define IPU3_UAPI_AF_MAX_SETS 24 +#define IPU3_UAPI_AF_MD_ITEM_SIZE 4 +#define IPU3_UAPI_AF_SPARE_FOR_BUBBLES \ + (IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \ + IPU3_UAPI_AF_MD_ITEM_SIZE) +#define IPU3_UAPI_AF_Y_TABLE_SET_SIZE 128 +#define IPU3_UAPI_AF_Y_TABLE_MAX_SIZE \ + (IPU3_UAPI_AF_MAX_SETS * \ + (IPU3_UAPI_AF_Y_TABLE_SET_SIZE + IPU3_UAPI_AF_SPARE_FOR_BUBBLES) * \ + IPU3_UAPI_MAX_STRIPES) + +/** + * struct ipu3_uapi_af_raw_buffer - AF meta data + * + * @y_table: Each color component will be convolved separately with filter1 + * and filter2 and the result will be summed out and averaged for + * each cell. + */ +struct ipu3_uapi_af_raw_buffer { + __u8 y_table[IPU3_UAPI_AF_Y_TABLE_MAX_SIZE] __attribute__((aligned(32))); +} __packed; + +/** + * struct ipu3_uapi_af_config_s - AF config + * + * @filter_config: AF uses Y1 and Y2 filters as configured in + * &ipu3_uapi_af_filter_config + * @padding: paddings + * @grid_cfg: See &ipu3_uapi_grid_config, default resolution 16x16. Use large + * grid size for large image and vice versa. + */ +struct ipu3_uapi_af_config_s { + struct ipu3_uapi_af_filter_config filter_config __attribute__((aligned(32))); + __u8 padding[4]; + struct ipu3_uapi_grid_config grid_cfg __attribute__((aligned(32))); +} __packed; + +#define IPU3_UAPI_AWB_FR_MAX_SETS 24 +#define IPU3_UAPI_AWB_FR_MD_ITEM_SIZE 8 +#define IPU3_UAPI_AWB_FR_BAYER_TBL_SIZE 256 +#define IPU3_UAPI_AWB_FR_SPARE_FOR_BUBBLES \ + (IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \ + IPU3_UAPI_AWB_FR_MD_ITEM_SIZE) +#define IPU3_UAPI_AWB_FR_BAYER_TABLE_MAX_SIZE \ + (IPU3_UAPI_AWB_FR_MAX_SETS * \ + (IPU3_UAPI_AWB_FR_BAYER_TBL_SIZE + \ + IPU3_UAPI_AWB_FR_SPARE_FOR_BUBBLES) * IPU3_UAPI_MAX_STRIPES) + +/** + * struct ipu3_uapi_awb_fr_raw_buffer - AWB filter response meta data + * + * @meta_data: Statistics output on the grid after convolving with 1D filter. + */ +struct ipu3_uapi_awb_fr_raw_buffer { + __u8 meta_data[IPU3_UAPI_AWB_FR_BAYER_TABLE_MAX_SIZE] + __attribute__((aligned(32))); +} __packed; + +/** + * struct ipu3_uapi_awb_fr_config_s - AWB filter response config + * + * @grid_cfg: grid config, default 16x16. + * @bayer_coeff: 1D Filter 1x11 center symmetry/anti-symmetry. + * coefficients defaults { 0, 0, 0, 0, 0, 128 }. + * Applied on whole image for each Bayer channel separately + * by a weighted sum of its 11x1 neighbors. + * @reserved1: reserved + * @bayer_sign: sign of filter coefficients, default 0. + * @bayer_nf: normalization factor for the convolution coeffs, to make sure + * total memory needed is within pre-determined range. + * NF should be the log2 of the sum of the abs values of the + * filter coeffs, range [7, 14], default 7. + * @reserved2: reserved + */ +struct ipu3_uapi_awb_fr_config_s { + struct ipu3_uapi_grid_config grid_cfg; + __u8 bayer_coeff[6]; + __u16 reserved1; + __u32 bayer_sign; + __u8 bayer_nf; + __u8 reserved2[7]; +} __packed; + +/** + * struct ipu3_uapi_4a_config - 4A config + * + * @awb_config: &ipu3_uapi_awb_config_s, default resolution 16x16 + * @ae_grd_config: auto exposure statistics &ipu3_uapi_ae_grid_config + * @padding: paddings + * @af_config: auto focus config &ipu3_uapi_af_config_s + * @awb_fr_config: &ipu3_uapi_awb_fr_config_s, default resolution 16x16 + */ +struct ipu3_uapi_4a_config { + struct ipu3_uapi_awb_config_s awb_config __attribute__((aligned(32))); + struct ipu3_uapi_ae_grid_config ae_grd_config; + __u8 padding[20]; + struct ipu3_uapi_af_config_s af_config; + struct ipu3_uapi_awb_fr_config_s awb_fr_config + __attribute__((aligned(32))); +} __packed; + +/** + * struct ipu3_uapi_bubble_info - Bubble info for host side debugging + * + * @num_of_stripes: A single frame is divided into several parts called stripes + * due to limitation on line buffer memory. + * The separation between the stripes is vertical. Each such + * stripe is processed as a single frame by the ISP pipe. + * @padding: padding bytes. + * @num_sets: number of sets. + * @padding1: padding bytes. + * @size_of_set: set size. + * @padding2: padding bytes. + * @bubble_size: is the amount of padding in the bubble expressed in "sets". + * @padding3: padding bytes. + */ +struct ipu3_uapi_bubble_info { + __u32 num_of_stripes __attribute__((aligned(32))); + __u8 padding[28]; + __u32 num_sets; + __u8 padding1[28]; + __u32 size_of_set; + __u8 padding2[28]; + __u32 bubble_size; + __u8 padding3[28]; +} __packed; + +/* + * struct ipu3_uapi_stats_3a_bubble_info_per_stripe + */ +struct ipu3_uapi_stats_3a_bubble_info_per_stripe { + struct ipu3_uapi_bubble_info awb[IPU3_UAPI_MAX_STRIPES]; + struct ipu3_uapi_bubble_info af[IPU3_UAPI_MAX_STRIPES]; + struct ipu3_uapi_bubble_info awb_fr[IPU3_UAPI_MAX_STRIPES]; +} __packed; + +/** + * struct ipu3_uapi_ff_status - Enable bits for each 3A fixed function + * + * @awb_en: auto white balance enable + * @padding: padding config + * @ae_en: auto exposure enable + * @padding1: padding config + * @af_en: auto focus enable + * @padding2: padding config + * @awb_fr_en: awb filter response enable bit + * @padding3: padding config + */ +struct ipu3_uapi_ff_status { + __u32 awb_en __attribute__((aligned(32))); + __u8 padding[28]; + __u32 ae_en; + __u8 padding1[28]; + __u32 af_en; + __u8 padding2[28]; + __u32 awb_fr_en; + __u8 padding3[28]; +} __packed; + +/** + * struct ipu3_uapi_stats_3a - 3A statistics + * + * @awb_raw_buffer: auto white balance meta data &ipu3_uapi_awb_raw_buffer + * @ae_raw_buffer: auto exposure raw data &ipu3_uapi_ae_raw_buffer_aligned + * @af_raw_buffer: &ipu3_uapi_af_raw_buffer for auto focus meta data + * @awb_fr_raw_buffer: value as specified by &ipu3_uapi_awb_fr_raw_buffer + * @stats_4a_config: 4a statistics config as defined by &ipu3_uapi_4a_config. + * @ae_join_buffers: 1 to use ae_raw_buffer. + * @padding: padding config + * @stats_3a_bubble_per_stripe: a &ipu3_uapi_stats_3a_bubble_info_per_stripe + * @stats_3a_status: 3a statistics status set in &ipu3_uapi_ff_status + */ +struct ipu3_uapi_stats_3a { + struct ipu3_uapi_awb_raw_buffer awb_raw_buffer; + struct ipu3_uapi_ae_raw_buffer_aligned + ae_raw_buffer[IPU3_UAPI_MAX_STRIPES]; + struct ipu3_uapi_af_raw_buffer af_raw_buffer; + struct ipu3_uapi_awb_fr_raw_buffer awb_fr_raw_buffer; + struct ipu3_uapi_4a_config stats_4a_config; + __u32 ae_join_buffers; + __u8 padding[28]; + struct ipu3_uapi_stats_3a_bubble_info_per_stripe + stats_3a_bubble_per_stripe; + struct ipu3_uapi_ff_status stats_3a_status; +} __packed; + +/******************* ipu3_uapi_acc_param *******************/ + +#define IPU3_UAPI_ISP_VEC_ELEMS 64 +#define IPU3_UAPI_ISP_TNR3_VMEM_LEN 9 + +#define IPU3_UAPI_BNR_LUT_SIZE 32 + +/* number of elements in gamma correction LUT */ +#define IPU3_UAPI_GAMMA_CORR_LUT_ENTRIES 256 + +/* largest grid is 73x56, for grid_height_per_slice of 2, 73x2 = 146 */ +#define IPU3_UAPI_SHD_MAX_CELLS_PER_SET 146 +#define IPU3_UAPI_SHD_MAX_CFG_SETS 28 +/* Normalization shift aka nf */ +#define IPU3_UAPI_SHD_BLGR_NF_SHIFT 13 +#define IPU3_UAPI_SHD_BLGR_NF_MASK 7 + +#define IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS 16 +#define IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS 14 +#define IPU3_UAPI_YUVP2_TCC_GAIN_PCWL_LUT_ELEMENTS 258 +#define IPU3_UAPI_YUVP2_TCC_R_SQR_LUT_ELEMENTS 24 + +#define IPU3_UAPI_ANR_LUT_SIZE 26 +#define IPU3_UAPI_ANR_PYRAMID_SIZE 22 + +#define IPU3_UAPI_LIN_LUT_SIZE 64 + +/* Bayer Noise Reduction related structs */ + +/** + * struct ipu3_uapi_bnr_static_config_wb_gains_config - White balance gains + * + * @gr: white balance gain for Gr channel. + * @r: white balance gain for R channel. + * @b: white balance gain for B channel. + * @gb: white balance gain for Gb channel. + * + * Precision u3.13, range [0, 8). White balance correction is done by applying + * a multiplicative gain to each color channels prior to BNR. + */ +struct ipu3_uapi_bnr_static_config_wb_gains_config { + __u16 gr; + __u16 r; + __u16 b; + __u16 gb; +} __packed; + +/** + * struct ipu3_uapi_bnr_static_config_wb_gains_thr_config - Threshold config + * + * @gr: white balance threshold gain for Gr channel. + * @r: white balance threshold gain for R channel. + * @b: white balance threshold gain for B channel. + * @gb: white balance threshold gain for Gb channel. + * + * Defines the threshold that specifies how different a defect pixel can be from + * its neighbors.(used by dynamic defect pixel correction sub block) + * Precision u4.4 range [0, 8]. + */ +struct ipu3_uapi_bnr_static_config_wb_gains_thr_config { + __u8 gr; + __u8 r; + __u8 b; + __u8 gb; +} __packed; + +/** + * struct ipu3_uapi_bnr_static_config_thr_coeffs_config - Noise model + * coefficients that controls noise threshold + * + * @cf: Free coefficient for threshold calculation, range [0, 8191], default 0. + * @reserved0: reserved + * @cg: Gain coefficient for threshold calculation, [0, 31], default 8. + * @ci: Intensity coefficient for threshold calculation. range [0, 0x1f] + * default 6. + * format: u3.2 (3 most significant bits represent whole number, + * 2 least significant bits represent the fractional part + * with each count representing 0.25) + * e.g. 6 in binary format is 00110, that translates to 1.5 + * @reserved1: reserved + * @r_nf: Normalization shift value for r^2 calculation, range [12, 20] + * where r is a radius of pixel [row, col] from centor of sensor. + * default 14. + * + * Threshold used to distinguish between noise and details. + */ +struct ipu3_uapi_bnr_static_config_thr_coeffs_config { + __u32 cf:13; + __u32 reserved0:3; + __u32 cg:5; + __u32 ci:5; + __u32 reserved1:1; + __u32 r_nf:5; +} __packed; + +/** + * struct ipu3_uapi_bnr_static_config_thr_ctrl_shd_config - Shading config + * + * @gr: Coefficient defines lens shading gain approximation for gr channel + * @r: Coefficient defines lens shading gain approximation for r channel + * @b: Coefficient defines lens shading gain approximation for b channel + * @gb: Coefficient defines lens shading gain approximation for gb channel + * + * Parameters for noise model (NM) adaptation of BNR due to shading correction. + * All above have precision of u3.3, default to 0. + */ +struct ipu3_uapi_bnr_static_config_thr_ctrl_shd_config { + __u8 gr; + __u8 r; + __u8 b; + __u8 gb; +} __packed; + +/** + * struct ipu3_uapi_bnr_static_config_opt_center_config - Optical center config + * + * @x_reset: Reset value of X (col start - X center). Precision s12.0. + * @reserved0: reserved + * @y_reset: Reset value of Y (row start - Y center). Precision s12.0. + * @reserved2: reserved + * + * Distance from corner to optical center for NM adaptation due to shading + * correction (should be calculated based on shading tables) + */ +struct ipu3_uapi_bnr_static_config_opt_center_config { + __s32 x_reset:13; + __u32 reserved0:3; + __s32 y_reset:13; + __u32 reserved2:3; +} __packed; + +/** + * struct ipu3_uapi_bnr_static_config_lut_config - BNR square root lookup table + * + * @values: pre-calculated values of square root function. + * + * LUT implementation of square root operation. + */ +struct ipu3_uapi_bnr_static_config_lut_config { + __u8 values[IPU3_UAPI_BNR_LUT_SIZE]; +} __packed; + +/** + * struct ipu3_uapi_bnr_static_config_bp_ctrl_config - Detect bad pixels (bp) + * + * @bp_thr_gain: Defines the threshold that specifies how different a + * defect pixel can be from its neighbors. Threshold is + * dependent on de-noise threshold calculated by algorithm. + * Range [4, 31], default 4. + * @reserved0: reserved + * @defect_mode: Mode of addressed defect pixels, + * 0 - single defect pixel is expected, + * 1 - 2 adjacent defect pixels are expected, default 1. + * @bp_gain: Defines how 2nd derivation that passes through a defect pixel + * is different from 2nd derivations that pass through + * neighbor pixels. u4.2, range [0, 256], default 8. + * @reserved1: reserved + * @w0_coeff: Blending coefficient of defect pixel correction. + * Precision u4, range [0, 8], default 8. + * @reserved2: reserved + * @w1_coeff: Enable influence of incorrect defect pixel correction to be + * avoided. Precision u4, range [1, 8], default 8. + * @reserved3: reserved + */ +struct ipu3_uapi_bnr_static_config_bp_ctrl_config { + __u32 bp_thr_gain:5; + __u32 reserved0:2; + __u32 defect_mode:1; + __u32 bp_gain:6; + __u32 reserved1:18; + __u32 w0_coeff:4; + __u32 reserved2:4; + __u32 w1_coeff:4; + __u32 reserved3:20; +} __packed; + +/** + * struct ipu3_uapi_bnr_static_config_dn_detect_ctrl_config - Denoising config + * + * @alpha: Weight of central element of smoothing filter. + * @beta: Weight of peripheral elements of smoothing filter, default 4. + * @gamma: Weight of diagonal elements of smoothing filter, default 4. + * + * beta and gamma parameter define the strength of the noise removal filter. + * All above has precision u0.4, range [0, 0xf] + * format: u0.4 (no / zero bits represent whole number, + * 4 bits represent the fractional part + * with each count representing 0.0625) + * e.g. 0xf translates to 0.0625x15 = 0.9375 + * + * @reserved0: reserved + * @max_inf: Maximum increase of peripheral or diagonal element influence + * relative to the pre-defined value range: [0x5, 0xa] + * @reserved1: reserved + * @gd_enable: Green disparity enable control, 0 - disable, 1 - enable. + * @bpc_enable: Bad pixel correction enable control, 0 - disable, 1 - enable. + * @bnr_enable: Bayer noise removal enable control, 0 - disable, 1 - enable. + * @ff_enable: Fixed function enable, 0 - disable, 1 - enable. + * @reserved2: reserved + */ +struct ipu3_uapi_bnr_static_config_dn_detect_ctrl_config { + __u32 alpha:4; + __u32 beta:4; + __u32 gamma:4; + __u32 reserved0:4; + __u32 max_inf:4; + __u32 reserved1:7; + __u32 gd_enable:1; + __u32 bpc_enable:1; + __u32 bnr_enable:1; + __u32 ff_enable:1; + __u32 reserved2:1; +} __packed; + +/** + * struct ipu3_uapi_bnr_static_config_opt_center_sqr_config - BNR optical square + * + * @x_sqr_reset: Reset value of X^2. + * @y_sqr_reset: Reset value of Y^2. + * + * Please note: + * + * #. X and Y ref to + * &ipu3_uapi_bnr_static_config_opt_center_config + * #. Both structs are used in threshold formula to calculate r^2, where r + * is a radius of pixel [row, col] from centor of sensor. + */ +struct ipu3_uapi_bnr_static_config_opt_center_sqr_config { + __u32 x_sqr_reset; + __u32 y_sqr_reset; +} __packed; + +/** + * struct ipu3_uapi_bnr_static_config - BNR static config + * + * @wb_gains: white balance gains &ipu3_uapi_bnr_static_config_wb_gains_config + * @wb_gains_thr: white balance gains threshold as defined by + * &ipu3_uapi_bnr_static_config_wb_gains_thr_config + * @thr_coeffs: coefficients of threshold + * &ipu3_uapi_bnr_static_config_thr_coeffs_config + * @thr_ctrl_shd: control of shading threshold + * &ipu3_uapi_bnr_static_config_thr_ctrl_shd_config + * @opt_center: optical center &ipu3_uapi_bnr_static_config_opt_center_config + * + * Above parameters and opt_center_sqr are used for white balance and shading. + * + * @lut: lookup table &ipu3_uapi_bnr_static_config_lut_config + * @bp_ctrl: detect and remove bad pixels as defined in struct + * &ipu3_uapi_bnr_static_config_bp_ctrl_config + * @dn_detect_ctrl: detect and remove noise. + * &ipu3_uapi_bnr_static_config_dn_detect_ctrl_config + * @column_size: The number of pixels in column. + * @opt_center_sqr: Reset value of r^2 to optical center, see + * &ipu3_uapi_bnr_static_config_opt_center_sqr_config. + */ +struct ipu3_uapi_bnr_static_config { + struct ipu3_uapi_bnr_static_config_wb_gains_config wb_gains; + struct ipu3_uapi_bnr_static_config_wb_gains_thr_config wb_gains_thr; + struct ipu3_uapi_bnr_static_config_thr_coeffs_config thr_coeffs; + struct ipu3_uapi_bnr_static_config_thr_ctrl_shd_config thr_ctrl_shd; + struct ipu3_uapi_bnr_static_config_opt_center_config opt_center; + struct ipu3_uapi_bnr_static_config_lut_config lut; + struct ipu3_uapi_bnr_static_config_bp_ctrl_config bp_ctrl; + struct ipu3_uapi_bnr_static_config_dn_detect_ctrl_config dn_detect_ctrl; + __u32 column_size; + struct ipu3_uapi_bnr_static_config_opt_center_sqr_config opt_center_sqr; +} __packed; + +/** + * struct ipu3_uapi_bnr_static_config_green_disparity - Correct green disparity + * + * @gd_red: Shading gain coeff for gr disparity level in bright red region. + * Precision u0.6, default 4(0.0625). + * @reserved0: reserved + * @gd_green: Shading gain coeff for gr disparity level in bright green + * region. Precision u0.6, default 4(0.0625). + * @reserved1: reserved + * @gd_blue: Shading gain coeff for gr disparity level in bright blue region. + * Precision u0.6, default 4(0.0625). + * @reserved2: reserved + * @gd_black: Maximal green disparity level in dark region (stronger disparity + * assumed to be image detail). Precision u14, default 80. + * @reserved3: reserved + * @gd_shading: Change maximal green disparity level according to square + * distance from image center. + * @reserved4: reserved + * @gd_support: Lower bound for the number of second green color pixels in + * current pixel neighborhood with less than threshold difference + * from it. + * + * The shading gain coeff of red, green, blue and black are used to calculate + * threshold given a pixel's color value and its coordinates in the image. + * + * @reserved5: reserved + * @gd_clip: Turn green disparity clip on/off, [0, 1], default 1. + * @gd_central_weight: Central pixel weight in 9 pixels weighted sum. + */ +struct ipu3_uapi_bnr_static_config_green_disparity { + __u32 gd_red:6; + __u32 reserved0:2; + __u32 gd_green:6; + __u32 reserved1:2; + __u32 gd_blue:6; + __u32 reserved2:10; + __u32 gd_black:14; + __u32 reserved3:2; + __u32 gd_shading:7; + __u32 reserved4:1; + __u32 gd_support:2; + __u32 reserved5:1; + __u32 gd_clip:1; + __u32 gd_central_weight:4; +} __packed; + +/** + * struct ipu3_uapi_dm_config - De-mosaic parameters + * + * @dm_en: de-mosaic enable. + * @ch_ar_en: Checker artifacts removal enable flag. Default 0. + * @fcc_en: False color correction (FCC) enable flag. Default 0. + * @reserved0: reserved + * @frame_width: do not care + * @gamma_sc: Sharpening coefficient (coefficient of 2-d derivation of + * complementary color in Hamilton-Adams interpolation). + * u5, range [0, 31], default 8. + * @reserved1: reserved + * @lc_ctrl: Parameter that controls weights of Chroma Homogeneity metric + * in calculation of final homogeneity metric. + * u5, range [0, 31], default 7. + * @reserved2: reserved + * @cr_param1: First parameter that defines Checker artifact removal + * feature gain. Precision u5, range [0, 31], default 8. + * @reserved3: reserved + * @cr_param2: Second parameter that defines Checker artifact removal + * feature gain. Precision u5, range [0, 31], default 8. + * @reserved4: reserved + * @coring_param: Defines power of false color correction operation. + * low for preserving edge colors, high for preserving gray + * edge artifacts. + * Precision u1.4, range [0, 1.9375], default 4 (0.25). + * @reserved5: reserved + * + * The demosaic fixed function block is responsible to covert Bayer(mosaiced) + * images into color images based on demosaicing algorithm. + */ +struct ipu3_uapi_dm_config { + __u32 dm_en:1; + __u32 ch_ar_en:1; + __u32 fcc_en:1; + __u32 reserved0:13; + __u32 frame_width:16; + + __u32 gamma_sc:5; + __u32 reserved1:3; + __u32 lc_ctrl:5; + __u32 reserved2:3; + __u32 cr_param1:5; + __u32 reserved3:3; + __u32 cr_param2:5; + __u32 reserved4:3; + + __u32 coring_param:5; + __u32 reserved5:27; +} __packed; + +/** + * struct ipu3_uapi_ccm_mat_config - Color correction matrix + * + * @coeff_m11: CCM 3x3 coefficient, range [-65536, 65535] + * @coeff_m12: CCM 3x3 coefficient, range [-8192, 8191] + * @coeff_m13: CCM 3x3 coefficient, range [-32768, 32767] + * @coeff_o_r: Bias 3x1 coefficient, range [-8191, 8181] + * @coeff_m21: CCM 3x3 coefficient, range [-32767, 32767] + * @coeff_m22: CCM 3x3 coefficient, range [-8192, 8191] + * @coeff_m23: CCM 3x3 coefficient, range [-32768, 32767] + * @coeff_o_g: Bias 3x1 coefficient, range [-8191, 8181] + * @coeff_m31: CCM 3x3 coefficient, range [-32768, 32767] + * @coeff_m32: CCM 3x3 coefficient, range [-8192, 8191] + * @coeff_m33: CCM 3x3 coefficient, range [-32768, 32767] + * @coeff_o_b: Bias 3x1 coefficient, range [-8191, 8181] + * + * Transform sensor specific color space to standard sRGB by applying 3x3 matrix + * and adding a bias vector O. The transformation is basically a rotation and + * translation in the 3-dimensional color spaces. Here are the defaults: + * + * 9775, -2671, 1087, 0 + * -1071, 8303, 815, 0 + * -23, -7887, 16103, 0 + */ +struct ipu3_uapi_ccm_mat_config { + __s16 coeff_m11; + __s16 coeff_m12; + __s16 coeff_m13; + __s16 coeff_o_r; + __s16 coeff_m21; + __s16 coeff_m22; + __s16 coeff_m23; + __s16 coeff_o_g; + __s16 coeff_m31; + __s16 coeff_m32; + __s16 coeff_m33; + __s16 coeff_o_b; +} __packed; + +/** + * struct ipu3_uapi_gamma_corr_ctrl - Gamma correction + * + * @enable: gamma correction enable. + * @reserved: reserved + */ +struct ipu3_uapi_gamma_corr_ctrl { + __u32 enable:1; + __u32 reserved:31; +} __packed; + +/** + * struct ipu3_uapi_gamma_corr_lut - Per-pixel tone mapping implemented as LUT. + * + * @lut: 256 tabulated values of the gamma function. LUT[1].. LUT[256] + * format u13.0, range [0, 8191]. + * + * The tone mapping operation is done by a Piece wise linear graph + * that is implemented as a lookup table(LUT). The pixel component input + * intensity is the X-axis of the graph which is the table entry. + */ +struct ipu3_uapi_gamma_corr_lut { + __u16 lut[IPU3_UAPI_GAMMA_CORR_LUT_ENTRIES]; +} __packed; + +/** + * struct ipu3_uapi_gamma_config - Gamma config + * + * @gc_ctrl: control of gamma correction &ipu3_uapi_gamma_corr_ctrl + * @gc_lut: lookup table of gamma correction &ipu3_uapi_gamma_corr_lut + */ +struct ipu3_uapi_gamma_config { + struct ipu3_uapi_gamma_corr_ctrl gc_ctrl __attribute__((aligned(32))); + struct ipu3_uapi_gamma_corr_lut gc_lut __attribute__((aligned(32))); +} __packed; + +/** + * struct ipu3_uapi_csc_mat_config - Color space conversion matrix config + * + * @coeff_c11: Conversion matrix value, format s0.14, range [-16384, 16383]. + * @coeff_c12: Conversion matrix value, format s0.14, range [-8192, 8191]. + * @coeff_c13: Conversion matrix value, format s0.14, range [-16384, 16383]. + * @coeff_b1: Bias 3x1 coefficient, s13.0 range [-8192, 8191]. + * @coeff_c21: Conversion matrix value, format s0.14, range [-16384, 16383]. + * @coeff_c22: Conversion matrix value, format s0.14, range [-8192, 8191]. + * @coeff_c23: Conversion matrix value, format s0.14, range [-16384, 16383]. + * @coeff_b2: Bias 3x1 coefficient, s13.0 range [-8192, 8191]. + * @coeff_c31: Conversion matrix value, format s0.14, range [-16384, 16383]. + * @coeff_c32: Conversion matrix value, format s0.14, range [-8192, 8191]. + * @coeff_c33: Conversion matrix value, format s0.14, range [-16384, 16383]. + * @coeff_b3: Bias 3x1 coefficient, s13.0 range [-8192, 8191]. + * + * To transform each pixel from RGB to YUV (Y - brightness/luminance, + * UV -chroma) by applying the pixel's values by a 3x3 matrix and adding an + * optional bias 3x1 vector. Here are the default values for the matrix: + * + * 4898, 9617, 1867, 0, + * -2410, -4732, 7143, 0, + * 10076, -8437, -1638, 0, + * + * (i.e. for real number 0.299, 0.299 * 2^14 becomes 4898.) + */ +struct ipu3_uapi_csc_mat_config { + __s16 coeff_c11; + __s16 coeff_c12; + __s16 coeff_c13; + __s16 coeff_b1; + __s16 coeff_c21; + __s16 coeff_c22; + __s16 coeff_c23; + __s16 coeff_b2; + __s16 coeff_c31; + __s16 coeff_c32; + __s16 coeff_c33; + __s16 coeff_b3; +} __packed; + +/** + * struct ipu3_uapi_cds_params - Chroma down-scaling + * + * @ds_c00: range [0, 3] + * @ds_c01: range [0, 3] + * @ds_c02: range [0, 3] + * @ds_c03: range [0, 3] + * @ds_c10: range [0, 3] + * @ds_c11: range [0, 3] + * @ds_c12: range [0, 3] + * @ds_c13: range [0, 3] + * + * In case user does not provide, above 4x2 filter will use following defaults: + * 1, 3, 3, 1, + * 1, 3, 3, 1, + * + * @ds_nf: Normalization factor for Chroma output downscaling filter, + * range 0,4, default 2. + * @reserved0: reserved + * @csc_en: Color space conversion enable + * @uv_bin_output: 0: output YUV 4.2.0, 1: output YUV 4.2.2(default). + * @reserved1: reserved + */ +struct ipu3_uapi_cds_params { + __u32 ds_c00:2; + __u32 ds_c01:2; + __u32 ds_c02:2; + __u32 ds_c03:2; + __u32 ds_c10:2; + __u32 ds_c11:2; + __u32 ds_c12:2; + __u32 ds_c13:2; + __u32 ds_nf:5; + __u32 reserved0:3; + __u32 csc_en:1; + __u32 uv_bin_output:1; + __u32 reserved1:6; +} __packed; + +/** + * struct ipu3_uapi_shd_grid_config - Bayer shading(darkening) correction + * + * @width: Grid horizontal dimensions, u8, [8, 128], default 73 + * @height: Grid vertical dimensions, u8, [8, 128], default 56 + * @block_width_log2: Log2 of the width of the grid cell in pixel count + * u4, [0, 15], default value 5. + * @reserved0: reserved + * @block_height_log2: Log2 of the height of the grid cell in pixel count + * u4, [0, 15], default value 6. + * @reserved1: reserved + * @grid_height_per_slice: SHD_MAX_CELLS_PER_SET/width. + * (with SHD_MAX_CELLS_PER_SET = 146). + * @x_start: X value of top left corner of sensor relative to ROI + * s13, [-4096, 0], default 0, only negative values. + * @y_start: Y value of top left corner of sensor relative to ROI + * s13, [-4096, 0], default 0, only negative values. + */ +struct ipu3_uapi_shd_grid_config { + /* reg 0 */ + __u8 width; + __u8 height; + __u8 block_width_log2:3; + __u8 reserved0:1; + __u8 block_height_log2:3; + __u8 reserved1:1; + __u8 grid_height_per_slice; + /* reg 1 */ + __s16 x_start; + __s16 y_start; +} __packed; + +/** + * struct ipu3_uapi_shd_general_config - Shading general config + * + * @init_set_vrt_offst_ul: set vertical offset, + * y_start >> block_height_log2 % grid_height_per_slice. + * @shd_enable: shading enable. + * @gain_factor: Gain factor. Shift calculated anti shading value. Precision u2. + * 0x0 - gain factor [1, 5], means no shift interpolated value. + * 0x1 - gain factor [1, 9], means shift interpolated by 1. + * 0x2 - gain factor [1, 17], means shift interpolated by 2. + * @reserved: reserved + * + * Correction is performed by multiplying a gain factor for each of the 4 Bayer + * channels as a function of the pixel location in the sensor. + */ +struct ipu3_uapi_shd_general_config { + __u32 init_set_vrt_offst_ul:8; + __u32 shd_enable:1; + __u32 gain_factor:2; + __u32 reserved:21; +} __packed; + +/** + * struct ipu3_uapi_shd_black_level_config - Black level correction + * + * @bl_r: Bios values for green red. s11 range [-2048, 2047]. + * @bl_gr: Bios values for green blue. s11 range [-2048, 2047]. + * @bl_gb: Bios values for red. s11 range [-2048, 2047]. + * @bl_b: Bios values for blue. s11 range [-2048, 2047]. + */ +struct ipu3_uapi_shd_black_level_config { + __s16 bl_r; + __s16 bl_gr; + __s16 bl_gb; + __s16 bl_b; +} __packed; + +/** + * struct ipu3_uapi_shd_config_static - Shading config static + * + * @grid: shading grid config &ipu3_uapi_shd_grid_config + * @general: shading general config &ipu3_uapi_shd_general_config + * @black_level: black level config for shading correction as defined by + * &ipu3_uapi_shd_black_level_config + */ +struct ipu3_uapi_shd_config_static { + struct ipu3_uapi_shd_grid_config grid; + struct ipu3_uapi_shd_general_config general; + struct ipu3_uapi_shd_black_level_config black_level; +} __packed; + +/** + * struct ipu3_uapi_shd_lut - Shading gain factor lookup table. + * + * @sets: array + * @sets.r_and_gr: Red and GreenR Lookup table. + * @sets.r_and_gr.r: Red shading factor. + * @sets.r_and_gr.gr: GreenR shading factor. + * @sets.reserved1: reserved + * @sets.gb_and_b: GreenB and Blue Lookup table. + * @sets.gb_and_b.gb: GreenB shading factor. + * @sets.gb_and_b.b: Blue shading factor. + * @sets.reserved2: reserved + * + * Map to shading correction LUT register set. + */ +struct ipu3_uapi_shd_lut { + struct { + struct { + __u16 r; + __u16 gr; + } r_and_gr[IPU3_UAPI_SHD_MAX_CELLS_PER_SET]; + __u8 reserved1[24]; + struct { + __u16 gb; + __u16 b; + } gb_and_b[IPU3_UAPI_SHD_MAX_CELLS_PER_SET]; + __u8 reserved2[24]; + } sets[IPU3_UAPI_SHD_MAX_CFG_SETS]; +} __packed; + +/** + * struct ipu3_uapi_shd_config - Shading config + * + * @shd: shading static config, see &ipu3_uapi_shd_config_static + * @shd_lut: shading lookup table &ipu3_uapi_shd_lut + */ +struct ipu3_uapi_shd_config { + struct ipu3_uapi_shd_config_static shd __attribute__((aligned(32))); + struct ipu3_uapi_shd_lut shd_lut __attribute__((aligned(32))); +} __packed; + +/* Image Enhancement Filter directed */ + +/** + * struct ipu3_uapi_iefd_cux2 - IEFd Config Unit 2 parameters + * + * @x0: X0 point of Config Unit, u9.0, default 0. + * @x1: X1 point of Config Unit, u9.0, default 0. + * @a01: Slope A of Config Unit, s4.4, default 0. + * @b01: Slope B, always 0. + * + * Calculate weight for blending directed and non-directed denoise elements + * + * Note: + * Each instance of Config Unit needs X coordinate of n points and + * slope A factor between points calculated by driver based on calibration + * parameters. + * + * All CU inputs are unsigned, they will be converted to signed when written + * to register, i.e. a01 will be written to 9 bit register in s4.4 format. + * The data precision s4.4 means 4 bits for integer parts and 4 bits for the + * fractional part, the first bit indicates positive or negative value. + * For userspace software (commonly the imaging library), the computation for + * the CU slope values should be based on the slope resolution 1/16 (binary + * 0.0001 - the minimal interval value), the slope value range is [-256, +255]. + * This applies to &ipu3_uapi_iefd_cux6_ed, &ipu3_uapi_iefd_cux2_1, + * &ipu3_uapi_iefd_cux2_1, &ipu3_uapi_iefd_cux4 and &ipu3_uapi_iefd_cux6_rad. + */ +struct ipu3_uapi_iefd_cux2 { + __u32 x0:9; + __u32 x1:9; + __u32 a01:9; + __u32 b01:5; +} __packed; + +/** + * struct ipu3_uapi_iefd_cux6_ed - Calculate power of non-directed sharpening + * element, Config Unit 6 for edge detail (ED). + * + * @x0: X coordinate of point 0, u9.0, default 0. + * @x1: X coordinate of point 1, u9.0, default 0. + * @x2: X coordinate of point 2, u9.0, default 0. + * @reserved0: reserved + * @x3: X coordinate of point 3, u9.0, default 0. + * @x4: X coordinate of point 4, u9.0, default 0. + * @x5: X coordinate of point 5, u9.0, default 0. + * @reserved1: reserved + * @a01: slope A points 01, s4.4, default 0. + * @a12: slope A points 12, s4.4, default 0. + * @a23: slope A points 23, s4.4, default 0. + * @reserved2: reserved + * @a34: slope A points 34, s4.4, default 0. + * @a45: slope A points 45, s4.4, default 0. + * @reserved3: reserved + * @b01: slope B points 01, s4.4, default 0. + * @b12: slope B points 12, s4.4, default 0. + * @b23: slope B points 23, s4.4, default 0. + * @reserved4: reserved + * @b34: slope B points 34, s4.4, default 0. + * @b45: slope B points 45, s4.4, default 0. + * @reserved5: reserved. + */ +struct ipu3_uapi_iefd_cux6_ed { + __u32 x0:9; + __u32 x1:9; + __u32 x2:9; + __u32 reserved0:5; + + __u32 x3:9; + __u32 x4:9; + __u32 x5:9; + __u32 reserved1:5; + + __u32 a01:9; + __u32 a12:9; + __u32 a23:9; + __u32 reserved2:5; + + __u32 a34:9; + __u32 a45:9; + __u32 reserved3:14; + + __u32 b01:9; + __u32 b12:9; + __u32 b23:9; + __u32 reserved4:5; + + __u32 b34:9; + __u32 b45:9; + __u32 reserved5:14; +} __packed; + +/** + * struct ipu3_uapi_iefd_cux2_1 - Calculate power of non-directed denoise + * element apply. + * @x0: X0 point of Config Unit, u9.0, default 0. + * @x1: X1 point of Config Unit, u9.0, default 0. + * @a01: Slope A of Config Unit, s4.4, default 0. + * @reserved1: reserved + * @b01: offset B0 of Config Unit, u7.0, default 0. + * @reserved2: reserved + */ +struct ipu3_uapi_iefd_cux2_1 { + __u32 x0:9; + __u32 x1:9; + __u32 a01:9; + __u32 reserved1:5; + + __u32 b01:8; + __u32 reserved2:24; +} __packed; + +/** + * struct ipu3_uapi_iefd_cux4 - Calculate power of non-directed sharpening + * element. + * + * @x0: X0 point of Config Unit, u9.0, default 0. + * @x1: X1 point of Config Unit, u9.0, default 0. + * @x2: X2 point of Config Unit, u9.0, default 0. + * @reserved0: reserved + * @x3: X3 point of Config Unit, u9.0, default 0. + * @a01: Slope A0 of Config Unit, s4.4, default 0. + * @a12: Slope A1 of Config Unit, s4.4, default 0. + * @reserved1: reserved + * @a23: Slope A2 of Config Unit, s4.4, default 0. + * @b01: Offset B0 of Config Unit, s7.0, default 0. + * @b12: Offset B1 of Config Unit, s7.0, default 0. + * @reserved2: reserved + * @b23: Offset B2 of Config Unit, s7.0, default 0. + * @reserved3: reserved + */ +struct ipu3_uapi_iefd_cux4 { + __u32 x0:9; + __u32 x1:9; + __u32 x2:9; + __u32 reserved0:5; + + __u32 x3:9; + __u32 a01:9; + __u32 a12:9; + __u32 reserved1:5; + + __u32 a23:9; + __u32 b01:8; + __u32 b12:8; + __u32 reserved2:7; + + __u32 b23:8; + __u32 reserved3:24; +} __packed; + +/** + * struct ipu3_uapi_iefd_cux6_rad - Radial Config Unit (CU) + * + * @x0: x0 points of Config Unit radial, u8.0 + * @x1: x1 points of Config Unit radial, u8.0 + * @x2: x2 points of Config Unit radial, u8.0 + * @x3: x3 points of Config Unit radial, u8.0 + * @x4: x4 points of Config Unit radial, u8.0 + * @x5: x5 points of Config Unit radial, u8.0 + * @reserved1: reserved + * @a01: Slope A of Config Unit radial, s7.8 + * @a12: Slope A of Config Unit radial, s7.8 + * @a23: Slope A of Config Unit radial, s7.8 + * @a34: Slope A of Config Unit radial, s7.8 + * @a45: Slope A of Config Unit radial, s7.8 + * @reserved2: reserved + * @b01: Slope B of Config Unit radial, s9.0 + * @b12: Slope B of Config Unit radial, s9.0 + * @b23: Slope B of Config Unit radial, s9.0 + * @reserved4: reserved + * @b34: Slope B of Config Unit radial, s9.0 + * @b45: Slope B of Config Unit radial, s9.0 + * @reserved5: reserved + */ +struct ipu3_uapi_iefd_cux6_rad { + __u32 x0:8; + __u32 x1:8; + __u32 x2:8; + __u32 x3:8; + + __u32 x4:8; + __u32 x5:8; + __u32 reserved1:16; + + __u32 a01:16; + __u32 a12:16; + + __u32 a23:16; + __u32 a34:16; + + __u32 a45:16; + __u32 reserved2:16; + + __u32 b01:10; + __u32 b12:10; + __u32 b23:10; + __u32 reserved4:2; + + __u32 b34:10; + __u32 b45:10; + __u32 reserved5:12; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_iefd_cfg_units - IEFd Config Units parameters + * + * @cu_1: calculate weight for blending directed and + * non-directed denoise elements. See &ipu3_uapi_iefd_cux2 + * @cu_ed: calculate power of non-directed sharpening element, see + * &ipu3_uapi_iefd_cux6_ed + * @cu_3: calculate weight for blending directed and + * non-directed denoise elements. A &ipu3_uapi_iefd_cux2 + * @cu_5: calculate power of non-directed denoise element apply, use + * &ipu3_uapi_iefd_cux2_1 + * @cu_6: calculate power of non-directed sharpening element. See + * &ipu3_uapi_iefd_cux4 + * @cu_7: calculate weight for blending directed and + * non-directed denoise elements. Use &ipu3_uapi_iefd_cux2 + * @cu_unsharp: Config Unit of unsharp &ipu3_uapi_iefd_cux4 + * @cu_radial: Config Unit of radial &ipu3_uapi_iefd_cux6_rad + * @cu_vssnlm: Config Unit of vssnlm &ipu3_uapi_iefd_cux2 + */ +struct ipu3_uapi_yuvp1_iefd_cfg_units { + struct ipu3_uapi_iefd_cux2 cu_1; + struct ipu3_uapi_iefd_cux6_ed cu_ed; + struct ipu3_uapi_iefd_cux2 cu_3; + struct ipu3_uapi_iefd_cux2_1 cu_5; + struct ipu3_uapi_iefd_cux4 cu_6; + struct ipu3_uapi_iefd_cux2 cu_7; + struct ipu3_uapi_iefd_cux4 cu_unsharp; + struct ipu3_uapi_iefd_cux6_rad cu_radial; + struct ipu3_uapi_iefd_cux2 cu_vssnlm; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_iefd_config_s - IEFd config + * + * @horver_diag_coeff: Gradient compensation. Compared with vertical / + * horizontal (0 / 90 degree), coefficient of diagonal (45 / + * 135 degree) direction should be corrected by approx. + * 1/sqrt(2). + * @reserved0: reserved + * @clamp_stitch: Slope to stitch between clamped and unclamped edge values + * @reserved1: reserved + * @direct_metric_update: Update coeff for direction metric + * @reserved2: reserved + * @ed_horver_diag_coeff: Radial Coefficient that compensates for + * different distance for vertical/horizontal and + * diagonal gradient calculation (approx. 1/sqrt(2)) + * @reserved3: reserved + */ +struct ipu3_uapi_yuvp1_iefd_config_s { + __u32 horver_diag_coeff:7; + __u32 reserved0:1; + __u32 clamp_stitch:6; + __u32 reserved1:2; + __u32 direct_metric_update:5; + __u32 reserved2:3; + __u32 ed_horver_diag_coeff:7; + __u32 reserved3:1; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_iefd_control - IEFd control + * + * @iefd_en: Enable IEFd + * @denoise_en: Enable denoise + * @direct_smooth_en: Enable directional smooth + * @rad_en: Enable radial update + * @vssnlm_en: Enable VSSNLM output filter + * @reserved: reserved + */ +struct ipu3_uapi_yuvp1_iefd_control { + __u32 iefd_en:1; + __u32 denoise_en:1; + __u32 direct_smooth_en:1; + __u32 rad_en:1; + __u32 vssnlm_en:1; + __u32 reserved:27; +} __packed; + +/** + * struct ipu3_uapi_sharp_cfg - Sharpening config + * + * @nega_lmt_txt: Sharpening limit for negative overshoots for texture. + * @reserved0: reserved + * @posi_lmt_txt: Sharpening limit for positive overshoots for texture. + * @reserved1: reserved + * @nega_lmt_dir: Sharpening limit for negative overshoots for direction (edge). + * @reserved2: reserved + * @posi_lmt_dir: Sharpening limit for positive overshoots for direction (edge). + * @reserved3: reserved + * + * Fixed point type u13.0, range [0, 8191]. + */ +struct ipu3_uapi_sharp_cfg { + __u32 nega_lmt_txt:13; + __u32 reserved0:19; + __u32 posi_lmt_txt:13; + __u32 reserved1:19; + __u32 nega_lmt_dir:13; + __u32 reserved2:19; + __u32 posi_lmt_dir:13; + __u32 reserved3:19; +} __packed; + +/** + * struct ipu3_uapi_far_w - Sharpening config for far sub-group + * + * @dir_shrp: Weight of wide direct sharpening, u1.6, range [0, 64], default 64. + * @reserved0: reserved + * @dir_dns: Weight of wide direct denoising, u1.6, range [0, 64], default 0. + * @reserved1: reserved + * @ndir_dns_powr: Power of non-direct denoising, + * Precision u1.6, range [0, 64], default 64. + * @reserved2: reserved + */ +struct ipu3_uapi_far_w { + __u32 dir_shrp:7; + __u32 reserved0:1; + __u32 dir_dns:7; + __u32 reserved1:1; + __u32 ndir_dns_powr:7; + __u32 reserved2:9; +} __packed; + +/** + * struct ipu3_uapi_unsharp_cfg - Unsharp config + * + * @unsharp_weight: Unsharp mask blending weight. + * u1.6, range [0, 64], default 16. + * 0 - disabled, 64 - use only unsharp. + * @reserved0: reserved + * @unsharp_amount: Unsharp mask amount, u4.5, range [0, 511], default 0. + * @reserved1: reserved + */ +struct ipu3_uapi_unsharp_cfg { + __u32 unsharp_weight:7; + __u32 reserved0:1; + __u32 unsharp_amount:9; + __u32 reserved1:15; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_iefd_shrp_cfg - IEFd sharpness config + * + * @cfg: sharpness config &ipu3_uapi_sharp_cfg + * @far_w: wide range config, value as specified by &ipu3_uapi_far_w: + * The 5x5 environment is separated into 2 sub-groups, the 3x3 nearest + * neighbors (8 pixels called Near), and the second order neighborhood + * around them (16 pixels called Far). + * @unshrp_cfg: unsharpness config. &ipu3_uapi_unsharp_cfg + */ +struct ipu3_uapi_yuvp1_iefd_shrp_cfg { + struct ipu3_uapi_sharp_cfg cfg; + struct ipu3_uapi_far_w far_w; + struct ipu3_uapi_unsharp_cfg unshrp_cfg; +} __packed; + +/** + * struct ipu3_uapi_unsharp_coef0 - Unsharp mask coefficients + * + * @c00: Coeff11, s0.8, range [-255, 255], default 1. + * @c01: Coeff12, s0.8, range [-255, 255], default 5. + * @c02: Coeff13, s0.8, range [-255, 255], default 9. + * @reserved: reserved + * + * Configurable registers for common sharpening support. + */ +struct ipu3_uapi_unsharp_coef0 { + __u32 c00:9; + __u32 c01:9; + __u32 c02:9; + __u32 reserved:5; +} __packed; + +/** + * struct ipu3_uapi_unsharp_coef1 - Unsharp mask coefficients + * + * @c11: Coeff22, s0.8, range [-255, 255], default 29. + * @c12: Coeff23, s0.8, range [-255, 255], default 55. + * @c22: Coeff33, s0.8, range [-255, 255], default 96. + * @reserved: reserved + */ +struct ipu3_uapi_unsharp_coef1 { + __u32 c11:9; + __u32 c12:9; + __u32 c22:9; + __u32 reserved:5; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_iefd_unshrp_cfg - Unsharp mask config + * + * @unsharp_coef0: unsharp coefficient 0 config. See &ipu3_uapi_unsharp_coef0 + * @unsharp_coef1: unsharp coefficient 1 config. See &ipu3_uapi_unsharp_coef1 + */ +struct ipu3_uapi_yuvp1_iefd_unshrp_cfg { + struct ipu3_uapi_unsharp_coef0 unsharp_coef0; + struct ipu3_uapi_unsharp_coef1 unsharp_coef1; +} __packed; + +/** + * struct ipu3_uapi_radial_reset_xy - Radial coordinate reset + * + * @x: Radial reset of x coordinate. Precision s12, [-4095, 4095], default 0. + * @reserved0: reserved + * @y: Radial center y coordinate. Precision s12, [-4095, 4095], default 0. + * @reserved1: reserved + */ +struct ipu3_uapi_radial_reset_xy { + __s32 x:13; + __u32 reserved0:3; + __s32 y:13; + __u32 reserved1:3; +} __packed; + +/** + * struct ipu3_uapi_radial_reset_x2 - Radial X^2 reset + * + * @x2: Radial reset of x^2 coordinate. Precision u24, default 0. + * @reserved: reserved + */ +struct ipu3_uapi_radial_reset_x2 { + __u32 x2:24; + __u32 reserved:8; +} __packed; + +/** + * struct ipu3_uapi_radial_reset_y2 - Radial Y^2 reset + * + * @y2: Radial reset of y^2 coordinate. Precision u24, default 0. + * @reserved: reserved + */ +struct ipu3_uapi_radial_reset_y2 { + __u32 y2:24; + __u32 reserved:8; +} __packed; + +/** + * struct ipu3_uapi_radial_cfg - Radial config + * + * @rad_nf: Radial. R^2 normalization factor is scale down by 2^ - (15 + scale) + * @reserved0: reserved + * @rad_inv_r2: Radial R^-2 normelized to (0.5..1). + * Precision u7, range [0, 127]. + * @reserved1: reserved + */ +struct ipu3_uapi_radial_cfg { + __u32 rad_nf:4; + __u32 reserved0:4; + __u32 rad_inv_r2:7; + __u32 reserved1:17; +} __packed; + +/** + * struct ipu3_uapi_rad_far_w - Radial FAR sub-group + * + * @rad_dir_far_sharp_w: Weight of wide direct sharpening, u1.6, range [0, 64], + * default 64. + * @rad_dir_far_dns_w: Weight of wide direct denoising, u1.6, range [0, 64], + * default 0. + * @rad_ndir_far_dns_power: power of non-direct sharpening, u1.6, range [0, 64], + * default 0. + * @reserved: reserved + */ +struct ipu3_uapi_rad_far_w { + __u32 rad_dir_far_sharp_w:8; + __u32 rad_dir_far_dns_w:8; + __u32 rad_ndir_far_dns_power:8; + __u32 reserved:8; +} __packed; + +/** + * struct ipu3_uapi_cu_cfg0 - Radius Config Unit cfg0 register + * + * @cu6_pow: Power of CU6. Power of non-direct sharpening, u3.4. + * @reserved0: reserved + * @cu_unsharp_pow: Power of unsharp mask, u2.4. + * @reserved1: reserved + * @rad_cu6_pow: Radial/corner CU6. Directed sharpening power, u3.4. + * @reserved2: reserved + * @rad_cu_unsharp_pow: Radial power of unsharp mask, u2.4. + * @reserved3: reserved + */ +struct ipu3_uapi_cu_cfg0 { + __u32 cu6_pow:7; + __u32 reserved0:1; + __u32 cu_unsharp_pow:7; + __u32 reserved1:1; + __u32 rad_cu6_pow:7; + __u32 reserved2:1; + __u32 rad_cu_unsharp_pow:6; + __u32 reserved3:2; +} __packed; + +/** + * struct ipu3_uapi_cu_cfg1 - Radius Config Unit cfg1 register + * + * @rad_cu6_x1: X1 point of Config Unit 6, precision u9.0. + * @reserved0: reserved + * @rad_cu_unsharp_x1: X1 point for Config Unit unsharp for radial/corner point + * precision u9.0. + * @reserved1: reserved + */ +struct ipu3_uapi_cu_cfg1 { + __u32 rad_cu6_x1:9; + __u32 reserved0:1; + __u32 rad_cu_unsharp_x1:9; + __u32 reserved1:13; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_iefd_rad_cfg - IEFd parameters changed radially over + * the picture plane. + * + * @reset_xy: reset xy value in radial calculation. &ipu3_uapi_radial_reset_xy + * @reset_x2: reset x square value in radial calculation. See struct + * &ipu3_uapi_radial_reset_x2 + * @reset_y2: reset y square value in radial calculation. See struct + * &ipu3_uapi_radial_reset_y2 + * @cfg: radial config defined in &ipu3_uapi_radial_cfg + * @rad_far_w: weight for wide range radial. &ipu3_uapi_rad_far_w + * @cu_cfg0: configuration unit 0. See &ipu3_uapi_cu_cfg0 + * @cu_cfg1: configuration unit 1. See &ipu3_uapi_cu_cfg1 + */ +struct ipu3_uapi_yuvp1_iefd_rad_cfg { + struct ipu3_uapi_radial_reset_xy reset_xy; + struct ipu3_uapi_radial_reset_x2 reset_x2; + struct ipu3_uapi_radial_reset_y2 reset_y2; + struct ipu3_uapi_radial_cfg cfg; + struct ipu3_uapi_rad_far_w rad_far_w; + struct ipu3_uapi_cu_cfg0 cu_cfg0; + struct ipu3_uapi_cu_cfg1 cu_cfg1; +} __packed; + +/* Vssnlm - Very small scale non-local mean algorithm */ + +/** + * struct ipu3_uapi_vss_lut_x - Vssnlm LUT x0/x1/x2 + * + * @vs_x0: Vssnlm LUT x0, precision u8, range [0, 255], default 16. + * @vs_x1: Vssnlm LUT x1, precision u8, range [0, 255], default 32. + * @vs_x2: Vssnlm LUT x2, precision u8, range [0, 255], default 64. + * @reserved2: reserved + */ +struct ipu3_uapi_vss_lut_x { + __u32 vs_x0:8; + __u32 vs_x1:8; + __u32 vs_x2:8; + __u32 reserved2:8; +} __packed; + +/** + * struct ipu3_uapi_vss_lut_y - Vssnlm LUT y0/y1/y2 + * + * @vs_y1: Vssnlm LUT y1, precision u4, range [0, 8], default 1. + * @reserved0: reserved + * @vs_y2: Vssnlm LUT y2, precision u4, range [0, 8], default 3. + * @reserved1: reserved + * @vs_y3: Vssnlm LUT y3, precision u4, range [0, 8], default 8. + * @reserved2: reserved + */ +struct ipu3_uapi_vss_lut_y { + __u32 vs_y1:4; + __u32 reserved0:4; + __u32 vs_y2:4; + __u32 reserved1:4; + __u32 vs_y3:4; + __u32 reserved2:12; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_iefd_vssnlm_cfg - IEFd Vssnlm Lookup table + * + * @vss_lut_x: vss lookup table. See &ipu3_uapi_vss_lut_x description + * @vss_lut_y: vss lookup table. See &ipu3_uapi_vss_lut_y description + */ +struct ipu3_uapi_yuvp1_iefd_vssnlm_cfg { + struct ipu3_uapi_vss_lut_x vss_lut_x; + struct ipu3_uapi_vss_lut_y vss_lut_y; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_iefd_config - IEFd config + * + * @units: configuration unit setting, &ipu3_uapi_yuvp1_iefd_cfg_units + * @config: configuration, as defined by &ipu3_uapi_yuvp1_iefd_config_s + * @control: control setting, as defined by &ipu3_uapi_yuvp1_iefd_control + * @sharp: sharpness setting, as defined by &ipu3_uapi_yuvp1_iefd_shrp_cfg + * @unsharp: unsharpness setting, as defined by &ipu3_uapi_yuvp1_iefd_unshrp_cfg + * @rad: radial setting, as defined by &ipu3_uapi_yuvp1_iefd_rad_cfg + * @vsslnm: vsslnm setting, as defined by &ipu3_uapi_yuvp1_iefd_vssnlm_cfg + */ +struct ipu3_uapi_yuvp1_iefd_config { + struct ipu3_uapi_yuvp1_iefd_cfg_units units; + struct ipu3_uapi_yuvp1_iefd_config_s config; + struct ipu3_uapi_yuvp1_iefd_control control; + struct ipu3_uapi_yuvp1_iefd_shrp_cfg sharp; + struct ipu3_uapi_yuvp1_iefd_unshrp_cfg unsharp; + struct ipu3_uapi_yuvp1_iefd_rad_cfg rad; + struct ipu3_uapi_yuvp1_iefd_vssnlm_cfg vsslnm; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_yds_config - Y Down-Sampling config + * + * @c00: range [0, 3], default 0x0 + * @c01: range [0, 3], default 0x1 + * @c02: range [0, 3], default 0x1 + * @c03: range [0, 3], default 0x0 + * @c10: range [0, 3], default 0x0 + * @c11: range [0, 3], default 0x1 + * @c12: range [0, 3], default 0x1 + * @c13: range [0, 3], default 0x0 + * + * Above are 4x2 filter coefficients for chroma output downscaling. + * + * @norm_factor: Normalization factor, range [0, 4], default 2 + * 0 - divide by 1 + * 1 - divide by 2 + * 2 - divide by 4 + * 3 - divide by 8 + * 4 - divide by 16 + * @reserved0: reserved + * @bin_output: Down sampling on Luma channel in two optional modes + * 0 - Bin output 4.2.0 (default), 1 output 4.2.2. + * @reserved1: reserved + */ +struct ipu3_uapi_yuvp1_yds_config { + __u32 c00:2; + __u32 c01:2; + __u32 c02:2; + __u32 c03:2; + __u32 c10:2; + __u32 c11:2; + __u32 c12:2; + __u32 c13:2; + __u32 norm_factor:5; + __u32 reserved0:4; + __u32 bin_output:1; + __u32 reserved1:6; +} __packed; + +/* Chroma Noise Reduction */ + +/** + * struct ipu3_uapi_yuvp1_chnr_enable_config - Chroma noise reduction enable + * + * @enable: enable/disable chroma noise reduction + * @yuv_mode: 0 - YUV420, 1 - YUV422 + * @reserved0: reserved + * @col_size: number of columns in the frame, max width is 2560 + * @reserved1: reserved + */ +struct ipu3_uapi_yuvp1_chnr_enable_config { + __u32 enable:1; + __u32 yuv_mode:1; + __u32 reserved0:14; + __u32 col_size:12; + __u32 reserved1:4; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_chnr_coring_config - Coring thresholds for UV + * + * @u: U coring level, u0.13, range [0.0, 1.0], default 0.0 + * @reserved0: reserved + * @v: V coring level, u0.13, range [0.0, 1.0], default 0.0 + * @reserved1: reserved + */ +struct ipu3_uapi_yuvp1_chnr_coring_config { + __u32 u:13; + __u32 reserved0:3; + __u32 v:13; + __u32 reserved1:3; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_chnr_sense_gain_config - Chroma noise reduction gains + * + * All sensitivity gain parameters have precision u13.0, range [0, 8191]. + * + * @vy: Sensitivity of horizontal edge of Y, default 100 + * @vu: Sensitivity of horizontal edge of U, default 100 + * @vv: Sensitivity of horizontal edge of V, default 100 + * @reserved0: reserved + * @hy: Sensitivity of vertical edge of Y, default 50 + * @hu: Sensitivity of vertical edge of U, default 50 + * @hv: Sensitivity of vertical edge of V, default 50 + * @reserved1: reserved + */ +struct ipu3_uapi_yuvp1_chnr_sense_gain_config { + __u32 vy:8; + __u32 vu:8; + __u32 vv:8; + __u32 reserved0:8; + + __u32 hy:8; + __u32 hu:8; + __u32 hv:8; + __u32 reserved1:8; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_chnr_iir_fir_config - Chroma IIR/FIR filter config + * + * @fir_0h: Value of center tap in horizontal FIR, range [0, 32], default 8. + * @reserved0: reserved + * @fir_1h: Value of distance 1 in horizontal FIR, range [0, 32], default 12. + * @reserved1: reserved + * @fir_2h: Value of distance 2 tap in horizontal FIR, range [0, 32], default 0. + * @dalpha_clip_val: weight for previous row in IIR, range [1, 256], default 0. + * @reserved2: reserved + */ +struct ipu3_uapi_yuvp1_chnr_iir_fir_config { + __u32 fir_0h:6; + __u32 reserved0:2; + __u32 fir_1h:6; + __u32 reserved1:2; + __u32 fir_2h:6; + __u32 dalpha_clip_val:9; + __u32 reserved2:1; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_chnr_config - Chroma noise reduction config + * + * @enable: chroma noise reduction enable, see + * &ipu3_uapi_yuvp1_chnr_enable_config + * @coring: coring config for chroma noise reduction, see + * &ipu3_uapi_yuvp1_chnr_coring_config + * @sense_gain: sensitivity config for chroma noise reduction, see + * ipu3_uapi_yuvp1_chnr_sense_gain_config + * @iir_fir: iir and fir config for chroma noise reduction, see + * ipu3_uapi_yuvp1_chnr_iir_fir_config + */ +struct ipu3_uapi_yuvp1_chnr_config { + struct ipu3_uapi_yuvp1_chnr_enable_config enable; + struct ipu3_uapi_yuvp1_chnr_coring_config coring; + struct ipu3_uapi_yuvp1_chnr_sense_gain_config sense_gain; + struct ipu3_uapi_yuvp1_chnr_iir_fir_config iir_fir; +} __packed; + +/* Edge Enhancement and Noise Reduction */ + +/** + * struct ipu3_uapi_yuvp1_y_ee_nr_lpf_config - Luma(Y) edge enhancement low-pass + * filter coefficients + * + * @a_diag: Smoothing diagonal coefficient, u5.0. + * @reserved0: reserved + * @a_periph: Image smoothing perpherial, u5.0. + * @reserved1: reserved + * @a_cent: Image Smoothing center coefficient, u5.0. + * @reserved2: reserved + * @enable: 0: Y_EE_NR disabled, output = input; 1: Y_EE_NR enabled. + */ +struct ipu3_uapi_yuvp1_y_ee_nr_lpf_config { + __u32 a_diag:5; + __u32 reserved0:3; + __u32 a_periph:5; + __u32 reserved1:3; + __u32 a_cent:5; + __u32 reserved2:9; + __u32 enable:1; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_y_ee_nr_sense_config - Luma(Y) edge enhancement + * noise reduction sensitivity gains + * + * @edge_sense_0: Sensitivity of edge in dark area. u13.0, default 8191. + * @reserved0: reserved + * @delta_edge_sense: Difference in the sensitivity of edges between + * the bright and dark areas. u13.0, default 0. + * @reserved1: reserved + * @corner_sense_0: Sensitivity of corner in dark area. u13.0, default 0. + * @reserved2: reserved + * @delta_corner_sense: Difference in the sensitivity of corners between + * the bright and dark areas. u13.0, default 8191. + * @reserved3: reserved + */ +struct ipu3_uapi_yuvp1_y_ee_nr_sense_config { + __u32 edge_sense_0:13; + __u32 reserved0:3; + __u32 delta_edge_sense:13; + __u32 reserved1:3; + __u32 corner_sense_0:13; + __u32 reserved2:3; + __u32 delta_corner_sense:13; + __u32 reserved3:3; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_y_ee_nr_gain_config - Luma(Y) edge enhancement + * noise reduction gain config + * + * @gain_pos_0: Gain for positive edge in dark area. u5.0, [0, 16], default 2. + * @reserved0: reserved + * @delta_gain_posi: Difference in the gain of edges between the bright and + * dark areas for positive edges. u5.0, [0, 16], default 0. + * @reserved1: reserved + * @gain_neg_0: Gain for negative edge in dark area. u5.0, [0, 16], default 8. + * @reserved2: reserved + * @delta_gain_neg: Difference in the gain of edges between the bright and + * dark areas for negative edges. u5.0, [0, 16], default 0. + * @reserved3: reserved + */ +struct ipu3_uapi_yuvp1_y_ee_nr_gain_config { + __u32 gain_pos_0:5; + __u32 reserved0:3; + __u32 delta_gain_posi:5; + __u32 reserved1:3; + __u32 gain_neg_0:5; + __u32 reserved2:3; + __u32 delta_gain_neg:5; + __u32 reserved3:3; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_y_ee_nr_clip_config - Luma(Y) edge enhancement + * noise reduction clipping config + * + * @clip_pos_0: Limit of positive edge in dark area + * u5, value [0, 16], default 8. + * @reserved0: reserved + * @delta_clip_posi: Difference in the limit of edges between the bright + * and dark areas for positive edges. + * u5, value [0, 16], default 8. + * @reserved1: reserved + * @clip_neg_0: Limit of negative edge in dark area + * u5, value [0, 16], default 8. + * @reserved2: reserved + * @delta_clip_neg: Difference in the limit of edges between the bright + * and dark areas for negative edges. + * u5, value [0, 16], default 8. + * @reserved3: reserved + */ +struct ipu3_uapi_yuvp1_y_ee_nr_clip_config { + __u32 clip_pos_0:5; + __u32 reserved0:3; + __u32 delta_clip_posi:5; + __u32 reserved1:3; + __u32 clip_neg_0:5; + __u32 reserved2:3; + __u32 delta_clip_neg:5; + __u32 reserved3:3; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_y_ee_nr_frng_config - Luma(Y) edge enhancement + * noise reduction fringe config + * + * @gain_exp: Common exponent of gains, u4, [0, 8], default 2. + * @reserved0: reserved + * @min_edge: Threshold for edge and smooth stitching, u13. + * @reserved1: reserved + * @lin_seg_param: Power of LinSeg, u4. + * @reserved2: reserved + * @t1: Parameter for enabling/disabling the edge enhancement, u1.0, [0, 1], + * default 1. + * @t2: Parameter for enabling/disabling the smoothing, u1.0, [0, 1], + * default 1. + * @reserved3: reserved + */ +struct ipu3_uapi_yuvp1_y_ee_nr_frng_config { + __u32 gain_exp:4; + __u32 reserved0:28; + __u32 min_edge:13; + __u32 reserved1:3; + __u32 lin_seg_param:4; + __u32 reserved2:4; + __u32 t1:1; + __u32 t2:1; + __u32 reserved3:6; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_y_ee_nr_diag_config - Luma(Y) edge enhancement + * noise reduction diagonal config + * + * @diag_disc_g: Coefficient that prioritize diagonal edge direction on + * horizontal or vertical for final enhancement. + * u4.0, [1, 15], default 1. + * @reserved0: reserved + * @hvw_hor: Weight of horizontal/vertical edge enhancement for hv edge. + * u2.2, [1, 15], default 4. + * @dw_hor: Weight of diagonal edge enhancement for hv edge. + * u2.2, [1, 15], default 1. + * @hvw_diag: Weight of horizontal/vertical edge enhancement for diagonal edge. + * u2.2, [1, 15], default 1. + * @dw_diag: Weight of diagonal edge enhancement for diagonal edge. + * u2.2, [1, 15], default 4. + * @reserved1: reserved + */ +struct ipu3_uapi_yuvp1_y_ee_nr_diag_config { + __u32 diag_disc_g:4; + __u32 reserved0:4; + __u32 hvw_hor:4; + __u32 dw_hor:4; + __u32 hvw_diag:4; + __u32 dw_diag:4; + __u32 reserved1:8; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config - Luma(Y) edge enhancement + * noise reduction false color correction (FCC) coring config + * + * @pos_0: Gain for positive edge in dark, u13.0, [0, 16], default 0. + * @reserved0: reserved + * @pos_delta: Gain for positive edge in bright, value: pos_0 + pos_delta <=16 + * u13.0, default 0. + * @reserved1: reserved + * @neg_0: Gain for negative edge in dark area, u13.0, range [0, 16], default 0. + * @reserved2: reserved + * @neg_delta: Gain for negative edge in bright area. neg_0 + neg_delta <=16 + * u13.0, default 0. + * @reserved3: reserved + * + * Coring is a simple soft thresholding technique. + */ +struct ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config { + __u32 pos_0:13; + __u32 reserved0:3; + __u32 pos_delta:13; + __u32 reserved1:3; + __u32 neg_0:13; + __u32 reserved2:3; + __u32 neg_delta:13; + __u32 reserved3:3; +} __packed; + +/** + * struct ipu3_uapi_yuvp1_y_ee_nr_config - Edge enhancement and noise reduction + * + * @lpf: low-pass filter config. See &ipu3_uapi_yuvp1_y_ee_nr_lpf_config + * @sense: sensitivity config. See &ipu3_uapi_yuvp1_y_ee_nr_sense_config + * @gain: gain config as defined in &ipu3_uapi_yuvp1_y_ee_nr_gain_config + * @clip: clip config as defined in &ipu3_uapi_yuvp1_y_ee_nr_clip_config + * @frng: fringe config as defined in &ipu3_uapi_yuvp1_y_ee_nr_frng_config + * @diag: diagonal edge config. See &ipu3_uapi_yuvp1_y_ee_nr_diag_config + * @fc_coring: coring config for fringe control. See + * &ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config + */ +struct ipu3_uapi_yuvp1_y_ee_nr_config { + struct ipu3_uapi_yuvp1_y_ee_nr_lpf_config lpf; + struct ipu3_uapi_yuvp1_y_ee_nr_sense_config sense; + struct ipu3_uapi_yuvp1_y_ee_nr_gain_config gain; + struct ipu3_uapi_yuvp1_y_ee_nr_clip_config clip; + struct ipu3_uapi_yuvp1_y_ee_nr_frng_config frng; + struct ipu3_uapi_yuvp1_y_ee_nr_diag_config diag; + struct ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config fc_coring; +} __packed; + +/* Total Color Correction */ + +/** + * struct ipu3_uapi_yuvp2_tcc_gen_control_static_config - Total color correction + * general control config + * + * @en: 0 - TCC disabled. Output = input 1 - TCC enabled. + * @blend_shift: blend shift, Range[3, 4], default NA. + * @gain_according_to_y_only: 0: Gain is calculated according to YUV, + * 1: Gain is calculated according to Y only + * @reserved0: reserved + * @gamma: Final blending coefficients. Values[-16, 16], default NA. + * @reserved1: reserved + * @delta: Final blending coefficients. Values[-16, 16], default NA. + * @reserved2: reserved + */ +struct ipu3_uapi_yuvp2_tcc_gen_control_static_config { + __u32 en:1; + __u32 blend_shift:3; + __u32 gain_according_to_y_only:1; + __u32 reserved0:11; + __s32 gamma:5; + __u32 reserved1:3; + __s32 delta:5; + __u32 reserved2:3; +} __packed; + +/** + * struct ipu3_uapi_yuvp2_tcc_macc_elem_static_config - Total color correction + * multi-axis color control (MACC) config + * + * @a: a coefficient for 2x2 MACC conversion matrix. + * @reserved0: reserved + * @b: b coefficient 2x2 MACC conversion matrix. + * @reserved1: reserved + * @c: c coefficient for 2x2 MACC conversion matrix. + * @reserved2: reserved + * @d: d coefficient for 2x2 MACC conversion matrix. + * @reserved3: reserved + */ +struct ipu3_uapi_yuvp2_tcc_macc_elem_static_config { + __s32 a:12; + __u32 reserved0:4; + __s32 b:12; + __u32 reserved1:4; + __s32 c:12; + __u32 reserved2:4; + __s32 d:12; + __u32 reserved3:4; +} __packed; + +/** + * struct ipu3_uapi_yuvp2_tcc_macc_table_static_config - Total color correction + * multi-axis color control (MACC) table array + * + * @entries: config for multi axis color correction, as specified by + * &ipu3_uapi_yuvp2_tcc_macc_elem_static_config + */ +struct ipu3_uapi_yuvp2_tcc_macc_table_static_config { + struct ipu3_uapi_yuvp2_tcc_macc_elem_static_config + entries[IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS]; +} __packed; + +/** + * struct ipu3_uapi_yuvp2_tcc_inv_y_lut_static_config - Total color correction + * inverse y lookup table + * + * @entries: lookup table for inverse y estimation, and use it to estimate the + * ratio between luma and chroma. Chroma by approximate the absolute + * value of the radius on the chroma plane (R = sqrt(u^2+v^2) ) and + * luma by approximate by 1/Y. + */ +struct ipu3_uapi_yuvp2_tcc_inv_y_lut_static_config { + __u16 entries[IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS]; +} __packed; + +/** + * struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config - Total color + * correction lookup table for PCWL + * + * @entries: lookup table for gain piece wise linear transformation (PCWL) + */ +struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config { + __u16 entries[IPU3_UAPI_YUVP2_TCC_GAIN_PCWL_LUT_ELEMENTS]; +} __packed; + +/** + * struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config - Total color correction + * lookup table for r square root + * + * @entries: lookup table for r square root estimation + */ +struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config { + __s16 entries[IPU3_UAPI_YUVP2_TCC_R_SQR_LUT_ELEMENTS]; +} __packed; + +/** + * struct ipu3_uapi_yuvp2_tcc_static_config- Total color correction static + * + * @gen_control: general config for Total Color Correction + * @macc_table: config for multi axis color correction + * @inv_y_lut: lookup table for inverse y estimation + * @gain_pcwl: lookup table for gain PCWL + * @r_sqr_lut: lookup table for r square root estimation. + */ +struct ipu3_uapi_yuvp2_tcc_static_config { + struct ipu3_uapi_yuvp2_tcc_gen_control_static_config gen_control; + struct ipu3_uapi_yuvp2_tcc_macc_table_static_config macc_table; + struct ipu3_uapi_yuvp2_tcc_inv_y_lut_static_config inv_y_lut; + struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config gain_pcwl; + struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config r_sqr_lut; +} __packed; + +/* Advanced Noise Reduction related structs */ + +/* + * struct ipu3_uapi_anr_alpha - Advanced noise reduction alpha + * + * Tunable parameters that are subject to modification according to the + * total gain used. + */ +struct ipu3_uapi_anr_alpha { + __u16 gr; + __u16 r; + __u16 b; + __u16 gb; + __u16 dc_gr; + __u16 dc_r; + __u16 dc_b; + __u16 dc_gb; +} __packed; + +/* + * struct ipu3_uapi_anr_beta - Advanced noise reduction beta + * + * Tunable parameters that are subject to modification according to the + * total gain used. + */ +struct ipu3_uapi_anr_beta { + __u16 beta_gr; + __u16 beta_r; + __u16 beta_b; + __u16 beta_gb; +} __packed; + +/* + * struct ipu3_uapi_anr_plane_color - Advanced noise reduction per plane R, Gr, + * Gb and B register settings + * + * Tunable parameters that are subject to modification according to the + * total gain used. + */ +struct ipu3_uapi_anr_plane_color { + __u16 reg_w_gr[16]; + __u16 reg_w_r[16]; + __u16 reg_w_b[16]; + __u16 reg_w_gb[16]; +} __packed; + +/** + * struct ipu3_uapi_anr_transform_config - Advanced noise reduction transform + * + * @enable: advanced noise reduction enabled. + * @adaptive_treshhold_en: On IPU3, adaptive threshold is always enabled. + * @reserved1: reserved + * @reserved2: reserved + * @alpha: using following defaults: + * 13, 13, 13, 13, 0, 0, 0, 0 + * 11, 11, 11, 11, 0, 0, 0, 0 + * 14, 14, 14, 14, 0, 0, 0, 0 + * @beta: use following defaults: + * 24, 24, 24, 24 + * 21, 20, 20, 21 + * 25, 25, 25, 25 + * @color: use defaults defined in driver/media/pci/intel/ipu3-tables.c + * @sqrt_lut: 11 bits per element, values = + * [724 768 810 849 887 + * 923 958 991 1024 1056 + * 1116 1145 1173 1201 1086 + * 1228 1254 1280 1305 1330 + * 1355 1379 1402 1425 1448] + * @xreset: Reset value of X for r^2 calculation Value: col_start-X_center + * Constraint: Xreset + FrameWdith=4095 Xreset= -4095, default -1632. + * @reserved3: reserved + * @yreset: Reset value of Y for r^2 calculation Value: row_start-Y_center + * Constraint: Yreset + FrameHeight=4095 Yreset= -4095, default -1224. + * @reserved4: reserved + * @x_sqr_reset: Reset value of X^2 for r^2 calculation Value = (Xreset)^2 + * @r_normfactor: Normalization factor for R. Default 14. + * @reserved5: reserved + * @y_sqr_reset: Reset value of Y^2 for r^2 calculation Value = (Yreset)^2 + * @gain_scale: Parameter describing shading gain as a function of distance + * from the image center. + * A single value per frame, loaded by the driver. Default 115. + */ +struct ipu3_uapi_anr_transform_config { + __u32 enable:1; /* 0 or 1, disabled or enabled */ + __u32 adaptive_treshhold_en:1; /* On IPU3, always enabled */ + + __u32 reserved1:30; + __u8 reserved2[44]; + + struct ipu3_uapi_anr_alpha alpha[3]; + struct ipu3_uapi_anr_beta beta[3]; + struct ipu3_uapi_anr_plane_color color[3]; + + __u16 sqrt_lut[IPU3_UAPI_ANR_LUT_SIZE]; /* 11 bits per element */ + + __s16 xreset:13; + __u16 reserved3:3; + __s16 yreset:13; + __u16 reserved4:3; + + __u32 x_sqr_reset:24; + __u32 r_normfactor:5; + __u32 reserved5:3; + + __u32 y_sqr_reset:24; + __u32 gain_scale:8; +} __packed; + +/** + * struct ipu3_uapi_anr_stitch_pyramid - ANR stitch pyramid + * + * @entry0: pyramid LUT entry0, range [0x0, 0x3f] + * @entry1: pyramid LUT entry1, range [0x0, 0x3f] + * @entry2: pyramid LUT entry2, range [0x0, 0x3f] + * @reserved: reserved + */ +struct ipu3_uapi_anr_stitch_pyramid { + __u32 entry0:6; + __u32 entry1:6; + __u32 entry2:6; + __u32 reserved:14; +} __packed; + +/** + * struct ipu3_uapi_anr_stitch_config - ANR stitch config + * + * @anr_stitch_en: enable stitch. Enabled with 1. + * @reserved: reserved + * @pyramid: pyramid table as defined by &ipu3_uapi_anr_stitch_pyramid + * default values: + * { 1, 3, 5 }, { 7, 7, 5 }, { 3, 1, 3 }, + * { 9, 15, 21 }, { 21, 15, 9 }, { 3, 5, 15 }, + * { 25, 35, 35 }, { 25, 15, 5 }, { 7, 21, 35 }, + * { 49, 49, 35 }, { 21, 7, 7 }, { 21, 35, 49 }, + * { 49, 35, 21 }, { 7, 5, 15 }, { 25, 35, 35 }, + * { 25, 15, 5 }, { 3, 9, 15 }, { 21, 21, 15 }, + * { 9, 3, 1 }, { 3, 5, 7 }, { 7, 5, 3}, { 1 } + */ +struct ipu3_uapi_anr_stitch_config { + __u32 anr_stitch_en; + __u8 reserved[44]; + struct ipu3_uapi_anr_stitch_pyramid pyramid[IPU3_UAPI_ANR_PYRAMID_SIZE]; +} __packed; + +/** + * struct ipu3_uapi_anr_config - ANR config + * + * @transform: advanced noise reduction transform config as specified by + * &ipu3_uapi_anr_transform_config + * @stitch: create 4x4 patch from 4 surrounding 8x8 patches. + */ +struct ipu3_uapi_anr_config { + struct ipu3_uapi_anr_transform_config transform __attribute__((aligned(32))); + struct ipu3_uapi_anr_stitch_config stitch __attribute__((aligned(32))); +} __packed; + +/** + * struct ipu3_uapi_acc_param - Accelerator cluster parameters + * + * ACC refers to the HW cluster containing all Fixed Functions (FFs). Each FF + * implements a specific algorithm. + * + * @bnr: parameters for bayer noise reduction static config. See + * &ipu3_uapi_bnr_static_config + * @green_disparity: disparity static config between gr and gb channel. + * See &ipu3_uapi_bnr_static_config_green_disparity + * @dm: de-mosaic config. See &ipu3_uapi_dm_config + * @ccm: color correction matrix. See &ipu3_uapi_ccm_mat_config + * @gamma: gamma correction config. See &ipu3_uapi_gamma_config + * @csc: color space conversion matrix. See &ipu3_uapi_csc_mat_config + * @cds: color down sample config. See &ipu3_uapi_cds_params + * @shd: lens shading correction config. See &ipu3_uapi_shd_config + * @iefd: Image enhancement filter and denoise config. + * &ipu3_uapi_yuvp1_iefd_config + * @yds_c0: y down scaler config. &ipu3_uapi_yuvp1_yds_config + * @chnr_c0: chroma noise reduction config. &ipu3_uapi_yuvp1_chnr_config + * @y_ee_nr: y edge enhancement and noise reduction config. + * &ipu3_uapi_yuvp1_y_ee_nr_config + * @yds: y down scaler config. See &ipu3_uapi_yuvp1_yds_config + * @chnr: chroma noise reduction config. See &ipu3_uapi_yuvp1_chnr_config + * @reserved1: reserved + * @yds2: y channel down scaler config. See &ipu3_uapi_yuvp1_yds_config + * @tcc: total color correction config as defined in struct + * &ipu3_uapi_yuvp2_tcc_static_config + * @reserved2: reserved + * @anr: advanced noise reduction config.See &ipu3_uapi_anr_config + * @awb_fr: AWB filter response config. See ipu3_uapi_awb_fr_config + * @ae: auto exposure config As specified by &ipu3_uapi_ae_config + * @af: auto focus config. As specified by &ipu3_uapi_af_config + * @awb: auto white balance config. As specified by &ipu3_uapi_awb_config + */ +struct ipu3_uapi_acc_param { + struct ipu3_uapi_bnr_static_config bnr; + struct ipu3_uapi_bnr_static_config_green_disparity + green_disparity __attribute__((aligned(32))); + struct ipu3_uapi_dm_config dm __attribute__((aligned(32))); + struct ipu3_uapi_ccm_mat_config ccm __attribute__((aligned(32))); + struct ipu3_uapi_gamma_config gamma __attribute__((aligned(32))); + struct ipu3_uapi_csc_mat_config csc __attribute__((aligned(32))); + struct ipu3_uapi_cds_params cds __attribute__((aligned(32))); + struct ipu3_uapi_shd_config shd __attribute__((aligned(32))); + struct ipu3_uapi_yuvp1_iefd_config iefd __attribute__((aligned(32))); + struct ipu3_uapi_yuvp1_yds_config yds_c0 __attribute__((aligned(32))); + struct ipu3_uapi_yuvp1_chnr_config chnr_c0 __attribute__((aligned(32))); + struct ipu3_uapi_yuvp1_y_ee_nr_config y_ee_nr __attribute__((aligned(32))); + struct ipu3_uapi_yuvp1_yds_config yds __attribute__((aligned(32))); + struct ipu3_uapi_yuvp1_chnr_config chnr __attribute__((aligned(32))); + struct ipu3_uapi_yuvp1_yds_config yds2 __attribute__((aligned(32))); + struct ipu3_uapi_yuvp2_tcc_static_config tcc __attribute__((aligned(32))); + struct ipu3_uapi_anr_config anr; + struct ipu3_uapi_awb_fr_config_s awb_fr; + struct ipu3_uapi_ae_config ae; + struct ipu3_uapi_af_config_s af; + struct ipu3_uapi_awb_config awb; +} __packed; + +/** + * struct ipu3_uapi_isp_lin_vmem_params - Linearization parameters + * + * @lin_lutlow_gr: linearization look-up table for GR channel interpolation. + * @lin_lutlow_r: linearization look-up table for R channel interpolation. + * @lin_lutlow_b: linearization look-up table for B channel interpolation. + * @lin_lutlow_gb: linearization look-up table for GB channel interpolation. + * lin_lutlow_gr / lin_lutlow_r / lin_lutlow_b / + * lin_lutlow_gb <= LIN_MAX_VALUE - 1. + * @lin_lutdif_gr: lin_lutlow_gr[i+1] - lin_lutlow_gr[i]. + * @lin_lutdif_r: lin_lutlow_r[i+1] - lin_lutlow_r[i]. + * @lin_lutdif_b: lin_lutlow_b[i+1] - lin_lutlow_b[i]. + * @lin_lutdif_gb: lin_lutlow_gb[i+1] - lin_lutlow_gb[i]. + */ +struct ipu3_uapi_isp_lin_vmem_params { + __s16 lin_lutlow_gr[IPU3_UAPI_LIN_LUT_SIZE]; + __s16 lin_lutlow_r[IPU3_UAPI_LIN_LUT_SIZE]; + __s16 lin_lutlow_b[IPU3_UAPI_LIN_LUT_SIZE]; + __s16 lin_lutlow_gb[IPU3_UAPI_LIN_LUT_SIZE]; + __s16 lin_lutdif_gr[IPU3_UAPI_LIN_LUT_SIZE]; + __s16 lin_lutdif_r[IPU3_UAPI_LIN_LUT_SIZE]; + __s16 lin_lutdif_b[IPU3_UAPI_LIN_LUT_SIZE]; + __s16 lin_lutdif_gb[IPU3_UAPI_LIN_LUT_SIZE]; +} __packed; + +/* Temporal Noise Reduction */ + +/** + * struct ipu3_uapi_isp_tnr3_vmem_params - Temporal noise reduction vector + * memory parameters + * + * @slope: slope setting in interpolation curve for temporal noise reduction. + * @reserved1: reserved + * @sigma: knee point setting in interpolation curve for temporal + * noise reduction. + * @reserved2: reserved + */ +struct ipu3_uapi_isp_tnr3_vmem_params { + __u16 slope[IPU3_UAPI_ISP_TNR3_VMEM_LEN]; + __u16 reserved1[IPU3_UAPI_ISP_VEC_ELEMS + - IPU3_UAPI_ISP_TNR3_VMEM_LEN]; + __u16 sigma[IPU3_UAPI_ISP_TNR3_VMEM_LEN]; + __u16 reserved2[IPU3_UAPI_ISP_VEC_ELEMS + - IPU3_UAPI_ISP_TNR3_VMEM_LEN]; +} __packed; + +/** + * struct ipu3_uapi_isp_tnr3_params - Temporal noise reduction v3 parameters + * + * @knee_y1: Knee point TNR3 assumes standard deviation of Y,U and + * V at Y1 are TnrY1_Sigma_Y, U and V. + * @knee_y2: Knee point TNR3 assumes standard deviation of Y,U and + * V at Y2 are TnrY2_Sigma_Y, U and V. + * @maxfb_y: Max feedback gain for Y + * @maxfb_u: Max feedback gain for U + * @maxfb_v: Max feedback gain for V + * @round_adj_y: rounding Adjust for Y + * @round_adj_u: rounding Adjust for U + * @round_adj_v: rounding Adjust for V + * @ref_buf_select: selection of the reference frame buffer to be used. + */ +struct ipu3_uapi_isp_tnr3_params { + __u32 knee_y1; + __u32 knee_y2; + __u32 maxfb_y; + __u32 maxfb_u; + __u32 maxfb_v; + __u32 round_adj_y; + __u32 round_adj_u; + __u32 round_adj_v; + __u32 ref_buf_select; +} __packed; + +/* Extreme Noise Reduction version 3 */ + +/** + * struct ipu3_uapi_isp_xnr3_vmem_params - Extreme noise reduction v3 + * vector memory parameters + * + * @x: xnr3 parameters. + * @a: xnr3 parameters. + * @b: xnr3 parameters. + * @c: xnr3 parameters. + */ +struct ipu3_uapi_isp_xnr3_vmem_params { + __u16 x[IPU3_UAPI_ISP_VEC_ELEMS]; + __u16 a[IPU3_UAPI_ISP_VEC_ELEMS]; + __u16 b[IPU3_UAPI_ISP_VEC_ELEMS]; + __u16 c[IPU3_UAPI_ISP_VEC_ELEMS]; +} __packed; + +/** + * struct ipu3_uapi_xnr3_alpha_params - Extreme noise reduction v3 + * alpha tuning parameters + * + * @y0: Sigma for Y range similarity in dark area. + * @u0: Sigma for U range similarity in dark area. + * @v0: Sigma for V range similarity in dark area. + * @ydiff: Sigma difference for Y between bright area and dark area. + * @udiff: Sigma difference for U between bright area and dark area. + * @vdiff: Sigma difference for V between bright area and dark area. + */ +struct ipu3_uapi_xnr3_alpha_params { + __u32 y0; + __u32 u0; + __u32 v0; + __u32 ydiff; + __u32 udiff; + __u32 vdiff; +} __packed; + +/** + * struct ipu3_uapi_xnr3_coring_params - Extreme noise reduction v3 + * coring parameters + * + * @u0: Coring Threshold of U channel in dark area. + * @v0: Coring Threshold of V channel in dark area. + * @udiff: Threshold difference of U channel between bright and dark area. + * @vdiff: Threshold difference of V channel between bright and dark area. + */ +struct ipu3_uapi_xnr3_coring_params { + __u32 u0; + __u32 v0; + __u32 udiff; + __u32 vdiff; +} __packed; + +/** + * struct ipu3_uapi_xnr3_blending_params - Blending factor + * + * @strength: The factor for blending output with input. This is tuning + * parameterHigher values lead to more aggressive XNR operation. + */ +struct ipu3_uapi_xnr3_blending_params { + __u32 strength; +} __packed; + +/** + * struct ipu3_uapi_isp_xnr3_params - Extreme noise reduction v3 parameters + * + * @alpha: parameters for xnr3 alpha. See &ipu3_uapi_xnr3_alpha_params + * @coring: parameters for xnr3 coring. See &ipu3_uapi_xnr3_coring_params + * @blending: parameters for xnr3 blending. See &ipu3_uapi_xnr3_blending_params + */ +struct ipu3_uapi_isp_xnr3_params { + struct ipu3_uapi_xnr3_alpha_params alpha; + struct ipu3_uapi_xnr3_coring_params coring; + struct ipu3_uapi_xnr3_blending_params blending; +} __packed; + +/***** Obgrid (optical black level compensation) table entry *****/ + +/** + * struct ipu3_uapi_obgrid_param - Optical black level compensation parameters + * + * @gr: Grid table values for color GR + * @r: Grid table values for color R + * @b: Grid table values for color B + * @gb: Grid table values for color GB + * + * Black level is different for red, green, and blue channels. So black level + * compensation is different per channel. + */ +struct ipu3_uapi_obgrid_param { + __u16 gr; + __u16 r; + __u16 b; + __u16 gb; +} __packed; + +/******************* V4L2_META_FMT_IPU3_PARAMS *******************/ + +/** + * struct ipu3_uapi_flags - bits to indicate which pipeline needs update + * + * @gdc: 0 = no update, 1 = update. + * @obgrid: 0 = no update, 1 = update. + * @reserved1: Not used. + * @acc_bnr: 0 = no update, 1 = update. + * @acc_green_disparity: 0 = no update, 1 = update. + * @acc_dm: 0 = no update, 1 = update. + * @acc_ccm: 0 = no update, 1 = update. + * @acc_gamma: 0 = no update, 1 = update. + * @acc_csc: 0 = no update, 1 = update. + * @acc_cds: 0 = no update, 1 = update. + * @acc_shd: 0 = no update, 1 = update. + * @reserved2: Not used. + * @acc_iefd: 0 = no update, 1 = update. + * @acc_yds_c0: 0 = no update, 1 = update. + * @acc_chnr_c0: 0 = no update, 1 = update. + * @acc_y_ee_nr: 0 = no update, 1 = update. + * @acc_yds: 0 = no update, 1 = update. + * @acc_chnr: 0 = no update, 1 = update. + * @acc_ytm: 0 = no update, 1 = update. + * @acc_yds2: 0 = no update, 1 = update. + * @acc_tcc: 0 = no update, 1 = update. + * @acc_dpc: 0 = no update, 1 = update. + * @acc_bds: 0 = no update, 1 = update. + * @acc_anr: 0 = no update, 1 = update. + * @acc_awb_fr: 0 = no update, 1 = update. + * @acc_ae: 0 = no update, 1 = update. + * @acc_af: 0 = no update, 1 = update. + * @acc_awb: 0 = no update, 1 = update. + * @__acc_osys: 0 = no update, 1 = update. + * @reserved3: Not used. + * @lin_vmem_params: 0 = no update, 1 = update. + * @tnr3_vmem_params: 0 = no update, 1 = update. + * @xnr3_vmem_params: 0 = no update, 1 = update. + * @tnr3_dmem_params: 0 = no update, 1 = update. + * @xnr3_dmem_params: 0 = no update, 1 = update. + * @reserved4: Not used. + * @obgrid_param: 0 = no update, 1 = update. + * @reserved5: Not used. + */ +struct ipu3_uapi_flags { + __u32 gdc:1; + __u32 obgrid:1; + __u32 reserved1:30; + + __u32 acc_bnr:1; + __u32 acc_green_disparity:1; + __u32 acc_dm:1; + __u32 acc_ccm:1; + __u32 acc_gamma:1; + __u32 acc_csc:1; + __u32 acc_cds:1; + __u32 acc_shd:1; + __u32 reserved2:2; + __u32 acc_iefd:1; + __u32 acc_yds_c0:1; + __u32 acc_chnr_c0:1; + __u32 acc_y_ee_nr:1; + __u32 acc_yds:1; + __u32 acc_chnr:1; + __u32 acc_ytm:1; + __u32 acc_yds2:1; + __u32 acc_tcc:1; + __u32 acc_dpc:1; + __u32 acc_bds:1; + __u32 acc_anr:1; + __u32 acc_awb_fr:1; + __u32 acc_ae:1; + __u32 acc_af:1; + __u32 acc_awb:1; + __u32 reserved3:4; + + __u32 lin_vmem_params:1; + __u32 tnr3_vmem_params:1; + __u32 xnr3_vmem_params:1; + __u32 tnr3_dmem_params:1; + __u32 xnr3_dmem_params:1; + __u32 reserved4:1; + __u32 obgrid_param:1; + __u32 reserved5:25; +} __packed; + +/** + * struct ipu3_uapi_params - V4L2_META_FMT_IPU3_PARAMS + * + * @use: select which parameters to apply, see &ipu3_uapi_flags + * @acc_param: ACC parameters, as specified by &ipu3_uapi_acc_param + * @lin_vmem_params: linearization VMEM, as specified by + * &ipu3_uapi_isp_lin_vmem_params + * @tnr3_vmem_params: tnr3 VMEM as specified by + * &ipu3_uapi_isp_tnr3_vmem_params + * @xnr3_vmem_params: xnr3 VMEM as specified by + * &ipu3_uapi_isp_xnr3_vmem_params + * @tnr3_dmem_params: tnr3 DMEM as specified by &ipu3_uapi_isp_tnr3_params + * @xnr3_dmem_params: xnr3 DMEM as specified by &ipu3_uapi_isp_xnr3_params + * @obgrid_param: obgrid parameters as specified by + * &ipu3_uapi_obgrid_param + * + * The video queue "parameters" is of format V4L2_META_FMT_IPU3_PARAMS. + * This is a "single plane" v4l2_meta_format using V4L2_BUF_TYPE_META_OUTPUT. + * + * struct ipu3_uapi_params as defined below contains a lot of parameters and + * ipu3_uapi_flags selects which parameters to apply. + */ +struct ipu3_uapi_params { + /* Flags which of the settings below are to be applied */ + struct ipu3_uapi_flags use __attribute__((aligned(32))); + + /* Accelerator cluster parameters */ + struct ipu3_uapi_acc_param acc_param; + + /* ISP vector address space parameters */ + struct ipu3_uapi_isp_lin_vmem_params lin_vmem_params; + struct ipu3_uapi_isp_tnr3_vmem_params tnr3_vmem_params; + struct ipu3_uapi_isp_xnr3_vmem_params xnr3_vmem_params; + + /* ISP data memory (DMEM) parameters */ + struct ipu3_uapi_isp_tnr3_params tnr3_dmem_params; + struct ipu3_uapi_isp_xnr3_params xnr3_dmem_params; + + /* Optical black level compensation */ + struct ipu3_uapi_obgrid_param obgrid_param; +} __packed; + +#endif /* __IPU3_UAPI_H */ diff --git a/drivers/staging/media/ipu3/ipu3-abi.h b/drivers/staging/media/ipu3/ipu3-abi.h index e1185602c7fd..c76935b436d7 100644 --- a/drivers/staging/media/ipu3/ipu3-abi.h +++ b/drivers/staging/media/ipu3/ipu3-abi.h @@ -4,7 +4,7 @@ #ifndef __IPU3_ABI_H #define __IPU3_ABI_H -#include "include/intel-ipu3.h" +#include "include/uapi/intel-ipu3.h" /******************* IMGU Hardware information *******************/ -- cgit v1.3.1 From caad79405086151dec128f78274a999f15d947ed Mon Sep 17 00:00:00 2001 From: Bernhard Wimmer Date: Wed, 21 Apr 2021 23:33:19 +0200 Subject: media: Documentation: ccs: Fix the op_pll_multiplier address According to the CCS spec the op_pll_multiplier address is 0x030e, not 0x031e. Signed-off-by: Bernhard Wimmer Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/drivers/ccs/ccs-regs.asc | 2 +- Documentation/driver-api/media/drivers/ccs/mk-ccs-regs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/driver-api/media/drivers/ccs/ccs-regs.asc b/Documentation/driver-api/media/drivers/ccs/ccs-regs.asc index f2042acc8a45..bbf9213c3388 100644 --- a/Documentation/driver-api/media/drivers/ccs/ccs-regs.asc +++ b/Documentation/driver-api/media/drivers/ccs/ccs-regs.asc @@ -210,7 +210,7 @@ pll_multiplier 0x0306 16 op_pix_clk_div 0x0308 16 op_sys_clk_div 0x030a 16 op_pre_pll_clk_div 0x030c 16 -op_pll_multiplier 0x031e 16 +op_pll_multiplier 0x030e 16 pll_mode 0x0310 8 - f 0 0 - e single 0 diff --git a/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs b/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs index 6668deaf2f19..2a4edc7e051a 100755 --- a/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs +++ b/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs @@ -72,13 +72,14 @@ $uc_header =~ s/[^A-Z0-9]/_/g; my $copyright = "/* Copyright (C) 2019--2020 Intel Corporation */\n"; my $license = "SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause"; +my $note = "/*\n * Generated by $0;\n * do not modify.\n */\n"; for my $fh ($A, $LC) { - print $fh "// $license\n$copyright\n" if defined $fh; + print $fh "// $license\n$copyright$note\n" if defined $fh; } for my $fh ($H, $LH) { - print $fh "/* $license */\n$copyright\n"; + print $fh "/* $license */\n$copyright$note\n"; } sub bit_def($) { -- cgit v1.3.1 From d443d838f6d76c8e1acbd4e27583cb2948066f0e Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Tue, 11 May 2021 16:23:20 +0200 Subject: media: dt-bindings: media: renesas,isp: Add bindings for ISP Channel Selector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add bindings for Renesas R-Car ISP Channel Selector IP. The ISP is responsible for filtering the MIPI CSI-2 bus and directing the different CSI-2 virtual channels to different R-Car VIN instances (DMA engines) for capture. Signed-off-by: Niklas Söderlund Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/renesas,isp.yaml | 196 +++++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 197 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/renesas,isp.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/renesas,isp.yaml b/Documentation/devicetree/bindings/media/renesas,isp.yaml new file mode 100644 index 000000000000..514857d36f6b --- /dev/null +++ b/Documentation/devicetree/bindings/media/renesas,isp.yaml @@ -0,0 +1,196 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +# Copyright (C) 2021 Renesas Electronics Corp. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/renesas,isp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas R-Car ISP Channel Selector + +maintainers: + - Niklas Söderlund + +description: + The R-Car ISP Channel Selector provides MIPI CSI-2 VC and DT filtering + capabilities for the Renesas R-Car family of devices. It is used in + conjunction with the R-Car VIN and CSI-2 modules, which provides the video + capture capabilities. + +properties: + compatible: + items: + - enum: + - renesas,r8a779a0-isp # V3U + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: + Input port node, multiple endpoints describing the connected R-Car + CSI-2 receivers. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + Single endpoint describing the R-Car VIN connected to output port 0. + + port@2: + $ref: /schemas/graph.yaml#/properties/port + description: + Single endpoint describing the R-Car VIN connected to output port 1. + + port@3: + $ref: /schemas/graph.yaml#/properties/port + description: + Single endpoint describing the R-Car VIN connected to output port 2. + + port@4: + $ref: /schemas/graph.yaml#/properties/port + description: + Single endpoint describing the R-Car VIN connected to output port 3. + + port@5: + $ref: /schemas/graph.yaml#/properties/port + description: + Single endpoint describing the R-Car VIN connected to output port 4. + + port@6: + $ref: /schemas/graph.yaml#/properties/port + description: + Single endpoint describing the R-Car VIN connected to output port 5. + + port@7: + $ref: /schemas/graph.yaml#/properties/port + description: + Single endpoint describing the R-Car VIN connected to output port 6. + + port@8: + $ref: /schemas/graph.yaml#/properties/port + description: + Single endpoint describing the R-Car VIN connected to output port 7. + + required: + - port@0 + - port@1 + - port@2 + - port@3 + - port@4 + - port@5 + - port@6 + - port@7 + - port@8 + +required: + - compatible + - reg + - interrupts + - clocks + - power-domains + - resets + - ports + +additionalProperties: false + +examples: + - | + #include + #include + #include + + isp1: isp@fed20000 { + compatible = "renesas,r8a779a0-isp"; + reg = <0xfed20000 0x10000>; + interrupts = ; + clocks = <&cpg CPG_MOD 613>; + power-domains = <&sysc R8A779A0_PD_A3ISP01>; + resets = <&cpg 613>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + + reg = <0>; + isp1csi41: endpoint@1 { + reg = <1>; + remote-endpoint = <&csi41isp1>; + }; + }; + + port@1 { + reg = <1>; + isp1vin08: endpoint { + remote-endpoint = <&vin08isp1>; + }; + }; + + port@2 { + reg = <2>; + isp1vin09: endpoint { + remote-endpoint = <&vin09isp1>; + }; + }; + + port@3 { + reg = <3>; + isp1vin10: endpoint { + remote-endpoint = <&vin10isp1>; + }; + }; + + port@4 { + reg = <4>; + isp1vin11: endpoint { + remote-endpoint = <&vin11isp1>; + }; + }; + + port@5 { + reg = <5>; + isp1vin12: endpoint { + remote-endpoint = <&vin12isp1>; + }; + }; + + port@6 { + reg = <6>; + isp1vin13: endpoint { + remote-endpoint = <&vin13isp1>; + }; + }; + + port@7 { + reg = <7>; + isp1vin14: endpoint { + remote-endpoint = <&vin14isp1>; + }; + }; + + port@8 { + reg = <8>; + isp1vin15: endpoint { + remote-endpoint = <&vin15isp1>; + }; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 0fee01ceb151..5e1bbb39a68e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11400,6 +11400,7 @@ L: linux-renesas-soc@vger.kernel.org S: Supported T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/renesas,csi2.yaml +F: Documentation/devicetree/bindings/media/renesas,isp.yaml F: Documentation/devicetree/bindings/media/renesas,vin.yaml F: drivers/media/platform/rcar-vin/ -- cgit v1.3.1 From 8f6a0eabb1f21a23a570b0986c8abe9fded3ad6f Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Tue, 11 May 2021 16:33:32 +0200 Subject: media: dt-bindings: media: renesas,vin: Add r8a779a0 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document support for the VIN module in the Renesas V3U (r8a779a0) SoC. The V3U is different from other SoCs as it have 32 instead of 8 (most of Gen3) or 16 (V3H) VIN instances. The VIN instances are also connected to a new IP the R-Car ISP Channel Selector. Signed-off-by: Niklas Söderlund Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/renesas,vin.yaml | 26 +++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/renesas,vin.yaml b/Documentation/devicetree/bindings/media/renesas,vin.yaml index dd1a5ce5896c..5ba06b0f030b 100644 --- a/Documentation/devicetree/bindings/media/renesas,vin.yaml +++ b/Documentation/devicetree/bindings/media/renesas,vin.yaml @@ -51,6 +51,7 @@ properties: - renesas,vin-r8a77980 # R-Car V3H - renesas,vin-r8a77990 # R-Car E3 - renesas,vin-r8a77995 # R-Car D3 + - renesas,vin-r8a779a0 # R-Car V3U reg: maxItems: 1 @@ -111,7 +112,7 @@ properties: description: VIN channel number $ref: /schemas/types.yaml#/definitions/uint32 minimum: 0 - maximum: 15 + maximum: 31 ports: $ref: /schemas/graph.yaml#/properties/ports @@ -187,6 +188,29 @@ properties: - required: - endpoint@3 + port@2: + $ref: /schemas/graph.yaml#/properties/port + description: + Input port node, multiple endpoints describing all the R-Car ISP + modules connected the VIN. + + properties: + endpoint@0: + $ref: /schemas/graph.yaml#/properties/endpoint + description: Endpoint connected to ISP0. + + endpoint@1: + $ref: /schemas/graph.yaml#/properties/endpoint + description: Endpoint connected to ISP1. + + endpoint@2: + $ref: /schemas/graph.yaml#/properties/endpoint + description: Endpoint connected to ISP2. + + endpoint@3: + $ref: /schemas/graph.yaml#/properties/endpoint + description: Endpoint connected to ISP3. + required: - compatible - reg -- cgit v1.3.1 From 83df8dfd57be041669e6dc365caf1d5f1b2791b8 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 2 Mar 2021 15:42:35 +0100 Subject: media: dt-bindings: media: Document RDA5807 FM radio bindings Add documentation for the devicetree bindings of the RDA5807 FM radio I2C chip from Unisoc. Signed-off-by: Paul Cercueil Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/i2c/rda,rda5807.yaml | 67 ++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/rda,rda5807.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/i2c/rda,rda5807.yaml b/Documentation/devicetree/bindings/media/i2c/rda,rda5807.yaml new file mode 100644 index 000000000000..f50e54a722eb --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/rda,rda5807.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/rda,rda5807.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Unisoc Communications RDA5807 FM radio receiver + +maintainers: + - Paul Cercueil + +properties: + compatible: + enum: + - rda,rda5807 + + reg: + description: I2C address. + maxItems: 1 + + power-supply: true + + rda,lnan: + description: Use LNAN input port. + type: boolean + + rda,lnap: + description: Use LNAP input port. + type: boolean + + rda,analog-out: + description: Enable analog audio output. + type: boolean + + rda,i2s-out: + description: Enable I2S digital audio output. + type: boolean + + rda,lna-microamp: + description: LNA working current, in micro-amperes. + default: 2500 + enum: [1800, 2100, 2500, 3000] + +required: + - compatible + - reg + - power-supply + +additionalProperties: false + +examples: + - | + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + radio@11 { + compatible = "rda,rda5807"; + reg = <0x11>; + + power-supply = <&ldo6>; + + rda,lnan; + rda,lnap; + rda,analog-out; + }; + }; -- cgit v1.3.1 From 90c3493e4d9e2e1450b5d3ffd314ff350f5132a0 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 12 Mar 2021 14:03:30 +0100 Subject: media: dt-bindings: media: renesas,vin: Add r8a77961 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the compatible string for M3-W+ (r8a77961) to the list of supported SoCs. Signed-off-by: Niklas Söderlund Acked-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/renesas,vin.yaml | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/renesas,vin.yaml b/Documentation/devicetree/bindings/media/renesas,vin.yaml index 5ba06b0f030b..39bb6db2fb32 100644 --- a/Documentation/devicetree/bindings/media/renesas,vin.yaml +++ b/Documentation/devicetree/bindings/media/renesas,vin.yaml @@ -46,6 +46,7 @@ properties: - renesas,vin-r8a7779 # R-Car H1 - renesas,vin-r8a7795 # R-Car H3 - renesas,vin-r8a7796 # R-Car M3-W + - renesas,vin-r8a77961 # R-Car M3-W+ - renesas,vin-r8a77965 # R-Car M3-N - renesas,vin-r8a77970 # R-Car V3M - renesas,vin-r8a77980 # R-Car V3H -- cgit v1.3.1 From be6cdcf2c9c97c5a702adb95520d0268c8ecc1ae Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 12 Mar 2021 14:04:21 +0100 Subject: media: dt-bindings: media: renesas,csi2: Add r8a77961 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the compatible string for M3-W+ (r8a77961) to the list of supported SoCs. Signed-off-by: Niklas Söderlund Acked-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/renesas,csi2.yaml | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/renesas,csi2.yaml b/Documentation/devicetree/bindings/media/renesas,csi2.yaml index 20396f1be999..23703b767f5b 100644 --- a/Documentation/devicetree/bindings/media/renesas,csi2.yaml +++ b/Documentation/devicetree/bindings/media/renesas,csi2.yaml @@ -25,6 +25,7 @@ properties: - renesas,r8a774e1-csi2 # RZ/G2H - renesas,r8a7795-csi2 # R-Car H3 - renesas,r8a7796-csi2 # R-Car M3-W + - renesas,r8a77961-csi2 # R-Car M3-W+ - renesas,r8a77965-csi2 # R-Car M3-N - renesas,r8a77970-csi2 # R-Car V3M - renesas,r8a77980-csi2 # R-Car V3H -- cgit v1.3.1 From bce18e52c866ff6ded13ac8ac37e9271f786c005 Mon Sep 17 00:00:00 2001 From: ChiYuan Huang Date: Wed, 2 Jun 2021 13:31:45 +0800 Subject: regulator: rt6160: Add DT binding document for Richtek RT6160 Add DT binding document for Richtek RT6160 voltage regulator. Signed-off-by: ChiYuan Huang Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/1622611906-2403-1-git-send-email-u0084500@gmail.com Signed-off-by: Mark Brown --- .../regulator/richtek,rt6160-regulator.yaml | 61 ++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/richtek,rt6160-regulator.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/richtek,rt6160-regulator.yaml b/Documentation/devicetree/bindings/regulator/richtek,rt6160-regulator.yaml new file mode 100644 index 000000000000..0534b0d68359 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/richtek,rt6160-regulator.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/richtek,rt6160-regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Richtek RT6160 BuckBoost converter + +maintainers: + - ChiYuan Huang + +description: | + The RT6160 is a high-efficiency buck-boost converter that can provide + up to 3A output current from 2025mV to 5200mV. And it support the wide + input voltage range from 2200mV to 5500mV. + + Datasheet is available at + https://www.richtek.com/assets/product_file/RT6160A/DS6160A-00.pdf + +allOf: + - $ref: regulator.yaml# + +properties: + compatible: + enum: + - richtek,rt6160 + + reg: + maxItems: 1 + + enable-gpios: + description: A connection of the 'enable' gpio line. + maxItems: 1 + + richtek,vsel-active-low: + description: | + Used to indicate the 'vsel' pin active level. if not specified, use + high active level as the default. + type: boolean + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + rt6160@75 { + compatible = "richtek,rt6160"; + reg = <0x75>; + enable-gpios = <&gpio26 2 0>; + regulator-name = "rt6160-buckboost"; + regulator-min-microvolt = <2025000>; + regulator-max-microvolt = <5200000>; + }; + }; -- cgit v1.3.1 From 98b9c7890b2d74d2f5342ef23d12c4bcbbec54bf Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 2 Jun 2021 15:06:12 +0200 Subject: docs: admin-guide: media: ipu3.rst: replace some characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion tools used during DocBook/LaTeX/html/Markdown->ReST conversion and some cut-and-pasted text contain some characters that aren't easily reachable on standard keyboards and/or could cause troubles when parsed by the documentation build system. Replace the occurences of the following characters: - U+201c ('“'): LEFT DOUBLE QUOTATION MARK - U+201d ('”'): RIGHT DOUBLE QUOTATION MARK Signed-off-by: Mauro Carvalho Chehab --- Documentation/admin-guide/media/ipu3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/media/ipu3.rst b/Documentation/admin-guide/media/ipu3.rst index d6454f637ff4..52c1c04173da 100644 --- a/Documentation/admin-guide/media/ipu3.rst +++ b/Documentation/admin-guide/media/ipu3.rst @@ -244,7 +244,7 @@ output larger bayer frame for further YUV processing than "VIDEO" mode to get high quality images. Besides, "STILL" mode need XNR3 to do noise reduction, hence "STILL" mode will need more power and memory bandwidth than "VIDEO" mode. TNR will be enabled in "VIDEO" mode and bypassed by "STILL" mode. ImgU is -running at “VIDEO” mode by default, the user can use v4l2 control +running at "VIDEO" mode by default, the user can use v4l2 control V4L2_CID_INTEL_IPU3_MODE (currently defined in drivers/staging/media/ipu3/include/uapi/intel-ipu3.h) to query and set the running mode. For user, there is no difference for buffer queueing between the -- cgit v1.3.1 From 9df4827523bdc4032b1021395e8ee6f880d1e8b1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 2 Jun 2021 15:06:43 +0200 Subject: docs: driver-api: media: zoran: replace SOFT HYPHEN character MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the occurences of the following character: - U+00ad ('­'): SOFT HYPHEN as ASCII HYPHEN is preferred over SOFT HYPHEN At least with some fonts, a SOFT HYPHEN is displayed as a blank space. Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/drivers/zoran.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/driver-api/media/drivers/zoran.rst b/Documentation/driver-api/media/drivers/zoran.rst index 83cbae9cedef..b205e10c3154 100644 --- a/Documentation/driver-api/media/drivers/zoran.rst +++ b/Documentation/driver-api/media/drivers/zoran.rst @@ -319,7 +319,7 @@ Conexant bt866 TV encoder ~~~~~~~~~~~~~~~~~~~~~~~~~ - is used in AVS6EYES, and -- can generate: NTSC/PAL, PAL­M, PAL­N +- can generate: NTSC/PAL, PAL-M, PAL-N The adv717x, should be able to produce PAL N. But you find nothing PAL N specific in the registers. Seem that you have to reuse a other standard -- cgit v1.3.1 From d4a84f86e9169e07595dd399c42bc7728d077531 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 2 Jun 2021 15:12:17 +0200 Subject: docs: userspace-api: media: fdl-appendix.rst: replace some characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion tools used during DocBook/LaTeX/html/Markdown->ReST conversion and some cut-and-pasted text contain some characters that aren't easily reachable on standard keyboards and/or could cause troubles when parsed by the documentation build system. Replace the occurences of the following characters: - U+201c ('“'): LEFT DOUBLE QUOTATION MARK - U+201d ('”'): RIGHT DOUBLE QUOTATION MARK Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/fdl-appendix.rst | 64 +++++++++++----------- 1 file changed, 32 insertions(+), 32 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/fdl-appendix.rst b/Documentation/userspace-api/media/fdl-appendix.rst index 683ebed87017..b1bc725b4ec7 100644 --- a/Documentation/userspace-api/media/fdl-appendix.rst +++ b/Documentation/userspace-api/media/fdl-appendix.rst @@ -13,14 +13,14 @@ GNU Free Documentation License =========== The purpose of this License is to make a manual, textbook, or other -written document “free” in the sense of freedom: to assure everyone the +written document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. -This License is a kind of “copyleft”, which means that derivative works +This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. @@ -44,21 +44,21 @@ works whose purpose is instruction or reference. This License applies to any manual or other work that contains a notice placed by the copyright holder saying it can be distributed under the -terms of this License. The “Document”, below, refers to any such manual +terms of this License. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as -“you”. +"you". .. _fdl-modified: -A “Modified Version” of the Document means any work containing the +A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. .. _fdl-secondary: -A “Secondary Section” is a named appendix or a front-matter section of +A "Secondary Section" is a named appendix or a front-matter section of the :ref:`Document ` that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing @@ -72,7 +72,7 @@ regarding them. .. _fdl-invariant: -The “Invariant Sections” are certain +The "Invariant Sections" are certain :ref:`Secondary Sections ` whose titles are designated, as being those of Invariant Sections, in the notice that says that the :ref:`Document ` is released under this License. @@ -80,14 +80,14 @@ as being those of Invariant Sections, in the notice that says that the .. _fdl-cover-texts: -The “Cover Texts” are certain short passages of text that are listed, as +The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the :ref:`Document ` is released under this License. .. _fdl-transparent: -A “Transparent” copy of the :ref:`Document ` means a +A "Transparent" copy of the :ref:`Document ` means a machine-readable copy, represented in a format whose specification is available to the general public, whose contents can be viewed and edited directly and straightforwardly with generic text editors or (for images @@ -97,7 +97,7 @@ formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup has been designed to thwart or discourage subsequent modification by readers is not Transparent. A copy that is -not “Transparent” is called “Opaque”. +not "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML @@ -111,10 +111,10 @@ word processors for output purposes only. .. _fdl-title-page: -The “Title Page” means, for a printed book, the title page itself, plus +The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which -do not have any title page as such, “Title Page” means the text near the +do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. @@ -242,11 +242,11 @@ Modified Version: Include an unaltered copy of this License. - **I.** - Preserve the section entitled “History”, and its title, and add to it + Preserve the section entitled "History", and its title, and add to it an item stating at least the title, year, new authors, and publisher of the :ref:`Modified Version ` as given on the :ref:`Title Page `. If there is no section entitled - “History” in the :ref:`Document `, create one stating + "History" in the :ref:`Document `, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. @@ -256,13 +256,13 @@ Modified Version: :ref:`Document ` for public access to a :ref:`Transparent ` copy of the Document, and likewise the network locations given in the Document for previous - versions it was based on. These may be placed in the “History” + versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. - **K.** - In any section entitled “Acknowledgements” or “Dedications”, preserve + In any section entitled "Acknowledgements" or "Dedications", preserve the section's title, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. @@ -274,11 +274,11 @@ Modified Version: part of the section titles. - **M.** - Delete any section entitled “Endorsements”. Such a section may not be + Delete any section entitled "Endorsements". Such a section may not be included in the :ref:`Modified Version `. - **N.** - Do not retitle any existing section as “Endorsements” or to conflict + Do not retitle any existing section as "Endorsements" or to conflict in title with any :ref:`Invariant Section `. If the :ref:`Modified Version ` includes new @@ -290,7 +290,7 @@ of :ref:`Invariant Sections ` in the Modified Version's license notice. These titles must be distinct from any other section titles. -You may add a section entitled “Endorsements”, provided it contains +You may add a section entitled "Endorsements", provided it contains nothing but endorsements of your :ref:`Modified Version ` by various parties--for example, statements of peer review or that the text has been approved by @@ -337,11 +337,11 @@ the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. -In the combination, you must combine any sections entitled “History” in -the various original documents, forming one section entitled “History”; -likewise combine any sections entitled “Acknowledgements”, and any -sections entitled “Dedications”. You must delete all sections entitled -“Endorsements.” +In the combination, you must combine any sections entitled "History" in +the various original documents, forming one section entitled "History"; +likewise combine any sections entitled "Acknowledgements", and any +sections entitled "Dedications". You must delete all sections entitled +"Endorsements." .. _fdl-section6: @@ -372,7 +372,7 @@ with other separate and independent documents or works, in or on a volume of a storage or distribution medium, does not as a whole count as a :ref:`Modified Version ` of the Document, provided no compilation copyright is claimed for the compilation. Such a compilation -is called an “aggregate”, and this License does not apply to the other +is called an "aggregate", and this License does not apply to the other self-contained works thus compiled with the Document , on account of their being thus compiled, if they are not themselves derivative works of the Document. If the :ref:`Cover Text ` @@ -429,7 +429,7 @@ concerns. See Each version of the License is given a distinguishing version number. If the :ref:`Document ` specifies that a particular -numbered version of this License “or any later version” applies to it, +numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not @@ -455,13 +455,13 @@ notices just after the title page: being LIST THEIR TITLES, with the :ref:`Front-Cover Texts ` being LIST, and with the :ref:`Back-Cover Texts ` being LIST. A copy - of the license is included in the section entitled “GNU Free - Documentation License”. + of the license is included in the section entitled "GNU Free + Documentation License". -If you have no :ref:`Invariant Sections `, write “with -no Invariant Sections” instead of saying which ones are invariant. If -you have no :ref:`Front-Cover Texts `, write “no -Front-Cover Texts” instead of “Front-Cover Texts being LIST”; likewise +If you have no :ref:`Invariant Sections `, write "with +no Invariant Sections" instead of saying which ones are invariant. If +you have no :ref:`Front-Cover Texts `, write "no +Front-Cover Texts" instead of "Front-Cover Texts being LIST"; likewise for :ref:`Back-Cover Texts `. If your document contains nontrivial examples of program code, we -- cgit v1.3.1 From eff7d26abc05821fd4ff32f2eef0a37cf977535b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 2 Jun 2021 15:12:18 +0200 Subject: docs: userspace-api: media: v4l: replace some characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion tools used during DocBook/LaTeX/html/Markdown->ReST conversion and some cut-and-pasted text contain some characters that aren't easily reachable on standard keyboards and/or could cause troubles when parsed by the documentation build system. Replace the occurences of the following characters: - U+00a0 (' '): NO-BREAK SPACE as it can cause lines being truncated on PDF output - U+2014 ('—'): EM DASH - U+2019 ('’'): RIGHT SINGLE QUOTATION MARK Note that Sphinx auto-translates '---' into EM DASH. Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/biblio.rst | 8 ++++---- Documentation/userspace-api/media/v4l/dev-decoder.rst | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/v4l/biblio.rst b/Documentation/userspace-api/media/v4l/biblio.rst index 64d241daf63c..7b8e6738ff9e 100644 --- a/Documentation/userspace-api/media/v4l/biblio.rst +++ b/Documentation/userspace-api/media/v4l/biblio.rst @@ -51,7 +51,7 @@ ISO 13818-1 =========== -:title: ITU-T Rec. H.222.0 | ISO/IEC 13818-1 "Information technology — Generic coding of moving pictures and associated audio information: Systems" +:title: ITU-T Rec. H.222.0 | ISO/IEC 13818-1 "Information technology --- Generic coding of moving pictures and associated audio information: Systems" :author: International Telecommunication Union (http://www.itu.ch), International Organisation for Standardisation (http://www.iso.ch) @@ -61,7 +61,7 @@ ISO 13818-2 =========== -:title: ITU-T Rec. H.262 | ISO/IEC 13818-2 "Information technology — Generic coding of moving pictures and associated audio information: Video" +:title: ITU-T Rec. H.262 | ISO/IEC 13818-2 "Information technology --- Generic coding of moving pictures and associated audio information: Video" :author: International Telecommunication Union (http://www.itu.ch), International Organisation for Standardisation (http://www.iso.ch) @@ -150,7 +150,7 @@ ITU-T.81 ======== -:title: ITU-T Recommendation T.81 "Information Technology — Digital Compression and Coding of Continous-Tone Still Images — Requirements and Guidelines" +:title: ITU-T Recommendation T.81 "Information Technology --- Digital Compression and Coding of Continous-Tone Still Images --- Requirements and Guidelines" :author: International Telecommunication Union (http://www.itu.int) @@ -310,7 +310,7 @@ ISO 12232:2006 ============== -:title: Photography — Digital still cameras — Determination of exposure index, ISO speed ratings, standard output sensitivity, and recommended exposure index +:title: Photography --- Digital still cameras --- Determination of exposure index, ISO speed ratings, standard output sensitivity, and recommended exposure index :author: International Organization for Standardization (http://www.iso.org) diff --git a/Documentation/userspace-api/media/v4l/dev-decoder.rst b/Documentation/userspace-api/media/v4l/dev-decoder.rst index 3d4138a4ba69..5b9b83feeceb 100644 --- a/Documentation/userspace-api/media/v4l/dev-decoder.rst +++ b/Documentation/userspace-api/media/v4l/dev-decoder.rst @@ -38,7 +38,7 @@ Conventions and Notations Used in This Document 6. i = [a..b]: sequence of integers from a to b, inclusive, i.e. i = [0..2]: i = 0, 1, 2. -7. Given an ``OUTPUT`` buffer A, then A’ represents a buffer on the ``CAPTURE`` +7. Given an ``OUTPUT`` buffer A, then A' represents a buffer on the ``CAPTURE`` queue containing data that resulted from processing buffer A. .. _decoder-glossary: @@ -288,7 +288,7 @@ Initialization Changing the ``OUTPUT`` format may change the currently set ``CAPTURE`` format. How the new ``CAPTURE`` format is determined is up to the decoder - and the client must ensure it matches its needs afterwards. + and the client must ensure it matches its needs afterwards. 2. Allocate source (bytestream) buffers via :c:func:`VIDIOC_REQBUFS` on ``OUTPUT``. @@ -874,7 +874,7 @@ it may be affected as per normal decoder operation. any of the following results on the ``CAPTURE`` queue is allowed: - {A’, B’, G’, H’}, {A’, G’, H’}, {G’, H’}. + {A', B', G', H'}, {A', G', H'}, {G', H'}. To determine the CAPTURE buffer containing the first decoded frame after the seek, the client may observe the timestamps to match the CAPTURE and OUTPUT -- cgit v1.3.1 From c11669f738f48c7b3cf3b7ec700af33e1566d9c3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 2 Jun 2021 15:12:18 +0200 Subject: docs: userspace-api: media: dvb: replace some characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion tools used during DocBook/LaTeX/html/Markdown->ReST conversion and some cut-and-pasted text contain some characters that aren't easily reachable on standard keyboards and/or could cause troubles when parsed by the documentation build system. Replace the occurences of the following characters: - U+00a0 (' '): NO-BREAK SPACE as it can cause lines being truncated on PDF output - U+2019 ('’'): RIGHT SINGLE QUOTATION MARK - U+201c ('“'): LEFT DOUBLE QUOTATION MARK - U+201d ('”'): RIGHT DOUBLE QUOTATION MARK Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/dvb/audio-set-bypass-mode.rst | 2 +- Documentation/userspace-api/media/dvb/audio.rst | 2 +- Documentation/userspace-api/media/dvb/dmx-fopen.rst | 2 +- Documentation/userspace-api/media/dvb/dmx-fread.rst | 2 +- Documentation/userspace-api/media/dvb/dmx-set-filter.rst | 2 +- Documentation/userspace-api/media/dvb/intro.rst | 6 +++--- Documentation/userspace-api/media/dvb/video.rst | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/dvb/audio-set-bypass-mode.rst b/Documentation/userspace-api/media/dvb/audio-set-bypass-mode.rst index ecac02f1b2fc..80d551a2053a 100644 --- a/Documentation/userspace-api/media/dvb/audio-set-bypass-mode.rst +++ b/Documentation/userspace-api/media/dvb/audio-set-bypass-mode.rst @@ -50,7 +50,7 @@ Description This ioctl call asks the Audio Device to bypass the Audio decoder and forward the stream without decoding. This mode shall be used if streams -that can’t be handled by the Digital TV system shall be decoded. Dolby +that can't be handled by the Digital TV system shall be decoded. Dolby DigitalTM streams are automatically forwarded by the Digital TV subsystem if the hardware can handle it. diff --git a/Documentation/userspace-api/media/dvb/audio.rst b/Documentation/userspace-api/media/dvb/audio.rst index eaae5675a47d..aa753336b31f 100644 --- a/Documentation/userspace-api/media/dvb/audio.rst +++ b/Documentation/userspace-api/media/dvb/audio.rst @@ -11,7 +11,7 @@ TV hardware. It can be accessed through ``/dev/dvb/adapter?/audio?``. Data types and ioctl definitions can be accessed by including ``linux/dvb/audio.h`` in your application. -Please note that some Digital TV cards don’t have their own MPEG decoder, which +Please note that some Digital TV cards don't have their own MPEG decoder, which results in the omission of the audio and video device. These ioctls were also used by V4L2 to control MPEG decoders implemented diff --git a/Documentation/userspace-api/media/dvb/dmx-fopen.rst b/Documentation/userspace-api/media/dvb/dmx-fopen.rst index 8f0a2b831d4a..50b36eb4371e 100644 --- a/Documentation/userspace-api/media/dvb/dmx-fopen.rst +++ b/Documentation/userspace-api/media/dvb/dmx-fopen.rst @@ -82,7 +82,7 @@ appropriately. :widths: 1 16 - - ``EMFILE`` - - “Too many open files”, i.e. no more filters available. + - "Too many open files", i.e. no more filters available. The generic error codes are described at the :ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/dmx-fread.rst b/Documentation/userspace-api/media/dvb/dmx-fread.rst index 78e9daef595a..88c4cddf7c30 100644 --- a/Documentation/userspace-api/media/dvb/dmx-fread.rst +++ b/Documentation/userspace-api/media/dvb/dmx-fread.rst @@ -34,7 +34,7 @@ Description This system call returns filtered data, which might be section or Packetized Elementary Stream (PES) data. The filtered data is transferred from -the driver’s internal circular buffer to ``buf``. The maximum amount of data +the driver's internal circular buffer to ``buf``. The maximum amount of data to be transferred is implied by count. .. note:: diff --git a/Documentation/userspace-api/media/dvb/dmx-set-filter.rst b/Documentation/userspace-api/media/dvb/dmx-set-filter.rst index f43455b7adae..1b8c8071b14f 100644 --- a/Documentation/userspace-api/media/dvb/dmx-set-filter.rst +++ b/Documentation/userspace-api/media/dvb/dmx-set-filter.rst @@ -37,7 +37,7 @@ parameters provided. A timeout may be defined stating number of seconds to wait for a section to be loaded. A value of 0 means that no timeout should be applied. Finally there is a flag field where it is possible to state whether a section should be CRC-checked, whether the filter should -be a ”one-shot” filter, i.e. if the filtering operation should be +be a "one-shot" filter, i.e. if the filtering operation should be stopped after the first section is received, and whether the filtering operation should be started immediately (without waiting for a :ref:`DMX_START` ioctl call). If a filter was previously set-up, this diff --git a/Documentation/userspace-api/media/dvb/intro.rst b/Documentation/userspace-api/media/dvb/intro.rst index a935f3914e56..6784ae79657c 100644 --- a/Documentation/userspace-api/media/dvb/intro.rst +++ b/Documentation/userspace-api/media/dvb/intro.rst @@ -107,7 +107,7 @@ Audio and video decoder a Systems on a Chip (SoC) integrated circuit. It may also not be needed for certain usages (e.g. for data-only - uses like “internet over satellite”). + uses like "internet over satellite"). :ref:`stb_components` shows a crude schematic of the control and data flow between those components. @@ -148,9 +148,9 @@ individual devices are called: - ``/dev/dvb/adapterN/caM``, -where ``N`` enumerates the Digital TV cards in a system starting from 0, and +where ``N`` enumerates the Digital TV cards in a system starting from 0, and ``M`` enumerates the devices of each type within each adapter, starting -from 0, too. We will omit the “``/dev/dvb/adapterN/``\ ” in the further +from 0, too. We will omit the "``/dev/dvb/adapterN/``\ " in the further discussion of these devices. More details about the data structures and function calls of all the diff --git a/Documentation/userspace-api/media/dvb/video.rst b/Documentation/userspace-api/media/dvb/video.rst index 38a8d39a1d25..808705b769a1 100644 --- a/Documentation/userspace-api/media/dvb/video.rst +++ b/Documentation/userspace-api/media/dvb/video.rst @@ -16,7 +16,7 @@ stream, not its presentation on the TV or computer screen. On PCs this is typically handled by an associated video4linux device, e.g. **/dev/video**, which allows scaling and defining output windows. -Some Digital TV cards don’t have their own MPEG decoder, which results in the +Some Digital TV cards don't have their own MPEG decoder, which results in the omission of the audio and video device as well as the video4linux device. -- cgit v1.3.1 From 8314b6732ae4e600bb933e108f96ce0176acb09c Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Tue, 1 Jun 2021 10:23:38 +0200 Subject: ima: Define new template fields xattrnames, xattrlengths and xattrvalues This patch defines the new template fields xattrnames, xattrlengths and xattrvalues, which contain respectively a list of xattr names (strings, separated by |), lengths (u32, hex) and values (hex). If an xattr is not present, the name and length are not displayed in the measurement list. Reported-by: kernel test robot (Missing prototype def) Signed-off-by: Roberto Sassu Signed-off-by: Mimi Zohar --- Documentation/security/IMA-templates.rst | 4 ++ include/linux/evm.h | 10 +++++ security/integrity/evm/evm_main.c | 69 +++++++++++++++++++++++++++++++ security/integrity/ima/ima_template.c | 9 ++++ security/integrity/ima/ima_template_lib.c | 64 ++++++++++++++++++++++++++++ security/integrity/ima/ima_template_lib.h | 6 +++ 6 files changed, 162 insertions(+) (limited to 'Documentation') diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst index 65c1ce451d08..6a58760a0a35 100644 --- a/Documentation/security/IMA-templates.rst +++ b/Documentation/security/IMA-templates.rst @@ -78,6 +78,10 @@ descriptors by adding their identifier to the format string - 'iuid': the inode UID; - 'igid': the inode GID; - 'imode': the inode mode; + - 'xattrnames': a list of xattr names (separated by |), only if the xattr is + present; + - 'xattrlengths': a list of xattr lengths (u32), only if the xattr is present; + - 'xattrvalues': a list of xattr values; Below, there is the list of defined template descriptors: diff --git a/include/linux/evm.h b/include/linux/evm.h index 5011a299c251..4c374be70247 100644 --- a/include/linux/evm.h +++ b/include/linux/evm.h @@ -39,6 +39,9 @@ extern int evm_inode_init_security(struct inode *inode, struct xattr *evm); extern bool evm_revalidate_status(const char *xattr_name); extern int evm_protected_xattr_if_enabled(const char *req_xattr_name); +extern int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer, + int buffer_size, char type, + bool canonical_fmt); #ifdef CONFIG_FS_POSIX_ACL extern int posix_xattr_acl(const char *xattrname); #else @@ -120,5 +123,12 @@ static inline int evm_protected_xattr_if_enabled(const char *req_xattr_name) return false; } +static inline int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer, + int buffer_size, char type, + bool canonical_fmt) +{ + return -EOPNOTSUPP; +} + #endif /* CONFIG_EVM */ #endif /* LINUX_EVM_H */ diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index ee4e17a790fb..2c226e634ae9 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -317,6 +317,75 @@ int evm_protected_xattr_if_enabled(const char *req_xattr_name) return evm_protected_xattr_common(req_xattr_name, true); } +/** + * evm_read_protected_xattrs - read EVM protected xattr names, lengths, values + * @dentry: dentry of the read xattrs + * @inode: inode of the read xattrs + * @buffer: buffer xattr names, lengths or values are copied to + * @buffer_size: size of buffer + * @type: n: names, l: lengths, v: values + * @canonical_fmt: data format (true: little endian, false: native format) + * + * Read protected xattr names (separated by |), lengths (u32) or values for a + * given dentry and return the total size of copied data. If buffer is NULL, + * just return the total size. + * + * Returns the total size on success, a negative value on error. + */ +int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer, + int buffer_size, char type, bool canonical_fmt) +{ + struct xattr_list *xattr; + int rc, size, total_size = 0; + + list_for_each_entry_lockless(xattr, &evm_config_xattrnames, list) { + rc = __vfs_getxattr(dentry, d_backing_inode(dentry), + xattr->name, NULL, 0); + if (rc < 0 && rc == -ENODATA) + continue; + else if (rc < 0) + return rc; + + switch (type) { + case 'n': + size = strlen(xattr->name) + 1; + if (buffer) { + if (total_size) + *(buffer + total_size - 1) = '|'; + + memcpy(buffer + total_size, xattr->name, size); + } + break; + case 'l': + size = sizeof(u32); + if (buffer) { + if (canonical_fmt) + rc = cpu_to_le32(rc); + + *(u32 *)(buffer + total_size) = rc; + } + break; + case 'v': + size = rc; + if (buffer) { + rc = __vfs_getxattr(dentry, + d_backing_inode(dentry), xattr->name, + buffer + total_size, + buffer_size - total_size); + if (rc < 0) + return rc; + } + break; + default: + return -EINVAL; + } + + total_size += size; + } + + return total_size; +} + /** * evm_verifyxattr - verify the integrity of the requested xattr * @dentry: object of the verify xattr diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 43784f2bf8bd..159a31d2fcdf 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -53,6 +53,15 @@ static const struct ima_template_field supported_fields[] = { .field_show = ima_show_template_uint}, {.field_id = "imode", .field_init = ima_eventinodemode_init, .field_show = ima_show_template_uint}, + {.field_id = "xattrnames", + .field_init = ima_eventinodexattrnames_init, + .field_show = ima_show_template_string}, + {.field_id = "xattrlengths", + .field_init = ima_eventinodexattrlengths_init, + .field_show = ima_show_template_sig}, + {.field_id = "xattrvalues", + .field_init = ima_eventinodexattrvalues_init, + .field_show = ima_show_template_sig}, }; /* diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 3156fb34b1af..518fd50ea48a 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -11,6 +11,7 @@ #include "ima_template_lib.h" #include +#include static bool ima_template_hash_algo_allowed(u8 algo) { @@ -618,3 +619,66 @@ int ima_eventinodemode_init(struct ima_event_data *event_data, return ima_write_template_field_data((char *)&mode, sizeof(mode), DATA_FMT_UINT, field_data); } + +static int ima_eventinodexattrs_init_common(struct ima_event_data *event_data, + struct ima_field_data *field_data, + char type) +{ + u8 *buffer = NULL; + int rc; + + if (!event_data->file) + return 0; + + rc = evm_read_protected_xattrs(file_dentry(event_data->file), NULL, 0, + type, ima_canonical_fmt); + if (rc < 0) + return 0; + + buffer = kmalloc(rc, GFP_KERNEL); + if (!buffer) + return 0; + + rc = evm_read_protected_xattrs(file_dentry(event_data->file), buffer, + rc, type, ima_canonical_fmt); + if (rc < 0) { + rc = 0; + goto out; + } + + rc = ima_write_template_field_data((char *)buffer, rc, DATA_FMT_HEX, + field_data); +out: + kfree(buffer); + return rc; +} + +/* + * ima_eventinodexattrnames_init - include a list of xattr names as part of the + * template data + */ +int ima_eventinodexattrnames_init(struct ima_event_data *event_data, + struct ima_field_data *field_data) +{ + return ima_eventinodexattrs_init_common(event_data, field_data, 'n'); +} + +/* + * ima_eventinodexattrlengths_init - include a list of xattr lengths as part of + * the template data + */ +int ima_eventinodexattrlengths_init(struct ima_event_data *event_data, + struct ima_field_data *field_data) +{ + return ima_eventinodexattrs_init_common(event_data, field_data, 'l'); +} + +/* + * ima_eventinodexattrvalues_init - include a list of xattr values as part of + * the template data + */ +int ima_eventinodexattrvalues_init(struct ima_event_data *event_data, + struct ima_field_data *field_data) +{ + return ima_eventinodexattrs_init_common(event_data, field_data, 'v'); +} diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h index 6509af4a97ee..c71f1de95753 100644 --- a/security/integrity/ima/ima_template_lib.h +++ b/security/integrity/ima/ima_template_lib.h @@ -56,4 +56,10 @@ int ima_eventinodegid_init(struct ima_event_data *event_data, struct ima_field_data *field_data); int ima_eventinodemode_init(struct ima_event_data *event_data, struct ima_field_data *field_data); +int ima_eventinodexattrnames_init(struct ima_event_data *event_data, + struct ima_field_data *field_data); +int ima_eventinodexattrlengths_init(struct ima_event_data *event_data, + struct ima_field_data *field_data); +int ima_eventinodexattrvalues_init(struct ima_event_data *event_data, + struct ima_field_data *field_data); #endif /* __LINUX_IMA_TEMPLATE_LIB_H */ -- cgit v1.3.1 From 937264905aa21655cb1142146997f211153e6e27 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 25 May 2021 10:48:46 +0200 Subject: crypto: ixp4xx - Add DT bindings This adds device tree bindings for the ixp4xx crypto engine. Cc: Corentin Labbe Cc: devicetree@vger.kernel.org Signed-off-by: Linus Walleij Reviewed-by: Rob Herring Signed-off-by: Herbert Xu --- .../bindings/crypto/intel,ixp4xx-crypto.yaml | 47 ++++++++++++++++++++++ .../intel,ixp4xx-network-processing-engine.yaml | 22 ++++++++-- 2 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 Documentation/devicetree/bindings/crypto/intel,ixp4xx-crypto.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/crypto/intel,ixp4xx-crypto.yaml b/Documentation/devicetree/bindings/crypto/intel,ixp4xx-crypto.yaml new file mode 100644 index 000000000000..9c53c27bd20a --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/intel,ixp4xx-crypto.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2018 Linaro Ltd. +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/crypto/intel,ixp4xx-crypto.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Intel IXP4xx cryptographic engine + +maintainers: + - Linus Walleij + +description: | + The Intel IXP4xx cryptographic engine makes use of the IXP4xx NPE + (Network Processing Engine). Since it is not a device on its own + it is defined as a subnode of the NPE, if crypto support is + available on the platform. + +properties: + compatible: + const: intel,ixp4xx-crypto + + intel,npe-handle: + $ref: '/schemas/types.yaml#/definitions/phandle-array' + maxItems: 1 + description: phandle to the NPE this crypto engine is using, the cell + describing the NPE instance to be used. + + queue-rx: + $ref: /schemas/types.yaml#/definitions/phandle-array + maxItems: 1 + description: phandle to the RX queue on the NPE, the cell describing + the queue instance to be used. + + queue-txready: + $ref: /schemas/types.yaml#/definitions/phandle-array + maxItems: 1 + description: phandle to the TX READY queue on the NPE, the cell describing + the queue instance to be used. + +required: + - compatible + - intel,npe-handle + - queue-rx + - queue-txready + +additionalProperties: false diff --git a/Documentation/devicetree/bindings/firmware/intel,ixp4xx-network-processing-engine.yaml b/Documentation/devicetree/bindings/firmware/intel,ixp4xx-network-processing-engine.yaml index 1bd2870c3a9c..c435c9f369a4 100644 --- a/Documentation/devicetree/bindings/firmware/intel,ixp4xx-network-processing-engine.yaml +++ b/Documentation/devicetree/bindings/firmware/intel,ixp4xx-network-processing-engine.yaml @@ -26,9 +26,16 @@ properties: reg: items: - - description: NPE0 register range - - description: NPE1 register range - - description: NPE2 register range + - description: NPE0 (NPE-A) register range + - description: NPE1 (NPE-B) register range + - description: NPE2 (NPE-C) register range + + crypto: + $ref: /schemas/crypto/intel,ixp4xx-crypto.yaml# + type: object + description: Optional node for the embedded crypto engine, the node + should be named with the instance number of the NPE engine used for + the crypto engine. required: - compatible @@ -38,8 +45,15 @@ additionalProperties: false examples: - | - npe@c8006000 { + npe: npe@c8006000 { compatible = "intel,ixp4xx-network-processing-engine"; reg = <0xc8006000 0x1000>, <0xc8007000 0x1000>, <0xc8008000 0x1000>; + + crypto { + compatible = "intel,ixp4xx-crypto"; + intel,npe-handle = <&npe 2>; + queue-rx = <&qmgr 30>; + queue-txready = <&qmgr 29>; + }; }; ... -- cgit v1.3.1 From d031d99b02eaf7363c33f5b27b38086cc8104082 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 24 May 2021 11:34:48 +0200 Subject: ASoC: meson: gx-card: fix sound-dai dt schema There is a fair amount of warnings when running 'make dtbs_check' with amlogic,gx-sound-card.yaml. Ex: arch/arm64/boot/dts/amlogic/meson-gxm-q200.dt.yaml: sound: dai-link-0:sound-dai:0:1: missing phandle tag in 0 arch/arm64/boot/dts/amlogic/meson-gxm-q200.dt.yaml: sound: dai-link-0:sound-dai:0:2: missing phandle tag in 0 arch/arm64/boot/dts/amlogic/meson-gxm-q200.dt.yaml: sound: dai-link-0:sound-dai:0: [66, 0, 0] is too long The reason is that the sound-dai phandle provided has cells, and in such case the schema should use 'phandle-array' instead of 'phandle'. Fixes: fd00366b8e41 ("ASoC: meson: gx: add sound card dt-binding documentation") Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210524093448.357140-1-jbrunet@baylibre.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml index db61f0731a20..2e35aeaa8781 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml +++ b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml @@ -57,7 +57,7 @@ patternProperties: rate sound-dai: - $ref: /schemas/types.yaml#/definitions/phandle + $ref: /schemas/types.yaml#/definitions/phandle-array description: phandle of the CPU DAI patternProperties: @@ -71,7 +71,7 @@ patternProperties: properties: sound-dai: - $ref: /schemas/types.yaml#/definitions/phandle + $ref: /schemas/types.yaml#/definitions/phandle-array description: phandle of the codec DAI required: -- cgit v1.3.1 From 1623d767c7ec563d6e52ab76426377bfdde68f97 Mon Sep 17 00:00:00 2001 From: ChiYuan Huang Date: Thu, 3 Jun 2021 13:57:23 +0800 Subject: regulator: rt6245: Add the binding document for Richtek RT6245 Add the binding document for Richtek RT6245. Signed-off-by: ChiYuan Huang Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/1622699844-19203-1-git-send-email-u0084500@gmail.com Signed-off-by: Mark Brown --- .../regulator/richtek,rt6245-regulator.yaml | 89 ++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/richtek,rt6245-regulator.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/richtek,rt6245-regulator.yaml b/Documentation/devicetree/bindings/regulator/richtek,rt6245-regulator.yaml new file mode 100644 index 000000000000..796ceac87445 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/richtek,rt6245-regulator.yaml @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/richtek,rt6245-regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Richtek RT6245 High Current Voltage Regulator + +maintainers: + - ChiYuan Huang + +description: | + The RT6245 is a high-performance, synchronous step-down converter + that can deliver up to 14A output current with an input supply + voltage range of 4.5V to 17V. + +allOf: + - $ref: regulator.yaml# + +properties: + compatible: + enum: + - richtek,rt6245 + + reg: + maxItems: 1 + + enable-gpios: + description: | + A connection of the chip 'enable' gpio line. If not provided, + it will be treat as a default-on power. + maxItems: 1 + + richtek,oc-level-select: + $ref: "/schemas/types.yaml#/definitions/uint8" + enum: [0, 1, 2, 3] + description: | + Over current level selection. Each respective value means the current + limit 8A, 14A, 12A, 10A. If this property is missing then keep in + in chip default. + + richtek,ot-level-select: + $ref: "/schemas/types.yaml#/definitions/uint8" + enum: [0, 1, 2] + description: | + Over temperature level selection. Each respective value means the degree + 150'c, 130'c, 170'c. If this property is missing then keep in chip + default. + + richtek,pgdly-time-select: + $ref: "/schemas/types.yaml#/definitions/uint8" + enum: [0, 1, 2, 3] + description: | + Power good signal delay time selection. Each respective value means the + delay time 0us, 10us, 20us, 40us. If this property is missing then keep + in chip default. + + + richtek,switch-freq-select: + $ref: "/schemas/types.yaml#/definitions/uint8" + enum: [0, 1, 2] + description: | + Buck switch frequency selection. Each respective value means 400KHz, + 800KHz, 1200KHz. If this property is missing then keep in chip default. + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + rt6245@34 { + compatible = "richtek,rt6245"; + status = "okay"; + reg = <0x34>; + enable-gpios = <&gpio26 2 0>; + + regulator-name = "rt6245-regulator"; + regulator-min-microvolt = <437500>; + regulator-max-microvolt = <1387500>; + regulator-boot-on; + }; + }; -- cgit v1.3.1 From 88016de3ab075790e1f1bf047576e9b557c22d19 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Thu, 3 Jun 2021 15:17:05 +0200 Subject: ima: Define new template evm-sig With the recent introduction of the evmsig template field, remote verifiers can obtain the EVM portable signature instead of the IMA signature, to verify file metadata. After introducing the new fields to include file metadata in the measurement list, this patch finally defines the evm-sig template, whose format is: d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode xattrnames, xattrlengths and xattrvalues are populated only from defined EVM protected xattrs, i.e. the ones that EVM considers to verify the portable signature. xattrnames and xattrlengths are populated only if the xattr is present. xattrnames and xattrlengths are not necessary for verifying the EVM portable signature, but they are included for completeness of information, if a remote verifier wants to infer more from file metadata. Signed-off-by: Roberto Sassu Signed-off-by: Mimi Zohar --- Documentation/security/IMA-templates.rst | 1 + security/integrity/ima/ima_template.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst index 6a58760a0a35..5adc22f99496 100644 --- a/Documentation/security/IMA-templates.rst +++ b/Documentation/security/IMA-templates.rst @@ -91,6 +91,7 @@ Below, there is the list of defined template descriptors: - "ima-sig": its format is ``d-ng|n-ng|sig``; - "ima-buf": its format is ``d-ng|n-ng|buf``; - "ima-modsig": its format is ``d-ng|n-ng|sig|d-modsig|modsig``; + - "evm-sig": its format is ``d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode``; Use diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 159a31d2fcdf..a85963853a91 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -22,6 +22,8 @@ static struct ima_template_desc builtin_templates[] = { {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"}, {.name = "ima-buf", .fmt = "d-ng|n-ng|buf"}, {.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"}, + {.name = "evm-sig", + .fmt = "d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode"}, {.name = "", .fmt = ""}, /* placeholder for a custom format */ }; @@ -69,7 +71,8 @@ static const struct ima_template_field supported_fields[] = { * need to be accounted for since they shouldn't be defined in the same template * description as 'd-ng' and 'n-ng' respectively. */ -#define MAX_TEMPLATE_NAME_LEN sizeof("d-ng|n-ng|sig|buf|d-modisg|modsig") +#define MAX_TEMPLATE_NAME_LEN \ + sizeof("d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode") static struct ima_template_desc *ima_template; static struct ima_template_desc *ima_buf_template; -- cgit v1.3.1 From 793e52d4e77d49737ad83cb11925c98f4907fcb1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 1 Jun 2021 11:41:39 +0200 Subject: media: docs: move DVB audio/video docs to staging The only upstream driver using the API described there is the av7110 driver. As the driver was moved to staging, move the API bits to staging as well. Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/Makefile | 10 +- .../userspace-api/media/audio.h.rst.exceptions | 19 -- .../media/dvb/audio-bilingual-channel-select.rst | 58 ----- .../media/dvb/audio-channel-select.rst | 57 ----- .../userspace-api/media/dvb/audio-clear-buffer.rst | 48 ---- .../userspace-api/media/dvb/audio-continue.rst | 48 ---- .../userspace-api/media/dvb/audio-fclose.rst | 51 ----- .../userspace-api/media/dvb/audio-fopen.rst | 103 --------- .../userspace-api/media/dvb/audio-fwrite.rst | 79 ------- .../media/dvb/audio-get-capabilities.rst | 54 ----- .../userspace-api/media/dvb/audio-get-status.rst | 54 ----- .../userspace-api/media/dvb/audio-pause.rst | 49 ---- .../userspace-api/media/dvb/audio-play.rst | 48 ---- .../media/dvb/audio-select-source.rst | 56 ----- .../userspace-api/media/dvb/audio-set-av-sync.rst | 58 ----- .../media/dvb/audio-set-bypass-mode.rst | 62 ------ .../userspace-api/media/dvb/audio-set-id.rst | 59 ----- .../userspace-api/media/dvb/audio-set-mixer.rst | 53 ----- .../userspace-api/media/dvb/audio-set-mute.rst | 62 ------ .../media/dvb/audio-set-streamtype.rst | 66 ------ .../userspace-api/media/dvb/audio-stop.rst | 48 ---- Documentation/userspace-api/media/dvb/audio.rst | 27 --- .../userspace-api/media/dvb/audio_data_types.rst | 116 ---------- .../media/dvb/audio_function_calls.rst | 30 --- Documentation/userspace-api/media/dvb/headers.rst | 7 - .../userspace-api/media/dvb/legacy_dvb_apis.rst | 7 - .../userspace-api/media/dvb/video-clear-buffer.rst | 54 ----- .../userspace-api/media/dvb/video-command.rst | 96 -------- .../userspace-api/media/dvb/video-continue.rst | 57 ----- .../userspace-api/media/dvb/video-fast-forward.rst | 72 ------ .../userspace-api/media/dvb/video-fclose.rst | 51 ----- .../userspace-api/media/dvb/video-fopen.rst | 111 --------- .../userspace-api/media/dvb/video-freeze.rst | 61 ----- .../userspace-api/media/dvb/video-fwrite.rst | 79 ------- .../media/dvb/video-get-capabilities.rst | 61 ----- .../userspace-api/media/dvb/video-get-event.rst | 105 --------- .../media/dvb/video-get-frame-count.rst | 65 ------ .../userspace-api/media/dvb/video-get-pts.rst | 69 ------ .../userspace-api/media/dvb/video-get-size.rst | 69 ------ .../userspace-api/media/dvb/video-get-status.rst | 72 ------ .../userspace-api/media/dvb/video-play.rst | 57 ----- .../media/dvb/video-select-source.rst | 76 ------- .../userspace-api/media/dvb/video-set-blank.rst | 64 ------ .../media/dvb/video-set-display-format.rst | 60 ----- .../userspace-api/media/dvb/video-set-format.rst | 82 ------- .../media/dvb/video-set-streamtype.rst | 61 ----- .../userspace-api/media/dvb/video-slowmotion.rst | 72 ------ .../userspace-api/media/dvb/video-stillpicture.rst | 61 ----- .../userspace-api/media/dvb/video-stop.rst | 74 ------ .../userspace-api/media/dvb/video-try-command.rst | 66 ------ Documentation/userspace-api/media/dvb/video.rst | 36 --- .../media/dvb/video_function_calls.rst | 35 --- .../userspace-api/media/dvb/video_types.rst | 248 --------------------- .../userspace-api/media/video.h.rst.exceptions | 39 ---- .../av7110/audio-bilingual-channel-select.rst | 58 +++++ .../staging/media/av7110/audio-channel-select.rst | 57 +++++ .../staging/media/av7110/audio-clear-buffer.rst | 48 ++++ drivers/staging/media/av7110/audio-continue.rst | 48 ++++ drivers/staging/media/av7110/audio-fclose.rst | 51 +++++ drivers/staging/media/av7110/audio-fopen.rst | 103 +++++++++ drivers/staging/media/av7110/audio-fwrite.rst | 79 +++++++ .../media/av7110/audio-get-capabilities.rst | 54 +++++ drivers/staging/media/av7110/audio-get-status.rst | 54 +++++ drivers/staging/media/av7110/audio-pause.rst | 49 ++++ drivers/staging/media/av7110/audio-play.rst | 48 ++++ .../staging/media/av7110/audio-select-source.rst | 56 +++++ drivers/staging/media/av7110/audio-set-av-sync.rst | 58 +++++ .../staging/media/av7110/audio-set-bypass-mode.rst | 62 ++++++ drivers/staging/media/av7110/audio-set-id.rst | 59 +++++ drivers/staging/media/av7110/audio-set-mixer.rst | 53 +++++ drivers/staging/media/av7110/audio-set-mute.rst | 62 ++++++ .../staging/media/av7110/audio-set-streamtype.rst | 66 ++++++ drivers/staging/media/av7110/audio-stop.rst | 48 ++++ drivers/staging/media/av7110/audio.rst | 27 +++ drivers/staging/media/av7110/audio_data_types.rst | 116 ++++++++++ .../staging/media/av7110/audio_function_calls.rst | 30 +++ .../staging/media/av7110/video-clear-buffer.rst | 54 +++++ drivers/staging/media/av7110/video-command.rst | 96 ++++++++ drivers/staging/media/av7110/video-continue.rst | 57 +++++ .../staging/media/av7110/video-fast-forward.rst | 72 ++++++ drivers/staging/media/av7110/video-fclose.rst | 51 +++++ drivers/staging/media/av7110/video-fopen.rst | 111 +++++++++ drivers/staging/media/av7110/video-freeze.rst | 61 +++++ drivers/staging/media/av7110/video-fwrite.rst | 79 +++++++ .../media/av7110/video-get-capabilities.rst | 61 +++++ drivers/staging/media/av7110/video-get-event.rst | 105 +++++++++ .../staging/media/av7110/video-get-frame-count.rst | 65 ++++++ drivers/staging/media/av7110/video-get-pts.rst | 69 ++++++ drivers/staging/media/av7110/video-get-size.rst | 69 ++++++ drivers/staging/media/av7110/video-get-status.rst | 72 ++++++ drivers/staging/media/av7110/video-play.rst | 57 +++++ .../staging/media/av7110/video-select-source.rst | 76 +++++++ drivers/staging/media/av7110/video-set-blank.rst | 64 ++++++ .../media/av7110/video-set-display-format.rst | 60 +++++ drivers/staging/media/av7110/video-set-format.rst | 82 +++++++ .../staging/media/av7110/video-set-streamtype.rst | 61 +++++ drivers/staging/media/av7110/video-slowmotion.rst | 72 ++++++ .../staging/media/av7110/video-stillpicture.rst | 61 +++++ drivers/staging/media/av7110/video-stop.rst | 74 ++++++ drivers/staging/media/av7110/video-try-command.rst | 66 ++++++ drivers/staging/media/av7110/video.rst | 36 +++ .../staging/media/av7110/video_function_calls.rst | 35 +++ drivers/staging/media/av7110/video_types.rst | 248 +++++++++++++++++++++ 103 files changed, 3302 insertions(+), 3380 deletions(-) delete mode 100644 Documentation/userspace-api/media/audio.h.rst.exceptions delete mode 100644 Documentation/userspace-api/media/dvb/audio-bilingual-channel-select.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-channel-select.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-clear-buffer.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-continue.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-fclose.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-fopen.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-fwrite.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-get-capabilities.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-get-status.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-pause.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-play.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-select-source.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-set-av-sync.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-set-bypass-mode.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-set-id.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-set-mixer.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-set-mute.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-set-streamtype.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio-stop.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio_data_types.rst delete mode 100644 Documentation/userspace-api/media/dvb/audio_function_calls.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-clear-buffer.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-command.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-continue.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-fast-forward.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-fclose.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-fopen.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-freeze.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-fwrite.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-get-capabilities.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-get-event.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-get-frame-count.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-get-pts.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-get-size.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-get-status.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-play.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-select-source.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-set-blank.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-set-display-format.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-set-format.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-set-streamtype.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-slowmotion.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-stillpicture.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-stop.rst delete mode 100644 Documentation/userspace-api/media/dvb/video-try-command.rst delete mode 100644 Documentation/userspace-api/media/dvb/video.rst delete mode 100644 Documentation/userspace-api/media/dvb/video_function_calls.rst delete mode 100644 Documentation/userspace-api/media/dvb/video_types.rst delete mode 100644 Documentation/userspace-api/media/video.h.rst.exceptions create mode 100644 drivers/staging/media/av7110/audio-bilingual-channel-select.rst create mode 100644 drivers/staging/media/av7110/audio-channel-select.rst create mode 100644 drivers/staging/media/av7110/audio-clear-buffer.rst create mode 100644 drivers/staging/media/av7110/audio-continue.rst create mode 100644 drivers/staging/media/av7110/audio-fclose.rst create mode 100644 drivers/staging/media/av7110/audio-fopen.rst create mode 100644 drivers/staging/media/av7110/audio-fwrite.rst create mode 100644 drivers/staging/media/av7110/audio-get-capabilities.rst create mode 100644 drivers/staging/media/av7110/audio-get-status.rst create mode 100644 drivers/staging/media/av7110/audio-pause.rst create mode 100644 drivers/staging/media/av7110/audio-play.rst create mode 100644 drivers/staging/media/av7110/audio-select-source.rst create mode 100644 drivers/staging/media/av7110/audio-set-av-sync.rst create mode 100644 drivers/staging/media/av7110/audio-set-bypass-mode.rst create mode 100644 drivers/staging/media/av7110/audio-set-id.rst create mode 100644 drivers/staging/media/av7110/audio-set-mixer.rst create mode 100644 drivers/staging/media/av7110/audio-set-mute.rst create mode 100644 drivers/staging/media/av7110/audio-set-streamtype.rst create mode 100644 drivers/staging/media/av7110/audio-stop.rst create mode 100644 drivers/staging/media/av7110/audio.rst create mode 100644 drivers/staging/media/av7110/audio_data_types.rst create mode 100644 drivers/staging/media/av7110/audio_function_calls.rst create mode 100644 drivers/staging/media/av7110/video-clear-buffer.rst create mode 100644 drivers/staging/media/av7110/video-command.rst create mode 100644 drivers/staging/media/av7110/video-continue.rst create mode 100644 drivers/staging/media/av7110/video-fast-forward.rst create mode 100644 drivers/staging/media/av7110/video-fclose.rst create mode 100644 drivers/staging/media/av7110/video-fopen.rst create mode 100644 drivers/staging/media/av7110/video-freeze.rst create mode 100644 drivers/staging/media/av7110/video-fwrite.rst create mode 100644 drivers/staging/media/av7110/video-get-capabilities.rst create mode 100644 drivers/staging/media/av7110/video-get-event.rst create mode 100644 drivers/staging/media/av7110/video-get-frame-count.rst create mode 100644 drivers/staging/media/av7110/video-get-pts.rst create mode 100644 drivers/staging/media/av7110/video-get-size.rst create mode 100644 drivers/staging/media/av7110/video-get-status.rst create mode 100644 drivers/staging/media/av7110/video-play.rst create mode 100644 drivers/staging/media/av7110/video-select-source.rst create mode 100644 drivers/staging/media/av7110/video-set-blank.rst create mode 100644 drivers/staging/media/av7110/video-set-display-format.rst create mode 100644 drivers/staging/media/av7110/video-set-format.rst create mode 100644 drivers/staging/media/av7110/video-set-streamtype.rst create mode 100644 drivers/staging/media/av7110/video-slowmotion.rst create mode 100644 drivers/staging/media/av7110/video-stillpicture.rst create mode 100644 drivers/staging/media/av7110/video-stop.rst create mode 100644 drivers/staging/media/av7110/video-try-command.rst create mode 100644 drivers/staging/media/av7110/video.rst create mode 100644 drivers/staging/media/av7110/video_function_calls.rst create mode 100644 drivers/staging/media/av7110/video_types.rst (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/Makefile b/Documentation/userspace-api/media/Makefile index 81a4a1a53bce..00922aa7efde 100644 --- a/Documentation/userspace-api/media/Makefile +++ b/Documentation/userspace-api/media/Makefile @@ -7,8 +7,8 @@ PARSER = $(srctree)/Documentation/sphinx/parse-headers.pl UAPI = $(srctree)/include/uapi/linux KAPI = $(srctree)/include/linux -FILES = audio.h.rst ca.h.rst dmx.h.rst frontend.h.rst net.h.rst video.h.rst \ - videodev2.h.rst media.h.rst cec.h.rst lirc.h.rst +FILES = ca.h.rst dmx.h.rst frontend.h.rst net.h.rst \ + videodev2.h.rst media.h.rst cec.h.rst lirc.h.rst TARGETS := $(addprefix $(BUILDDIR)/, $(FILES)) @@ -21,9 +21,6 @@ quiet_gen_rst = echo ' PARSE $(patsubst $(srctree)/%,%,$<)'; \ silent_gen_rst = ${gen_rst} -$(BUILDDIR)/audio.h.rst: ${UAPI}/dvb/audio.h ${PARSER} $(SRC_DIR)/audio.h.rst.exceptions - @$($(quiet)gen_rst) - $(BUILDDIR)/ca.h.rst: ${UAPI}/dvb/ca.h ${PARSER} $(SRC_DIR)/ca.h.rst.exceptions @$($(quiet)gen_rst) @@ -36,9 +33,6 @@ $(BUILDDIR)/frontend.h.rst: ${UAPI}/dvb/frontend.h ${PARSER} $(SRC_DIR)/frontend $(BUILDDIR)/net.h.rst: ${UAPI}/dvb/net.h ${PARSER} $(SRC_DIR)/net.h.rst.exceptions @$($(quiet)gen_rst) -$(BUILDDIR)/video.h.rst: ${UAPI}/dvb/video.h ${PARSER} $(SRC_DIR)/video.h.rst.exceptions - @$($(quiet)gen_rst) - $(BUILDDIR)/videodev2.h.rst: ${UAPI}/videodev2.h ${PARSER} $(SRC_DIR)/videodev2.h.rst.exceptions @$($(quiet)gen_rst) diff --git a/Documentation/userspace-api/media/audio.h.rst.exceptions b/Documentation/userspace-api/media/audio.h.rst.exceptions deleted file mode 100644 index cf6620477f73..000000000000 --- a/Documentation/userspace-api/media/audio.h.rst.exceptions +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -# Ignore header name -ignore define _DVBAUDIO_H_ - -# Undocumented audio caps, as this is a deprecated API anyway -ignore define AUDIO_CAP_DTS -ignore define AUDIO_CAP_LPCM -ignore define AUDIO_CAP_MP1 -ignore define AUDIO_CAP_MP2 -ignore define AUDIO_CAP_MP3 -ignore define AUDIO_CAP_AAC -ignore define AUDIO_CAP_OGG -ignore define AUDIO_CAP_SDDS -ignore define AUDIO_CAP_AC3 - -# some typedefs should point to struct/enums -replace typedef audio_mixer_t :c:type:`audio_mixer` -replace typedef audio_status_t :c:type:`audio_status` diff --git a/Documentation/userspace-api/media/dvb/audio-bilingual-channel-select.rst b/Documentation/userspace-api/media/dvb/audio-bilingual-channel-select.rst deleted file mode 100644 index 33b5363317f1..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-bilingual-channel-select.rst +++ /dev/null @@ -1,58 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _AUDIO_BILINGUAL_CHANNEL_SELECT: - -============================== -AUDIO_BILINGUAL_CHANNEL_SELECT -============================== - -Name ----- - -AUDIO_BILINGUAL_CHANNEL_SELECT - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:macro:: AUDIO_BILINGUAL_CHANNEL_SELECT - -``int ioctl(int fd, AUDIO_BILINGUAL_CHANNEL_SELECT, struct audio_channel_select *select)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - audio_channel_select_t ch - - - Select the output format of the audio (mono left/right, stereo). - -Description ------------ - -This ioctl is obsolete. Do not use in new drivers. It has been replaced -by the V4L2 ``V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK`` control -for MPEG decoders controlled through V4L2. - -This ioctl call asks the Audio Device to select the requested channel -for bilingual streams if possible. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/audio-channel-select.rst b/Documentation/userspace-api/media/dvb/audio-channel-select.rst deleted file mode 100644 index 74093df92a68..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-channel-select.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _AUDIO_CHANNEL_SELECT: - -==================== -AUDIO_CHANNEL_SELECT -==================== - -Name ----- - -AUDIO_CHANNEL_SELECT - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:macro:: AUDIO_CHANNEL_SELECT - -``int ioctl(int fd, AUDIO_CHANNEL_SELECT, struct audio_channel_select *select)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - audio_channel_select_t ch - - - Select the output format of the audio (mono left/right, stereo). - -Description ------------ - -This ioctl is for Digital TV devices only. To control a V4L2 decoder use the -V4L2 ``V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK`` control instead. - -This ioctl call asks the Audio Device to select the requested channel if -possible. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/audio-clear-buffer.rst b/Documentation/userspace-api/media/dvb/audio-clear-buffer.rst deleted file mode 100644 index a0ebb0278260..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-clear-buffer.rst +++ /dev/null @@ -1,48 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _AUDIO_CLEAR_BUFFER: - -================== -AUDIO_CLEAR_BUFFER -================== - -Name ----- - -AUDIO_CLEAR_BUFFER - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:macro:: AUDIO_CLEAR_BUFFER - -``int ioctl(int fd, AUDIO_CLEAR_BUFFER)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - -Description ------------ - -This ioctl call asks the Audio Device to clear all software and hardware -buffers of the audio decoder device. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/audio-continue.rst b/Documentation/userspace-api/media/dvb/audio-continue.rst deleted file mode 100644 index a2e9850f37f2..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-continue.rst +++ /dev/null @@ -1,48 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _AUDIO_CONTINUE: - -============== -AUDIO_CONTINUE -============== - -Name ----- - -AUDIO_CONTINUE - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:macro:: AUDIO_CONTINUE - -``int ioctl(int fd, AUDIO_CONTINUE)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - -Description ------------ - -This ioctl restarts the decoding and playing process previously paused -with AUDIO_PAUSE command. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/audio-fclose.rst b/Documentation/userspace-api/media/dvb/audio-fclose.rst deleted file mode 100644 index 77857d578e83..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-fclose.rst +++ /dev/null @@ -1,51 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _audio_fclose: - -======================== -Digital TV audio close() -======================== - -Name ----- - -Digital TV audio close() - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int close(int fd) - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - -Description ------------ - -This system call closes a previously opened audio device. - -Return Value ------------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - ``EBADF`` - - - fd is not a valid open file descriptor. diff --git a/Documentation/userspace-api/media/dvb/audio-fopen.rst b/Documentation/userspace-api/media/dvb/audio-fopen.rst deleted file mode 100644 index 774daaab3bad..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-fopen.rst +++ /dev/null @@ -1,103 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _audio_fopen: - -======================= -Digital TV audio open() -======================= - -Name ----- - -Digital TV audio open() - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int open(const char *deviceName, int flags) - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - const char \*deviceName - - - Name of specific audio device. - - - .. row 2 - - - int flags - - - A bit-wise OR of the following flags: - - - .. row 3 - - - - - O_RDONLY read-only access - - - .. row 4 - - - - - O_RDWR read/write access - - - .. row 5 - - - - - O_NONBLOCK open in non-blocking mode - - - .. row 6 - - - - - (blocking mode is the default) - -Description ------------ - -This system call opens a named audio device (e.g. -/dev/dvb/adapter0/audio0) for subsequent use. When an open() call has -succeeded, the device will be ready for use. The significance of -blocking or non-blocking mode is described in the documentation for -functions where there is a difference. It does not affect the semantics -of the open() call itself. A device opened in blocking mode can later be -put into non-blocking mode (and vice versa) using the F_SETFL command -of the fcntl system call. This is a standard system call, documented in -the Linux manual page for fcntl. Only one user can open the Audio Device -in O_RDWR mode. All other attempts to open the device in this mode will -fail, and an error code will be returned. If the Audio Device is opened -in O_RDONLY mode, the only ioctl call that can be used is -AUDIO_GET_STATUS. All other call will return with an error code. - -Return Value ------------- - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - ``ENODEV`` - - - Device driver not loaded/available. - - - .. row 2 - - - ``EBUSY`` - - - Device or resource busy. - - - .. row 3 - - - ``EINVAL`` - - - Invalid argument. diff --git a/Documentation/userspace-api/media/dvb/audio-fwrite.rst b/Documentation/userspace-api/media/dvb/audio-fwrite.rst deleted file mode 100644 index 7b096ac2b6c4..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-fwrite.rst +++ /dev/null @@ -1,79 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _audio_fwrite: - -========================= -Digital TV audio write() -========================= - -Name ----- - -Digital TV audio write() - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: size_t write(int fd, const void *buf, size_t count) - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - void \*buf - - - Pointer to the buffer containing the PES data. - - - .. row 3 - - - size_t count - - - Size of buf. - -Description ------------ - -This system call can only be used if AUDIO_SOURCE_MEMORY is selected -in the ioctl call AUDIO_SELECT_SOURCE. The data provided shall be in -PES format. If O_NONBLOCK is not specified the function will block -until buffer space is available. The amount of data to be transferred is -implied by count. - -Return Value ------------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - ``EPERM`` - - - Mode AUDIO_SOURCE_MEMORY not selected. - - - .. row 2 - - - ``ENOMEM`` - - - Attempted to write more data than the internal buffer can hold. - - - .. row 3 - - - ``EBADF`` - - - fd is not a valid open file descriptor. diff --git a/Documentation/userspace-api/media/dvb/audio-get-capabilities.rst b/Documentation/userspace-api/media/dvb/audio-get-capabilities.rst deleted file mode 100644 index 6d9eb71dad17..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-get-capabilities.rst +++ /dev/null @@ -1,54 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _AUDIO_GET_CAPABILITIES: - -====================== -AUDIO_GET_CAPABILITIES -====================== - -Name ----- - -AUDIO_GET_CAPABILITIES - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:macro:: AUDIO_GET_CAPABILITIES - -``int ioctl(int fd, AUDIO_GET_CAPABILITIES, unsigned int *cap)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - unsigned int \*cap - - - Returns a bit array of supported sound formats. - -Description ------------ - -This ioctl call asks the Audio Device to tell us about the decoding -capabilities of the audio hardware. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/audio-get-status.rst b/Documentation/userspace-api/media/dvb/audio-get-status.rst deleted file mode 100644 index 7ae8db2e65e9..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-get-status.rst +++ /dev/null @@ -1,54 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _AUDIO_GET_STATUS: - -================ -AUDIO_GET_STATUS -================ - -Name ----- - -AUDIO_GET_STATUS - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:macro:: AUDIO_GET_STATUS - -``int ioctl(int fd, AUDIO_GET_STATUS, struct audio_status *status)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - struct audio_status \*status - - - Returns the current state of Audio Device. - -Description ------------ - -This ioctl call asks the Audio Device to return the current state of the -Audio Device. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/audio-pause.rst b/Documentation/userspace-api/media/dvb/audio-pause.rst deleted file mode 100644 index d37d1ddce4df..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-pause.rst +++ /dev/null @@ -1,49 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _AUDIO_PAUSE: - -=========== -AUDIO_PAUSE -=========== - -Name ----- - -AUDIO_PAUSE - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:macro:: AUDIO_PAUSE - -``int ioctl(int fd, AUDIO_PAUSE)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - -Description ------------ - -This ioctl call suspends the audio stream being played. Decoding and -playing are paused. It is then possible to restart again decoding and -playing process of the audio stream using AUDIO_CONTINUE command. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/audio-play.rst b/Documentation/userspace-api/media/dvb/audio-play.rst deleted file mode 100644 index e591930b6ca7..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-play.rst +++ /dev/null @@ -1,48 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _AUDIO_PLAY: - -========== -AUDIO_PLAY -========== - -Name ----- - -AUDIO_PLAY - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:macro:: AUDIO_PLAY - -``int ioctl(int fd, AUDIO_PLAY)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - -Description ------------ - -This ioctl call asks the Audio Device to start playing an audio stream -from the selected source. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/audio-select-source.rst b/Documentation/userspace-api/media/dvb/audio-select-source.rst deleted file mode 100644 index 6a0c0f365eb1..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-select-source.rst +++ /dev/null @@ -1,56 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _AUDIO_SELECT_SOURCE: - -=================== -AUDIO_SELECT_SOURCE -=================== - -Name ----- - -AUDIO_SELECT_SOURCE - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:macro:: AUDIO_SELECT_SOURCE - -``int ioctl(int fd, AUDIO_SELECT_SOURCE, struct audio_stream_source *source)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - audio_stream_source_t source - - - Indicates the source that shall be used for the Audio stream. - -Description ------------ - -This ioctl call informs the audio device which source shall be used for -the input data. The possible sources are demux or memory. If -AUDIO_SOURCE_MEMORY is selected, the data is fed to the Audio Device -through the write command. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/audio-set-av-sync.rst b/Documentation/userspace-api/media/dvb/audio-set-av-sync.rst deleted file mode 100644 index 85a8016bf025..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-set-av-sync.rst +++ /dev/null @@ -1,58 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _AUDIO_SET_AV_SYNC: - -================= -AUDIO_SET_AV_SYNC -================= - -Name ----- - -AUDIO_SET_AV_SYNC - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:macro:: AUDIO_SET_AV_SYNC - -``int ioctl(int fd, AUDIO_SET_AV_SYNC, boolean state)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - boolean state - - - Tells the Digital TV subsystem if A/V synchronization shall be ON or OFF. - - TRUE: AV-sync ON - - FALSE: AV-sync OFF - -Description ------------ - -This ioctl call asks the Audio Device to turn ON or OFF A/V -synchronization. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/audio-set-bypass-mode.rst b/Documentation/userspace-api/media/dvb/audio-set-bypass-mode.rst deleted file mode 100644 index 80d551a2053a..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-set-bypass-mode.rst +++ /dev/null @@ -1,62 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _AUDIO_SET_BYPASS_MODE: - -===================== -AUDIO_SET_BYPASS_MODE -===================== - -Name ----- - -AUDIO_SET_BYPASS_MODE - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:macro:: AUDIO_SET_BYPASS_MODE - -``int ioctl(int fd, AUDIO_SET_BYPASS_MODE, boolean mode)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - boolean mode - - - Enables or disables the decoding of the current Audio stream in - the Digital TV subsystem. - - TRUE: Bypass is disabled - - FALSE: Bypass is enabled - -Description ------------ - -This ioctl call asks the Audio Device to bypass the Audio decoder and -forward the stream without decoding. This mode shall be used if streams -that can't be handled by the Digital TV system shall be decoded. Dolby -DigitalTM streams are automatically forwarded by the Digital TV subsystem if -the hardware can handle it. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/audio-set-id.rst b/Documentation/userspace-api/media/dvb/audio-set-id.rst deleted file mode 100644 index 39ad846d412d..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-set-id.rst +++ /dev/null @@ -1,59 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _AUDIO_SET_ID: - -============ -AUDIO_SET_ID -============ - -Name ----- - -AUDIO_SET_ID - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:macro:: AUDIO_SET_ID - -``int ioctl(int fd, AUDIO_SET_ID, int id)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - int id - - - audio sub-stream id - -Description ------------ - -This ioctl selects which sub-stream is to be decoded if a program or -system stream is sent to the video device. If no audio stream type is -set the id has to be in [0xC0,0xDF] for MPEG sound, in [0x80,0x87] for -AC3 and in [0xA0,0xA7] for LPCM. More specifications may follow for -other stream types. If the stream type is set the id just specifies the -substream id of the audio stream and only the first 5 bits are -recognized. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/audio-set-mixer.rst b/Documentation/userspace-api/media/dvb/audio-set-mixer.rst deleted file mode 100644 index 45dbdf4801e0..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-set-mixer.rst +++ /dev/null @@ -1,53 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _AUDIO_SET_MIXER: - -=============== -AUDIO_SET_MIXER -=============== - -Name ----- - -AUDIO_SET_MIXER - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:macro:: AUDIO_SET_MIXER - -``int ioctl(int fd, AUDIO_SET_MIXER, struct audio_mixer *mix)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - audio_mixer_t \*mix - - - mixer settings. - -Description ------------ - -This ioctl lets you adjust the mixer settings of the audio decoder. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/audio-set-mute.rst b/Documentation/userspace-api/media/dvb/audio-set-mute.rst deleted file mode 100644 index 987751f92967..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-set-mute.rst +++ /dev/null @@ -1,62 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _AUDIO_SET_MUTE: - -============== -AUDIO_SET_MUTE -============== - -Name ----- - -AUDIO_SET_MUTE - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:macro:: AUDIO_SET_MUTE - -``int ioctl(int fd, AUDIO_SET_MUTE, boolean state)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - boolean state - - - Indicates if audio device shall mute or not. - - TRUE: Audio Mute - - FALSE: Audio Un-mute - -Description ------------ - -This ioctl is for Digital TV devices only. To control a V4L2 decoder use the -V4L2 :ref:`VIDIOC_DECODER_CMD` with the -``V4L2_DEC_CMD_START_MUTE_AUDIO`` flag instead. - -This ioctl call asks the audio device to mute the stream that is -currently being played. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/audio-set-streamtype.rst b/Documentation/userspace-api/media/dvb/audio-set-streamtype.rst deleted file mode 100644 index 77d73c74882f..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-set-streamtype.rst +++ /dev/null @@ -1,66 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _AUDIO_SET_STREAMTYPE: - -==================== -AUDIO_SET_STREAMTYPE -==================== - -Name ----- - -AUDIO_SET_STREAMTYPE - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:macro:: AUDIO_SET_STREAMTYPE - -``int ioctl(fd, AUDIO_SET_STREAMTYPE, int type)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - int type - - - stream type - -Description ------------ - -This ioctl tells the driver which kind of audio stream to expect. This -is useful if the stream offers several audio sub-streams like LPCM and -AC3. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - ``EINVAL`` - - - type is not a valid or supported stream type. diff --git a/Documentation/userspace-api/media/dvb/audio-stop.rst b/Documentation/userspace-api/media/dvb/audio-stop.rst deleted file mode 100644 index d77f786fd797..000000000000 --- a/Documentation/userspace-api/media/dvb/audio-stop.rst +++ /dev/null @@ -1,48 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.audio - -.. _AUDIO_STOP: - -========== -AUDIO_STOP -========== - -Name ----- - -AUDIO_STOP - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:macro:: AUDIO_STOP - -``int ioctl(int fd, AUDIO_STOP)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - -Description ------------ - -This ioctl call asks the Audio Device to stop playing the current -stream. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/audio.rst b/Documentation/userspace-api/media/dvb/audio.rst deleted file mode 100644 index aa753336b31f..000000000000 --- a/Documentation/userspace-api/media/dvb/audio.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _dvb_audio: - -####################### -Digital TV Audio Device -####################### - -The Digital TV audio device controls the MPEG2 audio decoder of the Digital -TV hardware. It can be accessed through ``/dev/dvb/adapter?/audio?``. Data -types and ioctl definitions can be accessed by including -``linux/dvb/audio.h`` in your application. - -Please note that some Digital TV cards don't have their own MPEG decoder, which -results in the omission of the audio and video device. - -These ioctls were also used by V4L2 to control MPEG decoders implemented -in V4L2. The use of these ioctls for that purpose has been made obsolete -and proper V4L2 ioctls or controls have been created to replace that -functionality. - - -.. toctree:: - :maxdepth: 1 - - audio_data_types - audio_function_calls diff --git a/Documentation/userspace-api/media/dvb/audio_data_types.rst b/Documentation/userspace-api/media/dvb/audio_data_types.rst deleted file mode 100644 index 4744529136a8..000000000000 --- a/Documentation/userspace-api/media/dvb/audio_data_types.rst +++ /dev/null @@ -1,116 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _audio_data_types: - -**************** -Audio Data Types -**************** - -This section describes the structures, data types and defines used when -talking to the audio device. - -.. c:type:: audio_stream_source - -The audio stream source is set through the AUDIO_SELECT_SOURCE call -and can take the following values, depending on whether we are replaying -from an internal (demux) or external (user write) source. - - -.. code-block:: c - - typedef enum { - AUDIO_SOURCE_DEMUX, - AUDIO_SOURCE_MEMORY - } audio_stream_source_t; - -AUDIO_SOURCE_DEMUX selects the demultiplexer (fed either by the -frontend or the DVR device) as the source of the video stream. If -AUDIO_SOURCE_MEMORY is selected the stream comes from the application -through the ``write()`` system call. - - -.. c:type:: audio_play_state - -The following values can be returned by the AUDIO_GET_STATUS call -representing the state of audio playback. - - -.. code-block:: c - - typedef enum { - AUDIO_STOPPED, - AUDIO_PLAYING, - AUDIO_PAUSED - } audio_play_state_t; - - -.. c:type:: audio_channel_select - -The audio channel selected via AUDIO_CHANNEL_SELECT is determined by -the following values. - - -.. code-block:: c - - typedef enum { - AUDIO_STEREO, - AUDIO_MONO_LEFT, - AUDIO_MONO_RIGHT, - AUDIO_MONO, - AUDIO_STEREO_SWAPPED - } audio_channel_select_t; - - -.. c:type:: audio_status - -The AUDIO_GET_STATUS call returns the following structure informing -about various states of the playback operation. - - -.. code-block:: c - - typedef struct audio_status { - boolean AV_sync_state; - boolean mute_state; - audio_play_state_t play_state; - audio_stream_source_t stream_source; - audio_channel_select_t channel_select; - boolean bypass_mode; - audio_mixer_t mixer_state; - } audio_status_t; - - -.. c:type:: audio_mixer - -The following structure is used by the AUDIO_SET_MIXER call to set the -audio volume. - - -.. code-block:: c - - typedef struct audio_mixer { - unsigned int volume_left; - unsigned int volume_right; - } audio_mixer_t; - - -.. _audio_encodings: - -audio encodings -=============== - -A call to AUDIO_GET_CAPABILITIES returns an unsigned integer with the -following bits set according to the hardwares capabilities. - - -.. code-block:: c - - #define AUDIO_CAP_DTS 1 - #define AUDIO_CAP_LPCM 2 - #define AUDIO_CAP_MP1 4 - #define AUDIO_CAP_MP2 8 - #define AUDIO_CAP_MP3 16 - #define AUDIO_CAP_AAC 32 - #define AUDIO_CAP_OGG 64 - #define AUDIO_CAP_SDDS 128 - #define AUDIO_CAP_AC3 256 diff --git a/Documentation/userspace-api/media/dvb/audio_function_calls.rst b/Documentation/userspace-api/media/dvb/audio_function_calls.rst deleted file mode 100644 index fa5ba9539caf..000000000000 --- a/Documentation/userspace-api/media/dvb/audio_function_calls.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _audio_function_calls: - -******************** -Audio Function Calls -******************** - -.. toctree:: - :maxdepth: 1 - - audio-fopen - audio-fclose - audio-fwrite - audio-stop - audio-play - audio-pause - audio-continue - audio-select-source - audio-set-mute - audio-set-av-sync - audio-set-bypass-mode - audio-channel-select - audio-bilingual-channel-select - audio-get-status - audio-get-capabilities - audio-clear-buffer - audio-set-id - audio-set-mixer - audio-set-streamtype diff --git a/Documentation/userspace-api/media/dvb/headers.rst b/Documentation/userspace-api/media/dvb/headers.rst index 9743ffc35096..88c3eb33a89e 100644 --- a/Documentation/userspace-api/media/dvb/headers.rst +++ b/Documentation/userspace-api/media/dvb/headers.rst @@ -14,10 +14,3 @@ Digital TV uAPI headers .. kernel-include:: $BUILDDIR/ca.h.rst .. kernel-include:: $BUILDDIR/net.h.rst - -Legacy uAPI -*********** - -.. kernel-include:: $BUILDDIR/audio.h.rst - -.. kernel-include:: $BUILDDIR/video.h.rst diff --git a/Documentation/userspace-api/media/dvb/legacy_dvb_apis.rst b/Documentation/userspace-api/media/dvb/legacy_dvb_apis.rst index 6104879d728a..b97d56ee543c 100644 --- a/Documentation/userspace-api/media/dvb/legacy_dvb_apis.rst +++ b/Documentation/userspace-api/media/dvb/legacy_dvb_apis.rst @@ -11,11 +11,6 @@ The APIs described here **should not** be used on new drivers or applications. The DVBv3 frontend API has issues with new delivery systems, including DVB-S2, DVB-T2, ISDB, etc. -There's just one driver for a very legacy hardware using the Digital TV -audio and video APIs. No modern drivers should use it. Instead, audio and -video should be using the V4L2 and ALSA APIs, and the pipelines should -be set via the Media Controller API. - .. attention:: The APIs described here doesn't necessarily reflect the current @@ -28,5 +23,3 @@ be set via the Media Controller API. :maxdepth: 1 frontend_legacy_dvbv3_api - video - audio diff --git a/Documentation/userspace-api/media/dvb/video-clear-buffer.rst b/Documentation/userspace-api/media/dvb/video-clear-buffer.rst deleted file mode 100644 index a7730559bbb2..000000000000 --- a/Documentation/userspace-api/media/dvb/video-clear-buffer.rst +++ /dev/null @@ -1,54 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_CLEAR_BUFFER: - -================== -VIDEO_CLEAR_BUFFER -================== - -Name ----- - -VIDEO_CLEAR_BUFFER - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_CLEAR_BUFFER - -``int ioctl(fd, VIDEO_CLEAR_BUFFER)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_CLEAR_BUFFER for this command. - -Description ------------ - -This ioctl call clears all video buffers in the driver and in the -decoder hardware. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video-command.rst b/Documentation/userspace-api/media/dvb/video-command.rst deleted file mode 100644 index cae9445eb3af..000000000000 --- a/Documentation/userspace-api/media/dvb/video-command.rst +++ /dev/null @@ -1,96 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_COMMAND: - -============= -VIDEO_COMMAND -============= - -Name ----- - -VIDEO_COMMAND - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_COMMAND - -``int ioctl(int fd, VIDEO_COMMAND, struct video_command *cmd)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_COMMAND for this command. - - - .. row 3 - - - struct video_command \*cmd - - - Commands the decoder. - -Description ------------ - -This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders -this ioctl has been replaced by the -:ref:`VIDIOC_DECODER_CMD` ioctl. - -This ioctl commands the decoder. The ``video_command`` struct is a -subset of the ``v4l2_decoder_cmd`` struct, so refer to the -:ref:`VIDIOC_DECODER_CMD` documentation for -more information. - -.. c:type:: video_command - -.. code-block:: c - - /* The structure must be zeroed before use by the application - This ensures it can be extended safely in the future. */ - struct video_command { - __u32 cmd; - __u32 flags; - union { - struct { - __u64 pts; - } stop; - - struct { - /* 0 or 1000 specifies normal speed, - 1 specifies forward single stepping, - -1 specifies backward single stepping, - >1: playback at speed/1000 of the normal speed, - <-1: reverse playback at (-speed/1000) of the normal speed. */ - __s32 speed; - __u32 format; - } play; - - struct { - __u32 data[16]; - } raw; - }; - }; - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video-continue.rst b/Documentation/userspace-api/media/dvb/video-continue.rst deleted file mode 100644 index bc34bf3989e4..000000000000 --- a/Documentation/userspace-api/media/dvb/video-continue.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_CONTINUE: - -============== -VIDEO_CONTINUE -============== - -Name ----- - -VIDEO_CONTINUE - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_CONTINUE - -``int ioctl(fd, VIDEO_CONTINUE)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_CONTINUE for this command. - -Description ------------ - -This ioctl is for Digital TV devices only. To control a V4L2 decoder use the -V4L2 :ref:`VIDIOC_DECODER_CMD` instead. - -This ioctl call restarts decoding and playing processes of the video -stream which was played before a call to VIDEO_FREEZE was made. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video-fast-forward.rst b/Documentation/userspace-api/media/dvb/video-fast-forward.rst deleted file mode 100644 index e71fa8d6965b..000000000000 --- a/Documentation/userspace-api/media/dvb/video-fast-forward.rst +++ /dev/null @@ -1,72 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_FAST_FORWARD: - -================== -VIDEO_FAST_FORWARD -================== - -Name ----- - -VIDEO_FAST_FORWARD - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_FAST_FORWARD - -``int ioctl(fd, VIDEO_FAST_FORWARD, int nFrames)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_FAST_FORWARD for this command. - - - .. row 3 - - - int nFrames - - - The number of frames to skip. - -Description ------------ - -This ioctl call asks the Video Device to skip decoding of N number of -I-frames. This call can only be used if VIDEO_SOURCE_MEMORY is -selected. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - ``EPERM`` - - - Mode VIDEO_SOURCE_MEMORY not selected. diff --git a/Documentation/userspace-api/media/dvb/video-fclose.rst b/Documentation/userspace-api/media/dvb/video-fclose.rst deleted file mode 100644 index 01d24d548439..000000000000 --- a/Documentation/userspace-api/media/dvb/video-fclose.rst +++ /dev/null @@ -1,51 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _video_fclose: - -================= -dvb video close() -================= - -Name ----- - -dvb video close() - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int close(int fd) - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - -Description ------------ - -This system call closes a previously opened video device. - -Return Value ------------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - ``EBADF`` - - - fd is not a valid open file descriptor. diff --git a/Documentation/userspace-api/media/dvb/video-fopen.rst b/Documentation/userspace-api/media/dvb/video-fopen.rst deleted file mode 100644 index 1371b083e4e8..000000000000 --- a/Documentation/userspace-api/media/dvb/video-fopen.rst +++ /dev/null @@ -1,111 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _video_fopen: - -================ -dvb video open() -================ - -Name ----- - -dvb video open() - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int open(const char *deviceName, int flags) - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - const char \*deviceName - - - Name of specific video device. - - - .. row 2 - - - int flags - - - A bit-wise OR of the following flags: - - - .. row 3 - - - - - O_RDONLY read-only access - - - .. row 4 - - - - - O_RDWR read/write access - - - .. row 5 - - - - - O_NONBLOCK open in non-blocking mode - - - .. row 6 - - - - - (blocking mode is the default) - -Description ------------ - -This system call opens a named video device (e.g. -/dev/dvb/adapter0/video0) for subsequent use. - -When an open() call has succeeded, the device will be ready for use. The -significance of blocking or non-blocking mode is described in the -documentation for functions where there is a difference. It does not -affect the semantics of the open() call itself. A device opened in -blocking mode can later be put into non-blocking mode (and vice versa) -using the F_SETFL command of the fcntl system call. This is a standard -system call, documented in the Linux manual page for fcntl. Only one -user can open the Video Device in O_RDWR mode. All other attempts to -open the device in this mode will fail, and an error-code will be -returned. If the Video Device is opened in O_RDONLY mode, the only -ioctl call that can be used is VIDEO_GET_STATUS. All other call will -return an error code. - -Return Value ------------- - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - ``ENODEV`` - - - Device driver not loaded/available. - - - .. row 2 - - - ``EINTERNAL`` - - - Internal error. - - - .. row 3 - - - ``EBUSY`` - - - Device or resource busy. - - - .. row 4 - - - ``EINVAL`` - - - Invalid argument. diff --git a/Documentation/userspace-api/media/dvb/video-freeze.rst b/Documentation/userspace-api/media/dvb/video-freeze.rst deleted file mode 100644 index 4321f257cb70..000000000000 --- a/Documentation/userspace-api/media/dvb/video-freeze.rst +++ /dev/null @@ -1,61 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_FREEZE: - -============ -VIDEO_FREEZE -============ - -Name ----- - -VIDEO_FREEZE - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_FREEZE - -``int ioctl(fd, VIDEO_FREEZE)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_FREEZE for this command. - -Description ------------ - -This ioctl is for Digital TV devices only. To control a V4L2 decoder use the -V4L2 :ref:`VIDIOC_DECODER_CMD` instead. - -This ioctl call suspends the live video stream being played. Decoding -and playing are frozen. It is then possible to restart the decoding and -playing process of the video stream using the VIDEO_CONTINUE command. -If VIDEO_SOURCE_MEMORY is selected in the ioctl call -VIDEO_SELECT_SOURCE, the Digital TV subsystem will not decode any more data -until the ioctl call VIDEO_CONTINUE or VIDEO_PLAY is performed. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video-fwrite.rst b/Documentation/userspace-api/media/dvb/video-fwrite.rst deleted file mode 100644 index a07fd7d7a40e..000000000000 --- a/Documentation/userspace-api/media/dvb/video-fwrite.rst +++ /dev/null @@ -1,79 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _video_fwrite: - -================= -dvb video write() -================= - -Name ----- - -dvb video write() - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: size_t write(int fd, const void *buf, size_t count) - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - void \*buf - - - Pointer to the buffer containing the PES data. - - - .. row 3 - - - size_t count - - - Size of buf. - -Description ------------ - -This system call can only be used if VIDEO_SOURCE_MEMORY is selected -in the ioctl call VIDEO_SELECT_SOURCE. The data provided shall be in -PES format, unless the capability allows other formats. If O_NONBLOCK -is not specified the function will block until buffer space is -available. The amount of data to be transferred is implied by count. - -Return Value ------------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - ``EPERM`` - - - Mode VIDEO_SOURCE_MEMORY not selected. - - - .. row 2 - - - ``ENOMEM`` - - - Attempted to write more data than the internal buffer can hold. - - - .. row 3 - - - ``EBADF`` - - - fd is not a valid open file descriptor. diff --git a/Documentation/userspace-api/media/dvb/video-get-capabilities.rst b/Documentation/userspace-api/media/dvb/video-get-capabilities.rst deleted file mode 100644 index 01e09f56656c..000000000000 --- a/Documentation/userspace-api/media/dvb/video-get-capabilities.rst +++ /dev/null @@ -1,61 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_GET_CAPABILITIES: - -====================== -VIDEO_GET_CAPABILITIES -====================== - -Name ----- - -VIDEO_GET_CAPABILITIES - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_GET_CAPABILITIES - -``int ioctl(fd, VIDEO_GET_CAPABILITIES, unsigned int *cap)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_GET_CAPABILITIES for this command. - - - .. row 3 - - - unsigned int \*cap - - - Pointer to a location where to store the capability information. - -Description ------------ - -This ioctl call asks the video device about its decoding capabilities. -On success it returns and integer which has bits set according to the -defines in section ??. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video-get-event.rst b/Documentation/userspace-api/media/dvb/video-get-event.rst deleted file mode 100644 index 90382bc36cfe..000000000000 --- a/Documentation/userspace-api/media/dvb/video-get-event.rst +++ /dev/null @@ -1,105 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_GET_EVENT: - -=============== -VIDEO_GET_EVENT -=============== - -Name ----- - -VIDEO_GET_EVENT - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_GET_EVENT - -``int ioctl(fd, VIDEO_GET_EVENT, struct video_event *ev)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_GET_EVENT for this command. - - - .. row 3 - - - struct video_event \*ev - - - Points to the location where the event, if any, is to be stored. - -Description ------------ - -This ioctl is for Digital TV devices only. To get events from a V4L2 decoder -use the V4L2 :ref:`VIDIOC_DQEVENT` ioctl instead. - -This ioctl call returns an event of type video_event if available. If -an event is not available, the behavior depends on whether the device is -in blocking or non-blocking mode. In the latter case, the call fails -immediately with errno set to ``EWOULDBLOCK``. In the former case, the call -blocks until an event becomes available. The standard Linux poll() -and/or select() system calls can be used with the device file descriptor -to watch for new events. For select(), the file descriptor should be -included in the exceptfds argument, and for poll(), POLLPRI should be -specified as the wake-up condition. Read-only permissions are sufficient -for this ioctl call. - -.. c:type:: video_event - -.. code-block:: c - - struct video_event { - __s32 type; - #define VIDEO_EVENT_SIZE_CHANGED 1 - #define VIDEO_EVENT_FRAME_RATE_CHANGED 2 - #define VIDEO_EVENT_DECODER_STOPPED 3 - #define VIDEO_EVENT_VSYNC 4 - long timestamp; - union { - video_size_t size; - unsigned int frame_rate; /* in frames per 1000sec */ - unsigned char vsync_field; /* unknown/odd/even/progressive */ - } u; - }; - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - ``EWOULDBLOCK`` - - - There is no event pending, and the device is in non-blocking mode. - - - .. row 2 - - - ``EOVERFLOW`` - - - Overflow in event queue - one or more events were lost. diff --git a/Documentation/userspace-api/media/dvb/video-get-frame-count.rst b/Documentation/userspace-api/media/dvb/video-get-frame-count.rst deleted file mode 100644 index b48ac8c58a41..000000000000 --- a/Documentation/userspace-api/media/dvb/video-get-frame-count.rst +++ /dev/null @@ -1,65 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_GET_FRAME_COUNT: - -===================== -VIDEO_GET_FRAME_COUNT -===================== - -Name ----- - -VIDEO_GET_FRAME_COUNT - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_GET_FRAME_COUNT - -``int ioctl(int fd, VIDEO_GET_FRAME_COUNT, __u64 *pts)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_GET_FRAME_COUNT for this command. - - - .. row 3 - - - __u64 \*pts - - - Returns the number of frames displayed since the decoder was - started. - -Description ------------ - -This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders -this ioctl has been replaced by the ``V4L2_CID_MPEG_VIDEO_DEC_FRAME`` -control. - -This ioctl call asks the Video Device to return the number of displayed -frames since the decoder was started. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video-get-pts.rst b/Documentation/userspace-api/media/dvb/video-get-pts.rst deleted file mode 100644 index fedaff41be0b..000000000000 --- a/Documentation/userspace-api/media/dvb/video-get-pts.rst +++ /dev/null @@ -1,69 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_GET_PTS: - -============= -VIDEO_GET_PTS -============= - -Name ----- - -VIDEO_GET_PTS - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_GET_PTS - -``int ioctl(int fd, VIDEO_GET_PTS, __u64 *pts)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_GET_PTS for this command. - - - .. row 3 - - - __u64 \*pts - - - Returns the 33-bit timestamp as defined in ITU T-REC-H.222.0 / - ISO/IEC 13818-1. - - The PTS should belong to the currently played frame if possible, - but may also be a value close to it like the PTS of the last - decoded frame or the last PTS extracted by the PES parser. - -Description ------------ - -This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders -this ioctl has been replaced by the ``V4L2_CID_MPEG_VIDEO_DEC_PTS`` -control. - -This ioctl call asks the Video Device to return the current PTS -timestamp. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video-get-size.rst b/Documentation/userspace-api/media/dvb/video-get-size.rst deleted file mode 100644 index de34331c5bd1..000000000000 --- a/Documentation/userspace-api/media/dvb/video-get-size.rst +++ /dev/null @@ -1,69 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_GET_SIZE: - -============== -VIDEO_GET_SIZE -============== - -Name ----- - -VIDEO_GET_SIZE - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_GET_SIZE - -``int ioctl(int fd, VIDEO_GET_SIZE, video_size_t *size)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_GET_SIZE for this command. - - - .. row 3 - - - video_size_t \*size - - - Returns the size and aspect ratio. - -Description ------------ - -This ioctl returns the size and aspect ratio. - -.. c:type:: video_size_t - -.. code-block::c - - typedef struct { - int w; - int h; - video_format_t aspect_ratio; - } video_size_t; - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video-get-status.rst b/Documentation/userspace-api/media/dvb/video-get-status.rst deleted file mode 100644 index 9b86fbf411d4..000000000000 --- a/Documentation/userspace-api/media/dvb/video-get-status.rst +++ /dev/null @@ -1,72 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_GET_STATUS: - -================ -VIDEO_GET_STATUS -================ - -Name ----- - -VIDEO_GET_STATUS - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_GET_STATUS - -``int ioctl(fd, VIDEO_GET_STATUS, struct video_status *status)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_GET_STATUS for this command. - - - .. row 3 - - - struct video_status \*status - - - Returns the current status of the Video Device. - -Description ------------ - -This ioctl call asks the Video Device to return the current status of -the device. - -.. c:type:: video_status - -.. code-block:: c - - struct video_status { - int video_blank; /* blank video on freeze? */ - video_play_state_t play_state; /* current state of playback */ - video_stream_source_t stream_source; /* current source (demux/memory) */ - video_format_t video_format; /* current aspect ratio of stream*/ - video_displayformat_t display_format;/* selected cropping mode */ - }; - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video-play.rst b/Documentation/userspace-api/media/dvb/video-play.rst deleted file mode 100644 index 35ac8b98fdbf..000000000000 --- a/Documentation/userspace-api/media/dvb/video-play.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_PLAY: - -========== -VIDEO_PLAY -========== - -Name ----- - -VIDEO_PLAY - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_PLAY - -``int ioctl(fd, VIDEO_PLAY)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_PLAY for this command. - -Description ------------ - -This ioctl is for Digital TV devices only. To control a V4L2 decoder use the -V4L2 :ref:`VIDIOC_DECODER_CMD` instead. - -This ioctl call asks the Video Device to start playing a video stream -from the selected source. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video-select-source.rst b/Documentation/userspace-api/media/dvb/video-select-source.rst deleted file mode 100644 index 929a20985d53..000000000000 --- a/Documentation/userspace-api/media/dvb/video-select-source.rst +++ /dev/null @@ -1,76 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_SELECT_SOURCE: - -=================== -VIDEO_SELECT_SOURCE -=================== - -Name ----- - -VIDEO_SELECT_SOURCE - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_SELECT_SOURCE - -``int ioctl(fd, VIDEO_SELECT_SOURCE, video_stream_source_t source)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_SELECT_SOURCE for this command. - - - .. row 3 - - - video_stream_source_t source - - - Indicates which source shall be used for the Video stream. - -Description ------------ - -This ioctl is for Digital TV devices only. This ioctl was also supported by the -V4L2 ivtv driver, but that has been replaced by the ivtv-specific -``IVTV_IOC_PASSTHROUGH_MODE`` ioctl. - -This ioctl call informs the video device which source shall be used for -the input data. The possible sources are demux or memory. If memory is -selected, the data is fed to the video device through the write command. - -.. c:type:: video_stream_source_t - -.. code-block:: c - - typedef enum { - VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */ - VIDEO_SOURCE_MEMORY /* If this source is selected, the stream - comes from the user through the write - system call */ - } video_stream_source_t; - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video-set-blank.rst b/Documentation/userspace-api/media/dvb/video-set-blank.rst deleted file mode 100644 index 70249a6ba125..000000000000 --- a/Documentation/userspace-api/media/dvb/video-set-blank.rst +++ /dev/null @@ -1,64 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_SET_BLANK: - -=============== -VIDEO_SET_BLANK -=============== - -Name ----- - -VIDEO_SET_BLANK - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_SET_BLANK - -``int ioctl(fd, VIDEO_SET_BLANK, boolean mode)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_SET_BLANK for this command. - - - .. row 3 - - - boolean mode - - - TRUE: Blank screen when stop. - - - .. row 4 - - - - - FALSE: Show last decoded frame. - -Description ------------ - -This ioctl call asks the Video Device to blank out the picture. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video-set-display-format.rst b/Documentation/userspace-api/media/dvb/video-set-display-format.rst deleted file mode 100644 index 1de4f40ae732..000000000000 --- a/Documentation/userspace-api/media/dvb/video-set-display-format.rst +++ /dev/null @@ -1,60 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_SET_DISPLAY_FORMAT: - -======================== -VIDEO_SET_DISPLAY_FORMAT -======================== - -Name ----- - -VIDEO_SET_DISPLAY_FORMAT - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_SET_DISPLAY_FORMAT - -``int ioctl(fd, VIDEO_SET_DISPLAY_FORMAT)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_SET_DISPLAY_FORMAT for this command. - - - .. row 3 - - - video_display_format_t format - - - Selects the video format to be used. - -Description ------------ - -This ioctl call asks the Video Device to select the video format to be -applied by the MPEG chip on the video. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video-set-format.rst b/Documentation/userspace-api/media/dvb/video-set-format.rst deleted file mode 100644 index bb64e37ae081..000000000000 --- a/Documentation/userspace-api/media/dvb/video-set-format.rst +++ /dev/null @@ -1,82 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_SET_FORMAT: - -================ -VIDEO_SET_FORMAT -================ - -Name ----- - -VIDEO_SET_FORMAT - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_SET_FORMAT - -``int ioctl(fd, VIDEO_SET_FORMAT, video_format_t format)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_SET_FORMAT for this command. - - - .. row 3 - - - video_format_t format - - - video format of TV as defined in section ??. - -Description ------------ - -This ioctl sets the screen format (aspect ratio) of the connected output -device (TV) so that the output of the decoder can be adjusted -accordingly. - -.. c:type:: video_format_t - -.. code-block:: c - - typedef enum { - VIDEO_FORMAT_4_3, /* Select 4:3 format */ - VIDEO_FORMAT_16_9, /* Select 16:9 format. */ - VIDEO_FORMAT_221_1 /* 2.21:1 */ - } video_format_t; - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - ``EINVAL`` - - - format is not a valid video format. diff --git a/Documentation/userspace-api/media/dvb/video-set-streamtype.rst b/Documentation/userspace-api/media/dvb/video-set-streamtype.rst deleted file mode 100644 index 1f31c048bdbc..000000000000 --- a/Documentation/userspace-api/media/dvb/video-set-streamtype.rst +++ /dev/null @@ -1,61 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_SET_STREAMTYPE: - -==================== -VIDEO_SET_STREAMTYPE -==================== - -Name ----- - -VIDEO_SET_STREAMTYPE - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_SET_STREAMTYPE - -``int ioctl(fd, VIDEO_SET_STREAMTYPE, int type)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_SET_STREAMTYPE for this command. - - - .. row 3 - - - int type - - - stream type - -Description ------------ - -This ioctl tells the driver which kind of stream to expect being written -to it. If this call is not used the default of video PES is used. Some -drivers might not support this call and always expect PES. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video-slowmotion.rst b/Documentation/userspace-api/media/dvb/video-slowmotion.rst deleted file mode 100644 index 1478fcc30cb8..000000000000 --- a/Documentation/userspace-api/media/dvb/video-slowmotion.rst +++ /dev/null @@ -1,72 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_SLOWMOTION: - -================ -VIDEO_SLOWMOTION -================ - -Name ----- - -VIDEO_SLOWMOTION - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_SLOWMOTION - -``int ioctl(fd, VIDEO_SLOWMOTION, int nFrames)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_SLOWMOTION for this command. - - - .. row 3 - - - int nFrames - - - The number of times to repeat each frame. - -Description ------------ - -This ioctl call asks the video device to repeat decoding frames N number -of times. This call can only be used if VIDEO_SOURCE_MEMORY is -selected. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - ``EPERM`` - - - Mode VIDEO_SOURCE_MEMORY not selected. diff --git a/Documentation/userspace-api/media/dvb/video-stillpicture.rst b/Documentation/userspace-api/media/dvb/video-stillpicture.rst deleted file mode 100644 index d25384222a20..000000000000 --- a/Documentation/userspace-api/media/dvb/video-stillpicture.rst +++ /dev/null @@ -1,61 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_STILLPICTURE: - -================== -VIDEO_STILLPICTURE -================== - -Name ----- - -VIDEO_STILLPICTURE - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_STILLPICTURE - -``int ioctl(fd, VIDEO_STILLPICTURE, struct video_still_picture *sp)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_STILLPICTURE for this command. - - - .. row 3 - - - struct video_still_picture \*sp - - - Pointer to a location where an I-frame and size is stored. - -Description ------------ - -This ioctl call asks the Video Device to display a still picture -(I-frame). The input data shall contain an I-frame. If the pointer is -NULL, then the current displayed still picture is blanked. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video-stop.rst b/Documentation/userspace-api/media/dvb/video-stop.rst deleted file mode 100644 index 96f61c5b48a2..000000000000 --- a/Documentation/userspace-api/media/dvb/video-stop.rst +++ /dev/null @@ -1,74 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_STOP: - -========== -VIDEO_STOP -========== - -Name ----- - -VIDEO_STOP - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_STOP - -``int ioctl(fd, VIDEO_STOP, boolean mode)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_STOP for this command. - - - .. row 3 - - - Boolean mode - - - Indicates how the screen shall be handled. - - - .. row 4 - - - - - TRUE: Blank screen when stop. - - - .. row 5 - - - - - FALSE: Show last decoded frame. - -Description ------------ - -This ioctl is for Digital TV devices only. To control a V4L2 decoder use the -V4L2 :ref:`VIDIOC_DECODER_CMD` instead. - -This ioctl call asks the Video Device to stop playing the current -stream. Depending on the input parameter, the screen can be blanked out -or displaying the last decoded frame. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video-try-command.rst b/Documentation/userspace-api/media/dvb/video-try-command.rst deleted file mode 100644 index 79bf3dfb8a32..000000000000 --- a/Documentation/userspace-api/media/dvb/video-try-command.rst +++ /dev/null @@ -1,66 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. c:namespace:: DTV.video - -.. _VIDEO_TRY_COMMAND: - -================= -VIDEO_TRY_COMMAND -================= - -Name ----- - -VIDEO_TRY_COMMAND - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:macro:: VIDEO_TRY_COMMAND - -``int ioctl(int fd, VIDEO_TRY_COMMAND, struct video_command *cmd)`` - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_TRY_COMMAND for this command. - - - .. row 3 - - - struct video_command \*cmd - - - Try a decoder command. - -Description ------------ - -This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders -this ioctl has been replaced by the -:ref:`VIDIOC_TRY_DECODER_CMD ` ioctl. - -This ioctl tries a decoder command. The ``video_command`` struct is a -subset of the ``v4l2_decoder_cmd`` struct, so refer to the -:ref:`VIDIOC_TRY_DECODER_CMD ` documentation -for more information. - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/userspace-api/media/dvb/video.rst b/Documentation/userspace-api/media/dvb/video.rst deleted file mode 100644 index 808705b769a1..000000000000 --- a/Documentation/userspace-api/media/dvb/video.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _dvb_video: - -####################### -Digital TV Video Device -####################### - -The Digital TV video device controls the MPEG2 video decoder of the Digital -TV hardware. It can be accessed through **/dev/dvb/adapter0/video0**. Data -types and ioctl definitions can be accessed by including -**linux/dvb/video.h** in your application. - -Note that the Digital TV video device only controls decoding of the MPEG video -stream, not its presentation on the TV or computer screen. On PCs this -is typically handled by an associated video4linux device, e.g. -**/dev/video**, which allows scaling and defining output windows. - -Some Digital TV cards don't have their own MPEG decoder, which results in the -omission of the audio and video device as well as the video4linux -device. - -The ioctls that deal with SPUs (sub picture units) and navigation -packets are only supported on some MPEG decoders made for DVD playback. - -These ioctls were also used by V4L2 to control MPEG decoders implemented -in V4L2. The use of these ioctls for that purpose has been made obsolete -and proper V4L2 ioctls or controls have been created to replace that -functionality. - - -.. toctree:: - :maxdepth: 1 - - video_types - video_function_calls diff --git a/Documentation/userspace-api/media/dvb/video_function_calls.rst b/Documentation/userspace-api/media/dvb/video_function_calls.rst deleted file mode 100644 index 20a897be5dca..000000000000 --- a/Documentation/userspace-api/media/dvb/video_function_calls.rst +++ /dev/null @@ -1,35 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _video_function_calls: - -******************** -Video Function Calls -******************** - -.. toctree:: - :maxdepth: 1 - - video-fopen - video-fclose - video-fwrite - video-stop - video-play - video-freeze - video-continue - video-select-source - video-set-blank - video-get-status - video-get-frame-count - video-get-pts - video-get-event - video-command - video-try-command - video-get-size - video-set-display-format - video-stillpicture - video-fast-forward - video-slowmotion - video-get-capabilities - video-clear-buffer - video-set-streamtype - video-set-format diff --git a/Documentation/userspace-api/media/dvb/video_types.rst b/Documentation/userspace-api/media/dvb/video_types.rst deleted file mode 100644 index c4557d328b7a..000000000000 --- a/Documentation/userspace-api/media/dvb/video_types.rst +++ /dev/null @@ -1,248 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _video_types: - -**************** -Video Data Types -**************** - - -.. _video-format-t: - -video_format_t -============== - -The ``video_format_t`` data type defined by - - -.. code-block:: c - - typedef enum { - VIDEO_FORMAT_4_3, /* Select 4:3 format */ - VIDEO_FORMAT_16_9, /* Select 16:9 format. */ - VIDEO_FORMAT_221_1 /* 2.21:1 */ - } video_format_t; - -is used in the VIDEO_SET_FORMAT function (??) to tell the driver which -aspect ratio the output hardware (e.g. TV) has. It is also used in the -data structures video_status (??) returned by VIDEO_GET_STATUS (??) -and video_event (??) returned by VIDEO_GET_EVENT (??) which report -about the display format of the current video stream. - - -.. _video-displayformat-t: - -video_displayformat_t -===================== - -In case the display format of the video stream and of the display -hardware differ the application has to specify how to handle the -cropping of the picture. This can be done using the -VIDEO_SET_DISPLAY_FORMAT call (??) which accepts - - -.. code-block:: c - - typedef enum { - VIDEO_PAN_SCAN, /* use pan and scan format */ - VIDEO_LETTER_BOX, /* use letterbox format */ - VIDEO_CENTER_CUT_OUT /* use center cut out format */ - } video_displayformat_t; - -as argument. - - -.. _video-stream-source-t: - -video_stream_source_t -===================== - -The video stream source is set through the VIDEO_SELECT_SOURCE call -and can take the following values, depending on whether we are replaying -from an internal (demuxer) or external (user write) source. - - -.. code-block:: c - - typedef enum { - VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */ - VIDEO_SOURCE_MEMORY /* If this source is selected, the stream - comes from the user through the write - system call */ - } video_stream_source_t; - -VIDEO_SOURCE_DEMUX selects the demultiplexer (fed either by the -frontend or the DVR device) as the source of the video stream. If -VIDEO_SOURCE_MEMORY is selected the stream comes from the application -through the **write()** system call. - - -.. _video-play-state-t: - -video_play_state_t -================== - -The following values can be returned by the VIDEO_GET_STATUS call -representing the state of video playback. - - -.. code-block:: c - - typedef enum { - VIDEO_STOPPED, /* Video is stopped */ - VIDEO_PLAYING, /* Video is currently playing */ - VIDEO_FREEZED /* Video is freezed */ - } video_play_state_t; - - -.. c:type:: video_command - -struct video_command -==================== - -The structure must be zeroed before use by the application This ensures -it can be extended safely in the future. - - -.. code-block:: c - - struct video_command { - __u32 cmd; - __u32 flags; - union { - struct { - __u64 pts; - } stop; - - struct { - /* 0 or 1000 specifies normal speed, - 1 specifies forward single stepping, - -1 specifies backward single stepping, - >>1: playback at speed/1000 of the normal speed, - <-1: reverse playback at (-speed/1000) of the normal speed. */ - __s32 speed; - __u32 format; - } play; - - struct { - __u32 data[16]; - } raw; - }; - }; - - -.. _video-size-t: - -video_size_t -============ - - -.. code-block:: c - - typedef struct { - int w; - int h; - video_format_t aspect_ratio; - } video_size_t; - - -.. c:type:: video_event - -struct video_event -================== - -The following is the structure of a video event as it is returned by the -VIDEO_GET_EVENT call. - - -.. code-block:: c - - struct video_event { - __s32 type; - #define VIDEO_EVENT_SIZE_CHANGED 1 - #define VIDEO_EVENT_FRAME_RATE_CHANGED 2 - #define VIDEO_EVENT_DECODER_STOPPED 3 - #define VIDEO_EVENT_VSYNC 4 - long timestamp; - union { - video_size_t size; - unsigned int frame_rate; /* in frames per 1000sec */ - unsigned char vsync_field; /* unknown/odd/even/progressive */ - } u; - }; - - -.. c:type:: video_status - -struct video_status -=================== - -The VIDEO_GET_STATUS call returns the following structure informing -about various states of the playback operation. - - -.. code-block:: c - - struct video_status { - int video_blank; /* blank video on freeze? */ - video_play_state_t play_state; /* current state of playback */ - video_stream_source_t stream_source; /* current source (demux/memory) */ - video_format_t video_format; /* current aspect ratio of stream */ - video_displayformat_t display_format;/* selected cropping mode */ - }; - -If video_blank is set video will be blanked out if the channel is -changed or if playback is stopped. Otherwise, the last picture will be -displayed. play_state indicates if the video is currently frozen, -stopped, or being played back. The stream_source corresponds to the -selected source for the video stream. It can come either from the -demultiplexer or from memory. The video_format indicates the aspect -ratio (one of 4:3 or 16:9) of the currently played video stream. -Finally, display_format corresponds to the selected cropping mode in -case the source video format is not the same as the format of the output -device. - - -.. c:type:: video_still_picture - -struct video_still_picture -========================== - -An I-frame displayed via the VIDEO_STILLPICTURE call is passed on -within the following structure. - - -.. code-block:: c - - /* pointer to and size of a single iframe in memory */ - struct video_still_picture { - char *iFrame; /* pointer to a single iframe in memory */ - int32_t size; - }; - - -.. _video_caps: - -video capabilities -================== - -A call to VIDEO_GET_CAPABILITIES returns an unsigned integer with the -following bits set according to the hardwares capabilities. - - -.. code-block:: c - - /* bit definitions for capabilities: */ - /* can the hardware decode MPEG1 and/or MPEG2? */ - #define VIDEO_CAP_MPEG1 1 - #define VIDEO_CAP_MPEG2 2 - /* can you send a system and/or program stream to video device? - (you still have to open the video and the audio device but only - send the stream to the video device) */ - #define VIDEO_CAP_SYS 4 - #define VIDEO_CAP_PROG 8 - /* can the driver also handle SPU, NAVI and CSS encoded data? - (CSS API is not present yet) */ - #define VIDEO_CAP_SPU 16 - #define VIDEO_CAP_NAVI 32 - #define VIDEO_CAP_CSS 64 diff --git a/Documentation/userspace-api/media/video.h.rst.exceptions b/Documentation/userspace-api/media/video.h.rst.exceptions deleted file mode 100644 index ea9de59ad8b7..000000000000 --- a/Documentation/userspace-api/media/video.h.rst.exceptions +++ /dev/null @@ -1,39 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -# Ignore header name -ignore define _UAPI_DVBVIDEO_H_ - -# This is a deprecated obscure API. Just ignore things we don't know -ignore define VIDEO_CMD_PLAY -ignore define VIDEO_CMD_STOP -ignore define VIDEO_CMD_FREEZE -ignore define VIDEO_CMD_CONTINUE -ignore define VIDEO_CMD_FREEZE_TO_BLACK -ignore define VIDEO_CMD_STOP_TO_BLACK -ignore define VIDEO_CMD_STOP_IMMEDIATELY -ignore define VIDEO_PLAY_FMT_NONE -ignore define VIDEO_PLAY_FMT_GOP -ignore define VIDEO_VSYNC_FIELD_UNKNOWN -ignore define VIDEO_VSYNC_FIELD_ODD -ignore define VIDEO_VSYNC_FIELD_EVEN -ignore define VIDEO_VSYNC_FIELD_PROGRESSIVE -ignore define VIDEO_EVENT_SIZE_CHANGED -ignore define VIDEO_EVENT_FRAME_RATE_CHANGED -ignore define VIDEO_EVENT_DECODER_STOPPED -ignore define VIDEO_EVENT_VSYNC -ignore define VIDEO_CAP_MPEG1 -ignore define VIDEO_CAP_MPEG2 -ignore define VIDEO_CAP_SYS -ignore define VIDEO_CAP_PROG -ignore define VIDEO_CAP_SPU -ignore define VIDEO_CAP_NAVI -ignore define VIDEO_CAP_CSS - -# some typedefs should point to struct/enums -replace typedef video_format_t :c:type:`video_format` -replace typedef video_system_t :c:type:`video_system` -replace typedef video_displayformat_t :c:type:`video_displayformat` -replace typedef video_size_t :c:type:`video_size` -replace typedef video_stream_source_t :c:type:`video_stream_source` -replace typedef video_play_state_t :c:type:`video_play_state` -replace typedef video_navi_pack_t :c:type:`video_navi_pack` diff --git a/drivers/staging/media/av7110/audio-bilingual-channel-select.rst b/drivers/staging/media/av7110/audio-bilingual-channel-select.rst new file mode 100644 index 000000000000..33b5363317f1 --- /dev/null +++ b/drivers/staging/media/av7110/audio-bilingual-channel-select.rst @@ -0,0 +1,58 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_BILINGUAL_CHANNEL_SELECT: + +============================== +AUDIO_BILINGUAL_CHANNEL_SELECT +============================== + +Name +---- + +AUDIO_BILINGUAL_CHANNEL_SELECT + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_BILINGUAL_CHANNEL_SELECT + +``int ioctl(int fd, AUDIO_BILINGUAL_CHANNEL_SELECT, struct audio_channel_select *select)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - audio_channel_select_t ch + + - Select the output format of the audio (mono left/right, stereo). + +Description +----------- + +This ioctl is obsolete. Do not use in new drivers. It has been replaced +by the V4L2 ``V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK`` control +for MPEG decoders controlled through V4L2. + +This ioctl call asks the Audio Device to select the requested channel +for bilingual streams if possible. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/audio-channel-select.rst b/drivers/staging/media/av7110/audio-channel-select.rst new file mode 100644 index 000000000000..74093df92a68 --- /dev/null +++ b/drivers/staging/media/av7110/audio-channel-select.rst @@ -0,0 +1,57 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_CHANNEL_SELECT: + +==================== +AUDIO_CHANNEL_SELECT +==================== + +Name +---- + +AUDIO_CHANNEL_SELECT + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_CHANNEL_SELECT + +``int ioctl(int fd, AUDIO_CHANNEL_SELECT, struct audio_channel_select *select)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - audio_channel_select_t ch + + - Select the output format of the audio (mono left/right, stereo). + +Description +----------- + +This ioctl is for Digital TV devices only. To control a V4L2 decoder use the +V4L2 ``V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK`` control instead. + +This ioctl call asks the Audio Device to select the requested channel if +possible. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/audio-clear-buffer.rst b/drivers/staging/media/av7110/audio-clear-buffer.rst new file mode 100644 index 000000000000..a0ebb0278260 --- /dev/null +++ b/drivers/staging/media/av7110/audio-clear-buffer.rst @@ -0,0 +1,48 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_CLEAR_BUFFER: + +================== +AUDIO_CLEAR_BUFFER +================== + +Name +---- + +AUDIO_CLEAR_BUFFER + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_CLEAR_BUFFER + +``int ioctl(int fd, AUDIO_CLEAR_BUFFER)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + +Description +----------- + +This ioctl call asks the Audio Device to clear all software and hardware +buffers of the audio decoder device. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/audio-continue.rst b/drivers/staging/media/av7110/audio-continue.rst new file mode 100644 index 000000000000..a2e9850f37f2 --- /dev/null +++ b/drivers/staging/media/av7110/audio-continue.rst @@ -0,0 +1,48 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_CONTINUE: + +============== +AUDIO_CONTINUE +============== + +Name +---- + +AUDIO_CONTINUE + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_CONTINUE + +``int ioctl(int fd, AUDIO_CONTINUE)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + +Description +----------- + +This ioctl restarts the decoding and playing process previously paused +with AUDIO_PAUSE command. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/audio-fclose.rst b/drivers/staging/media/av7110/audio-fclose.rst new file mode 100644 index 000000000000..77857d578e83 --- /dev/null +++ b/drivers/staging/media/av7110/audio-fclose.rst @@ -0,0 +1,51 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _audio_fclose: + +======================== +Digital TV audio close() +======================== + +Name +---- + +Digital TV audio close() + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:function:: int close(int fd) + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + +Description +----------- + +This system call closes a previously opened audio device. + +Return Value +------------ + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EBADF`` + + - fd is not a valid open file descriptor. diff --git a/drivers/staging/media/av7110/audio-fopen.rst b/drivers/staging/media/av7110/audio-fopen.rst new file mode 100644 index 000000000000..774daaab3bad --- /dev/null +++ b/drivers/staging/media/av7110/audio-fopen.rst @@ -0,0 +1,103 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _audio_fopen: + +======================= +Digital TV audio open() +======================= + +Name +---- + +Digital TV audio open() + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:function:: int open(const char *deviceName, int flags) + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - const char \*deviceName + + - Name of specific audio device. + + - .. row 2 + + - int flags + + - A bit-wise OR of the following flags: + + - .. row 3 + + - + - O_RDONLY read-only access + + - .. row 4 + + - + - O_RDWR read/write access + + - .. row 5 + + - + - O_NONBLOCK open in non-blocking mode + + - .. row 6 + + - + - (blocking mode is the default) + +Description +----------- + +This system call opens a named audio device (e.g. +/dev/dvb/adapter0/audio0) for subsequent use. When an open() call has +succeeded, the device will be ready for use. The significance of +blocking or non-blocking mode is described in the documentation for +functions where there is a difference. It does not affect the semantics +of the open() call itself. A device opened in blocking mode can later be +put into non-blocking mode (and vice versa) using the F_SETFL command +of the fcntl system call. This is a standard system call, documented in +the Linux manual page for fcntl. Only one user can open the Audio Device +in O_RDWR mode. All other attempts to open the device in this mode will +fail, and an error code will be returned. If the Audio Device is opened +in O_RDONLY mode, the only ioctl call that can be used is +AUDIO_GET_STATUS. All other call will return with an error code. + +Return Value +------------ + +.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``ENODEV`` + + - Device driver not loaded/available. + + - .. row 2 + + - ``EBUSY`` + + - Device or resource busy. + + - .. row 3 + + - ``EINVAL`` + + - Invalid argument. diff --git a/drivers/staging/media/av7110/audio-fwrite.rst b/drivers/staging/media/av7110/audio-fwrite.rst new file mode 100644 index 000000000000..7b096ac2b6c4 --- /dev/null +++ b/drivers/staging/media/av7110/audio-fwrite.rst @@ -0,0 +1,79 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _audio_fwrite: + +========================= +Digital TV audio write() +========================= + +Name +---- + +Digital TV audio write() + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:function:: size_t write(int fd, const void *buf, size_t count) + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - void \*buf + + - Pointer to the buffer containing the PES data. + + - .. row 3 + + - size_t count + + - Size of buf. + +Description +----------- + +This system call can only be used if AUDIO_SOURCE_MEMORY is selected +in the ioctl call AUDIO_SELECT_SOURCE. The data provided shall be in +PES format. If O_NONBLOCK is not specified the function will block +until buffer space is available. The amount of data to be transferred is +implied by count. + +Return Value +------------ + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EPERM`` + + - Mode AUDIO_SOURCE_MEMORY not selected. + + - .. row 2 + + - ``ENOMEM`` + + - Attempted to write more data than the internal buffer can hold. + + - .. row 3 + + - ``EBADF`` + + - fd is not a valid open file descriptor. diff --git a/drivers/staging/media/av7110/audio-get-capabilities.rst b/drivers/staging/media/av7110/audio-get-capabilities.rst new file mode 100644 index 000000000000..6d9eb71dad17 --- /dev/null +++ b/drivers/staging/media/av7110/audio-get-capabilities.rst @@ -0,0 +1,54 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_GET_CAPABILITIES: + +====================== +AUDIO_GET_CAPABILITIES +====================== + +Name +---- + +AUDIO_GET_CAPABILITIES + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_GET_CAPABILITIES + +``int ioctl(int fd, AUDIO_GET_CAPABILITIES, unsigned int *cap)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - unsigned int \*cap + + - Returns a bit array of supported sound formats. + +Description +----------- + +This ioctl call asks the Audio Device to tell us about the decoding +capabilities of the audio hardware. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/audio-get-status.rst b/drivers/staging/media/av7110/audio-get-status.rst new file mode 100644 index 000000000000..7ae8db2e65e9 --- /dev/null +++ b/drivers/staging/media/av7110/audio-get-status.rst @@ -0,0 +1,54 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_GET_STATUS: + +================ +AUDIO_GET_STATUS +================ + +Name +---- + +AUDIO_GET_STATUS + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_GET_STATUS + +``int ioctl(int fd, AUDIO_GET_STATUS, struct audio_status *status)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - struct audio_status \*status + + - Returns the current state of Audio Device. + +Description +----------- + +This ioctl call asks the Audio Device to return the current state of the +Audio Device. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/audio-pause.rst b/drivers/staging/media/av7110/audio-pause.rst new file mode 100644 index 000000000000..d37d1ddce4df --- /dev/null +++ b/drivers/staging/media/av7110/audio-pause.rst @@ -0,0 +1,49 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_PAUSE: + +=========== +AUDIO_PAUSE +=========== + +Name +---- + +AUDIO_PAUSE + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_PAUSE + +``int ioctl(int fd, AUDIO_PAUSE)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + +Description +----------- + +This ioctl call suspends the audio stream being played. Decoding and +playing are paused. It is then possible to restart again decoding and +playing process of the audio stream using AUDIO_CONTINUE command. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/audio-play.rst b/drivers/staging/media/av7110/audio-play.rst new file mode 100644 index 000000000000..e591930b6ca7 --- /dev/null +++ b/drivers/staging/media/av7110/audio-play.rst @@ -0,0 +1,48 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_PLAY: + +========== +AUDIO_PLAY +========== + +Name +---- + +AUDIO_PLAY + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_PLAY + +``int ioctl(int fd, AUDIO_PLAY)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + +Description +----------- + +This ioctl call asks the Audio Device to start playing an audio stream +from the selected source. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/audio-select-source.rst b/drivers/staging/media/av7110/audio-select-source.rst new file mode 100644 index 000000000000..6a0c0f365eb1 --- /dev/null +++ b/drivers/staging/media/av7110/audio-select-source.rst @@ -0,0 +1,56 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_SELECT_SOURCE: + +=================== +AUDIO_SELECT_SOURCE +=================== + +Name +---- + +AUDIO_SELECT_SOURCE + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_SELECT_SOURCE + +``int ioctl(int fd, AUDIO_SELECT_SOURCE, struct audio_stream_source *source)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - audio_stream_source_t source + + - Indicates the source that shall be used for the Audio stream. + +Description +----------- + +This ioctl call informs the audio device which source shall be used for +the input data. The possible sources are demux or memory. If +AUDIO_SOURCE_MEMORY is selected, the data is fed to the Audio Device +through the write command. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/audio-set-av-sync.rst b/drivers/staging/media/av7110/audio-set-av-sync.rst new file mode 100644 index 000000000000..85a8016bf025 --- /dev/null +++ b/drivers/staging/media/av7110/audio-set-av-sync.rst @@ -0,0 +1,58 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_SET_AV_SYNC: + +================= +AUDIO_SET_AV_SYNC +================= + +Name +---- + +AUDIO_SET_AV_SYNC + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_SET_AV_SYNC + +``int ioctl(int fd, AUDIO_SET_AV_SYNC, boolean state)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - boolean state + + - Tells the Digital TV subsystem if A/V synchronization shall be ON or OFF. + + TRUE: AV-sync ON + + FALSE: AV-sync OFF + +Description +----------- + +This ioctl call asks the Audio Device to turn ON or OFF A/V +synchronization. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/audio-set-bypass-mode.rst b/drivers/staging/media/av7110/audio-set-bypass-mode.rst new file mode 100644 index 000000000000..80d551a2053a --- /dev/null +++ b/drivers/staging/media/av7110/audio-set-bypass-mode.rst @@ -0,0 +1,62 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_SET_BYPASS_MODE: + +===================== +AUDIO_SET_BYPASS_MODE +===================== + +Name +---- + +AUDIO_SET_BYPASS_MODE + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_SET_BYPASS_MODE + +``int ioctl(int fd, AUDIO_SET_BYPASS_MODE, boolean mode)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - boolean mode + + - Enables or disables the decoding of the current Audio stream in + the Digital TV subsystem. + + TRUE: Bypass is disabled + + FALSE: Bypass is enabled + +Description +----------- + +This ioctl call asks the Audio Device to bypass the Audio decoder and +forward the stream without decoding. This mode shall be used if streams +that can't be handled by the Digital TV system shall be decoded. Dolby +DigitalTM streams are automatically forwarded by the Digital TV subsystem if +the hardware can handle it. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/audio-set-id.rst b/drivers/staging/media/av7110/audio-set-id.rst new file mode 100644 index 000000000000..39ad846d412d --- /dev/null +++ b/drivers/staging/media/av7110/audio-set-id.rst @@ -0,0 +1,59 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_SET_ID: + +============ +AUDIO_SET_ID +============ + +Name +---- + +AUDIO_SET_ID + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_SET_ID + +``int ioctl(int fd, AUDIO_SET_ID, int id)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - int id + + - audio sub-stream id + +Description +----------- + +This ioctl selects which sub-stream is to be decoded if a program or +system stream is sent to the video device. If no audio stream type is +set the id has to be in [0xC0,0xDF] for MPEG sound, in [0x80,0x87] for +AC3 and in [0xA0,0xA7] for LPCM. More specifications may follow for +other stream types. If the stream type is set the id just specifies the +substream id of the audio stream and only the first 5 bits are +recognized. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/audio-set-mixer.rst b/drivers/staging/media/av7110/audio-set-mixer.rst new file mode 100644 index 000000000000..45dbdf4801e0 --- /dev/null +++ b/drivers/staging/media/av7110/audio-set-mixer.rst @@ -0,0 +1,53 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_SET_MIXER: + +=============== +AUDIO_SET_MIXER +=============== + +Name +---- + +AUDIO_SET_MIXER + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_SET_MIXER + +``int ioctl(int fd, AUDIO_SET_MIXER, struct audio_mixer *mix)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - audio_mixer_t \*mix + + - mixer settings. + +Description +----------- + +This ioctl lets you adjust the mixer settings of the audio decoder. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/audio-set-mute.rst b/drivers/staging/media/av7110/audio-set-mute.rst new file mode 100644 index 000000000000..987751f92967 --- /dev/null +++ b/drivers/staging/media/av7110/audio-set-mute.rst @@ -0,0 +1,62 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_SET_MUTE: + +============== +AUDIO_SET_MUTE +============== + +Name +---- + +AUDIO_SET_MUTE + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_SET_MUTE + +``int ioctl(int fd, AUDIO_SET_MUTE, boolean state)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - boolean state + + - Indicates if audio device shall mute or not. + + TRUE: Audio Mute + + FALSE: Audio Un-mute + +Description +----------- + +This ioctl is for Digital TV devices only. To control a V4L2 decoder use the +V4L2 :ref:`VIDIOC_DECODER_CMD` with the +``V4L2_DEC_CMD_START_MUTE_AUDIO`` flag instead. + +This ioctl call asks the audio device to mute the stream that is +currently being played. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/audio-set-streamtype.rst b/drivers/staging/media/av7110/audio-set-streamtype.rst new file mode 100644 index 000000000000..77d73c74882f --- /dev/null +++ b/drivers/staging/media/av7110/audio-set-streamtype.rst @@ -0,0 +1,66 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_SET_STREAMTYPE: + +==================== +AUDIO_SET_STREAMTYPE +==================== + +Name +---- + +AUDIO_SET_STREAMTYPE + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_SET_STREAMTYPE + +``int ioctl(fd, AUDIO_SET_STREAMTYPE, int type)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - int type + + - stream type + +Description +----------- + +This ioctl tells the driver which kind of audio stream to expect. This +is useful if the stream offers several audio sub-streams like LPCM and +AC3. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. + + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EINVAL`` + + - type is not a valid or supported stream type. diff --git a/drivers/staging/media/av7110/audio-stop.rst b/drivers/staging/media/av7110/audio-stop.rst new file mode 100644 index 000000000000..d77f786fd797 --- /dev/null +++ b/drivers/staging/media/av7110/audio-stop.rst @@ -0,0 +1,48 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_STOP: + +========== +AUDIO_STOP +========== + +Name +---- + +AUDIO_STOP + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_STOP + +``int ioctl(int fd, AUDIO_STOP)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + +Description +----------- + +This ioctl call asks the Audio Device to stop playing the current +stream. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/audio.rst b/drivers/staging/media/av7110/audio.rst new file mode 100644 index 000000000000..aa753336b31f --- /dev/null +++ b/drivers/staging/media/av7110/audio.rst @@ -0,0 +1,27 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later + +.. _dvb_audio: + +####################### +Digital TV Audio Device +####################### + +The Digital TV audio device controls the MPEG2 audio decoder of the Digital +TV hardware. It can be accessed through ``/dev/dvb/adapter?/audio?``. Data +types and ioctl definitions can be accessed by including +``linux/dvb/audio.h`` in your application. + +Please note that some Digital TV cards don't have their own MPEG decoder, which +results in the omission of the audio and video device. + +These ioctls were also used by V4L2 to control MPEG decoders implemented +in V4L2. The use of these ioctls for that purpose has been made obsolete +and proper V4L2 ioctls or controls have been created to replace that +functionality. + + +.. toctree:: + :maxdepth: 1 + + audio_data_types + audio_function_calls diff --git a/drivers/staging/media/av7110/audio_data_types.rst b/drivers/staging/media/av7110/audio_data_types.rst new file mode 100644 index 000000000000..4744529136a8 --- /dev/null +++ b/drivers/staging/media/av7110/audio_data_types.rst @@ -0,0 +1,116 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later + +.. _audio_data_types: + +**************** +Audio Data Types +**************** + +This section describes the structures, data types and defines used when +talking to the audio device. + +.. c:type:: audio_stream_source + +The audio stream source is set through the AUDIO_SELECT_SOURCE call +and can take the following values, depending on whether we are replaying +from an internal (demux) or external (user write) source. + + +.. code-block:: c + + typedef enum { + AUDIO_SOURCE_DEMUX, + AUDIO_SOURCE_MEMORY + } audio_stream_source_t; + +AUDIO_SOURCE_DEMUX selects the demultiplexer (fed either by the +frontend or the DVR device) as the source of the video stream. If +AUDIO_SOURCE_MEMORY is selected the stream comes from the application +through the ``write()`` system call. + + +.. c:type:: audio_play_state + +The following values can be returned by the AUDIO_GET_STATUS call +representing the state of audio playback. + + +.. code-block:: c + + typedef enum { + AUDIO_STOPPED, + AUDIO_PLAYING, + AUDIO_PAUSED + } audio_play_state_t; + + +.. c:type:: audio_channel_select + +The audio channel selected via AUDIO_CHANNEL_SELECT is determined by +the following values. + + +.. code-block:: c + + typedef enum { + AUDIO_STEREO, + AUDIO_MONO_LEFT, + AUDIO_MONO_RIGHT, + AUDIO_MONO, + AUDIO_STEREO_SWAPPED + } audio_channel_select_t; + + +.. c:type:: audio_status + +The AUDIO_GET_STATUS call returns the following structure informing +about various states of the playback operation. + + +.. code-block:: c + + typedef struct audio_status { + boolean AV_sync_state; + boolean mute_state; + audio_play_state_t play_state; + audio_stream_source_t stream_source; + audio_channel_select_t channel_select; + boolean bypass_mode; + audio_mixer_t mixer_state; + } audio_status_t; + + +.. c:type:: audio_mixer + +The following structure is used by the AUDIO_SET_MIXER call to set the +audio volume. + + +.. code-block:: c + + typedef struct audio_mixer { + unsigned int volume_left; + unsigned int volume_right; + } audio_mixer_t; + + +.. _audio_encodings: + +audio encodings +=============== + +A call to AUDIO_GET_CAPABILITIES returns an unsigned integer with the +following bits set according to the hardwares capabilities. + + +.. code-block:: c + + #define AUDIO_CAP_DTS 1 + #define AUDIO_CAP_LPCM 2 + #define AUDIO_CAP_MP1 4 + #define AUDIO_CAP_MP2 8 + #define AUDIO_CAP_MP3 16 + #define AUDIO_CAP_AAC 32 + #define AUDIO_CAP_OGG 64 + #define AUDIO_CAP_SDDS 128 + #define AUDIO_CAP_AC3 256 diff --git a/drivers/staging/media/av7110/audio_function_calls.rst b/drivers/staging/media/av7110/audio_function_calls.rst new file mode 100644 index 000000000000..fa5ba9539caf --- /dev/null +++ b/drivers/staging/media/av7110/audio_function_calls.rst @@ -0,0 +1,30 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later + +.. _audio_function_calls: + +******************** +Audio Function Calls +******************** + +.. toctree:: + :maxdepth: 1 + + audio-fopen + audio-fclose + audio-fwrite + audio-stop + audio-play + audio-pause + audio-continue + audio-select-source + audio-set-mute + audio-set-av-sync + audio-set-bypass-mode + audio-channel-select + audio-bilingual-channel-select + audio-get-status + audio-get-capabilities + audio-clear-buffer + audio-set-id + audio-set-mixer + audio-set-streamtype diff --git a/drivers/staging/media/av7110/video-clear-buffer.rst b/drivers/staging/media/av7110/video-clear-buffer.rst new file mode 100644 index 000000000000..a7730559bbb2 --- /dev/null +++ b/drivers/staging/media/av7110/video-clear-buffer.rst @@ -0,0 +1,54 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_CLEAR_BUFFER: + +================== +VIDEO_CLEAR_BUFFER +================== + +Name +---- + +VIDEO_CLEAR_BUFFER + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_CLEAR_BUFFER + +``int ioctl(fd, VIDEO_CLEAR_BUFFER)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_CLEAR_BUFFER for this command. + +Description +----------- + +This ioctl call clears all video buffers in the driver and in the +decoder hardware. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video-command.rst b/drivers/staging/media/av7110/video-command.rst new file mode 100644 index 000000000000..cae9445eb3af --- /dev/null +++ b/drivers/staging/media/av7110/video-command.rst @@ -0,0 +1,96 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_COMMAND: + +============= +VIDEO_COMMAND +============= + +Name +---- + +VIDEO_COMMAND + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_COMMAND + +``int ioctl(int fd, VIDEO_COMMAND, struct video_command *cmd)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_COMMAND for this command. + + - .. row 3 + + - struct video_command \*cmd + + - Commands the decoder. + +Description +----------- + +This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders +this ioctl has been replaced by the +:ref:`VIDIOC_DECODER_CMD` ioctl. + +This ioctl commands the decoder. The ``video_command`` struct is a +subset of the ``v4l2_decoder_cmd`` struct, so refer to the +:ref:`VIDIOC_DECODER_CMD` documentation for +more information. + +.. c:type:: video_command + +.. code-block:: c + + /* The structure must be zeroed before use by the application + This ensures it can be extended safely in the future. */ + struct video_command { + __u32 cmd; + __u32 flags; + union { + struct { + __u64 pts; + } stop; + + struct { + /* 0 or 1000 specifies normal speed, + 1 specifies forward single stepping, + -1 specifies backward single stepping, + >1: playback at speed/1000 of the normal speed, + <-1: reverse playback at (-speed/1000) of the normal speed. */ + __s32 speed; + __u32 format; + } play; + + struct { + __u32 data[16]; + } raw; + }; + }; + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video-continue.rst b/drivers/staging/media/av7110/video-continue.rst new file mode 100644 index 000000000000..bc34bf3989e4 --- /dev/null +++ b/drivers/staging/media/av7110/video-continue.rst @@ -0,0 +1,57 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_CONTINUE: + +============== +VIDEO_CONTINUE +============== + +Name +---- + +VIDEO_CONTINUE + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_CONTINUE + +``int ioctl(fd, VIDEO_CONTINUE)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_CONTINUE for this command. + +Description +----------- + +This ioctl is for Digital TV devices only. To control a V4L2 decoder use the +V4L2 :ref:`VIDIOC_DECODER_CMD` instead. + +This ioctl call restarts decoding and playing processes of the video +stream which was played before a call to VIDEO_FREEZE was made. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video-fast-forward.rst b/drivers/staging/media/av7110/video-fast-forward.rst new file mode 100644 index 000000000000..e71fa8d6965b --- /dev/null +++ b/drivers/staging/media/av7110/video-fast-forward.rst @@ -0,0 +1,72 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_FAST_FORWARD: + +================== +VIDEO_FAST_FORWARD +================== + +Name +---- + +VIDEO_FAST_FORWARD + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_FAST_FORWARD + +``int ioctl(fd, VIDEO_FAST_FORWARD, int nFrames)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_FAST_FORWARD for this command. + + - .. row 3 + + - int nFrames + + - The number of frames to skip. + +Description +----------- + +This ioctl call asks the Video Device to skip decoding of N number of +I-frames. This call can only be used if VIDEO_SOURCE_MEMORY is +selected. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. + + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EPERM`` + + - Mode VIDEO_SOURCE_MEMORY not selected. diff --git a/drivers/staging/media/av7110/video-fclose.rst b/drivers/staging/media/av7110/video-fclose.rst new file mode 100644 index 000000000000..01d24d548439 --- /dev/null +++ b/drivers/staging/media/av7110/video-fclose.rst @@ -0,0 +1,51 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _video_fclose: + +================= +dvb video close() +================= + +Name +---- + +dvb video close() + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:function:: int close(int fd) + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + +Description +----------- + +This system call closes a previously opened video device. + +Return Value +------------ + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EBADF`` + + - fd is not a valid open file descriptor. diff --git a/drivers/staging/media/av7110/video-fopen.rst b/drivers/staging/media/av7110/video-fopen.rst new file mode 100644 index 000000000000..1371b083e4e8 --- /dev/null +++ b/drivers/staging/media/av7110/video-fopen.rst @@ -0,0 +1,111 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _video_fopen: + +================ +dvb video open() +================ + +Name +---- + +dvb video open() + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:function:: int open(const char *deviceName, int flags) + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - const char \*deviceName + + - Name of specific video device. + + - .. row 2 + + - int flags + + - A bit-wise OR of the following flags: + + - .. row 3 + + - + - O_RDONLY read-only access + + - .. row 4 + + - + - O_RDWR read/write access + + - .. row 5 + + - + - O_NONBLOCK open in non-blocking mode + + - .. row 6 + + - + - (blocking mode is the default) + +Description +----------- + +This system call opens a named video device (e.g. +/dev/dvb/adapter0/video0) for subsequent use. + +When an open() call has succeeded, the device will be ready for use. The +significance of blocking or non-blocking mode is described in the +documentation for functions where there is a difference. It does not +affect the semantics of the open() call itself. A device opened in +blocking mode can later be put into non-blocking mode (and vice versa) +using the F_SETFL command of the fcntl system call. This is a standard +system call, documented in the Linux manual page for fcntl. Only one +user can open the Video Device in O_RDWR mode. All other attempts to +open the device in this mode will fail, and an error-code will be +returned. If the Video Device is opened in O_RDONLY mode, the only +ioctl call that can be used is VIDEO_GET_STATUS. All other call will +return an error code. + +Return Value +------------ + +.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``ENODEV`` + + - Device driver not loaded/available. + + - .. row 2 + + - ``EINTERNAL`` + + - Internal error. + + - .. row 3 + + - ``EBUSY`` + + - Device or resource busy. + + - .. row 4 + + - ``EINVAL`` + + - Invalid argument. diff --git a/drivers/staging/media/av7110/video-freeze.rst b/drivers/staging/media/av7110/video-freeze.rst new file mode 100644 index 000000000000..4321f257cb70 --- /dev/null +++ b/drivers/staging/media/av7110/video-freeze.rst @@ -0,0 +1,61 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_FREEZE: + +============ +VIDEO_FREEZE +============ + +Name +---- + +VIDEO_FREEZE + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_FREEZE + +``int ioctl(fd, VIDEO_FREEZE)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_FREEZE for this command. + +Description +----------- + +This ioctl is for Digital TV devices only. To control a V4L2 decoder use the +V4L2 :ref:`VIDIOC_DECODER_CMD` instead. + +This ioctl call suspends the live video stream being played. Decoding +and playing are frozen. It is then possible to restart the decoding and +playing process of the video stream using the VIDEO_CONTINUE command. +If VIDEO_SOURCE_MEMORY is selected in the ioctl call +VIDEO_SELECT_SOURCE, the Digital TV subsystem will not decode any more data +until the ioctl call VIDEO_CONTINUE or VIDEO_PLAY is performed. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video-fwrite.rst b/drivers/staging/media/av7110/video-fwrite.rst new file mode 100644 index 000000000000..a07fd7d7a40e --- /dev/null +++ b/drivers/staging/media/av7110/video-fwrite.rst @@ -0,0 +1,79 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _video_fwrite: + +================= +dvb video write() +================= + +Name +---- + +dvb video write() + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:function:: size_t write(int fd, const void *buf, size_t count) + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - void \*buf + + - Pointer to the buffer containing the PES data. + + - .. row 3 + + - size_t count + + - Size of buf. + +Description +----------- + +This system call can only be used if VIDEO_SOURCE_MEMORY is selected +in the ioctl call VIDEO_SELECT_SOURCE. The data provided shall be in +PES format, unless the capability allows other formats. If O_NONBLOCK +is not specified the function will block until buffer space is +available. The amount of data to be transferred is implied by count. + +Return Value +------------ + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EPERM`` + + - Mode VIDEO_SOURCE_MEMORY not selected. + + - .. row 2 + + - ``ENOMEM`` + + - Attempted to write more data than the internal buffer can hold. + + - .. row 3 + + - ``EBADF`` + + - fd is not a valid open file descriptor. diff --git a/drivers/staging/media/av7110/video-get-capabilities.rst b/drivers/staging/media/av7110/video-get-capabilities.rst new file mode 100644 index 000000000000..01e09f56656c --- /dev/null +++ b/drivers/staging/media/av7110/video-get-capabilities.rst @@ -0,0 +1,61 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_GET_CAPABILITIES: + +====================== +VIDEO_GET_CAPABILITIES +====================== + +Name +---- + +VIDEO_GET_CAPABILITIES + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_GET_CAPABILITIES + +``int ioctl(fd, VIDEO_GET_CAPABILITIES, unsigned int *cap)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_GET_CAPABILITIES for this command. + + - .. row 3 + + - unsigned int \*cap + + - Pointer to a location where to store the capability information. + +Description +----------- + +This ioctl call asks the video device about its decoding capabilities. +On success it returns and integer which has bits set according to the +defines in section ??. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video-get-event.rst b/drivers/staging/media/av7110/video-get-event.rst new file mode 100644 index 000000000000..90382bc36cfe --- /dev/null +++ b/drivers/staging/media/av7110/video-get-event.rst @@ -0,0 +1,105 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_GET_EVENT: + +=============== +VIDEO_GET_EVENT +=============== + +Name +---- + +VIDEO_GET_EVENT + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_GET_EVENT + +``int ioctl(fd, VIDEO_GET_EVENT, struct video_event *ev)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_GET_EVENT for this command. + + - .. row 3 + + - struct video_event \*ev + + - Points to the location where the event, if any, is to be stored. + +Description +----------- + +This ioctl is for Digital TV devices only. To get events from a V4L2 decoder +use the V4L2 :ref:`VIDIOC_DQEVENT` ioctl instead. + +This ioctl call returns an event of type video_event if available. If +an event is not available, the behavior depends on whether the device is +in blocking or non-blocking mode. In the latter case, the call fails +immediately with errno set to ``EWOULDBLOCK``. In the former case, the call +blocks until an event becomes available. The standard Linux poll() +and/or select() system calls can be used with the device file descriptor +to watch for new events. For select(), the file descriptor should be +included in the exceptfds argument, and for poll(), POLLPRI should be +specified as the wake-up condition. Read-only permissions are sufficient +for this ioctl call. + +.. c:type:: video_event + +.. code-block:: c + + struct video_event { + __s32 type; + #define VIDEO_EVENT_SIZE_CHANGED 1 + #define VIDEO_EVENT_FRAME_RATE_CHANGED 2 + #define VIDEO_EVENT_DECODER_STOPPED 3 + #define VIDEO_EVENT_VSYNC 4 + long timestamp; + union { + video_size_t size; + unsigned int frame_rate; /* in frames per 1000sec */ + unsigned char vsync_field; /* unknown/odd/even/progressive */ + } u; + }; + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EWOULDBLOCK`` + + - There is no event pending, and the device is in non-blocking mode. + + - .. row 2 + + - ``EOVERFLOW`` + + - Overflow in event queue - one or more events were lost. diff --git a/drivers/staging/media/av7110/video-get-frame-count.rst b/drivers/staging/media/av7110/video-get-frame-count.rst new file mode 100644 index 000000000000..b48ac8c58a41 --- /dev/null +++ b/drivers/staging/media/av7110/video-get-frame-count.rst @@ -0,0 +1,65 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_GET_FRAME_COUNT: + +===================== +VIDEO_GET_FRAME_COUNT +===================== + +Name +---- + +VIDEO_GET_FRAME_COUNT + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_GET_FRAME_COUNT + +``int ioctl(int fd, VIDEO_GET_FRAME_COUNT, __u64 *pts)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_GET_FRAME_COUNT for this command. + + - .. row 3 + + - __u64 \*pts + + - Returns the number of frames displayed since the decoder was + started. + +Description +----------- + +This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders +this ioctl has been replaced by the ``V4L2_CID_MPEG_VIDEO_DEC_FRAME`` +control. + +This ioctl call asks the Video Device to return the number of displayed +frames since the decoder was started. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video-get-pts.rst b/drivers/staging/media/av7110/video-get-pts.rst new file mode 100644 index 000000000000..fedaff41be0b --- /dev/null +++ b/drivers/staging/media/av7110/video-get-pts.rst @@ -0,0 +1,69 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_GET_PTS: + +============= +VIDEO_GET_PTS +============= + +Name +---- + +VIDEO_GET_PTS + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_GET_PTS + +``int ioctl(int fd, VIDEO_GET_PTS, __u64 *pts)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_GET_PTS for this command. + + - .. row 3 + + - __u64 \*pts + + - Returns the 33-bit timestamp as defined in ITU T-REC-H.222.0 / + ISO/IEC 13818-1. + + The PTS should belong to the currently played frame if possible, + but may also be a value close to it like the PTS of the last + decoded frame or the last PTS extracted by the PES parser. + +Description +----------- + +This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders +this ioctl has been replaced by the ``V4L2_CID_MPEG_VIDEO_DEC_PTS`` +control. + +This ioctl call asks the Video Device to return the current PTS +timestamp. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video-get-size.rst b/drivers/staging/media/av7110/video-get-size.rst new file mode 100644 index 000000000000..de34331c5bd1 --- /dev/null +++ b/drivers/staging/media/av7110/video-get-size.rst @@ -0,0 +1,69 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_GET_SIZE: + +============== +VIDEO_GET_SIZE +============== + +Name +---- + +VIDEO_GET_SIZE + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_GET_SIZE + +``int ioctl(int fd, VIDEO_GET_SIZE, video_size_t *size)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_GET_SIZE for this command. + + - .. row 3 + + - video_size_t \*size + + - Returns the size and aspect ratio. + +Description +----------- + +This ioctl returns the size and aspect ratio. + +.. c:type:: video_size_t + +.. code-block::c + + typedef struct { + int w; + int h; + video_format_t aspect_ratio; + } video_size_t; + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video-get-status.rst b/drivers/staging/media/av7110/video-get-status.rst new file mode 100644 index 000000000000..9b86fbf411d4 --- /dev/null +++ b/drivers/staging/media/av7110/video-get-status.rst @@ -0,0 +1,72 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_GET_STATUS: + +================ +VIDEO_GET_STATUS +================ + +Name +---- + +VIDEO_GET_STATUS + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_GET_STATUS + +``int ioctl(fd, VIDEO_GET_STATUS, struct video_status *status)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_GET_STATUS for this command. + + - .. row 3 + + - struct video_status \*status + + - Returns the current status of the Video Device. + +Description +----------- + +This ioctl call asks the Video Device to return the current status of +the device. + +.. c:type:: video_status + +.. code-block:: c + + struct video_status { + int video_blank; /* blank video on freeze? */ + video_play_state_t play_state; /* current state of playback */ + video_stream_source_t stream_source; /* current source (demux/memory) */ + video_format_t video_format; /* current aspect ratio of stream*/ + video_displayformat_t display_format;/* selected cropping mode */ + }; + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video-play.rst b/drivers/staging/media/av7110/video-play.rst new file mode 100644 index 000000000000..35ac8b98fdbf --- /dev/null +++ b/drivers/staging/media/av7110/video-play.rst @@ -0,0 +1,57 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_PLAY: + +========== +VIDEO_PLAY +========== + +Name +---- + +VIDEO_PLAY + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_PLAY + +``int ioctl(fd, VIDEO_PLAY)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_PLAY for this command. + +Description +----------- + +This ioctl is for Digital TV devices only. To control a V4L2 decoder use the +V4L2 :ref:`VIDIOC_DECODER_CMD` instead. + +This ioctl call asks the Video Device to start playing a video stream +from the selected source. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video-select-source.rst b/drivers/staging/media/av7110/video-select-source.rst new file mode 100644 index 000000000000..929a20985d53 --- /dev/null +++ b/drivers/staging/media/av7110/video-select-source.rst @@ -0,0 +1,76 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_SELECT_SOURCE: + +=================== +VIDEO_SELECT_SOURCE +=================== + +Name +---- + +VIDEO_SELECT_SOURCE + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_SELECT_SOURCE + +``int ioctl(fd, VIDEO_SELECT_SOURCE, video_stream_source_t source)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_SELECT_SOURCE for this command. + + - .. row 3 + + - video_stream_source_t source + + - Indicates which source shall be used for the Video stream. + +Description +----------- + +This ioctl is for Digital TV devices only. This ioctl was also supported by the +V4L2 ivtv driver, but that has been replaced by the ivtv-specific +``IVTV_IOC_PASSTHROUGH_MODE`` ioctl. + +This ioctl call informs the video device which source shall be used for +the input data. The possible sources are demux or memory. If memory is +selected, the data is fed to the video device through the write command. + +.. c:type:: video_stream_source_t + +.. code-block:: c + + typedef enum { + VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */ + VIDEO_SOURCE_MEMORY /* If this source is selected, the stream + comes from the user through the write + system call */ + } video_stream_source_t; + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video-set-blank.rst b/drivers/staging/media/av7110/video-set-blank.rst new file mode 100644 index 000000000000..70249a6ba125 --- /dev/null +++ b/drivers/staging/media/av7110/video-set-blank.rst @@ -0,0 +1,64 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_SET_BLANK: + +=============== +VIDEO_SET_BLANK +=============== + +Name +---- + +VIDEO_SET_BLANK + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_SET_BLANK + +``int ioctl(fd, VIDEO_SET_BLANK, boolean mode)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_SET_BLANK for this command. + + - .. row 3 + + - boolean mode + + - TRUE: Blank screen when stop. + + - .. row 4 + + - + - FALSE: Show last decoded frame. + +Description +----------- + +This ioctl call asks the Video Device to blank out the picture. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video-set-display-format.rst b/drivers/staging/media/av7110/video-set-display-format.rst new file mode 100644 index 000000000000..1de4f40ae732 --- /dev/null +++ b/drivers/staging/media/av7110/video-set-display-format.rst @@ -0,0 +1,60 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_SET_DISPLAY_FORMAT: + +======================== +VIDEO_SET_DISPLAY_FORMAT +======================== + +Name +---- + +VIDEO_SET_DISPLAY_FORMAT + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_SET_DISPLAY_FORMAT + +``int ioctl(fd, VIDEO_SET_DISPLAY_FORMAT)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_SET_DISPLAY_FORMAT for this command. + + - .. row 3 + + - video_display_format_t format + + - Selects the video format to be used. + +Description +----------- + +This ioctl call asks the Video Device to select the video format to be +applied by the MPEG chip on the video. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video-set-format.rst b/drivers/staging/media/av7110/video-set-format.rst new file mode 100644 index 000000000000..bb64e37ae081 --- /dev/null +++ b/drivers/staging/media/av7110/video-set-format.rst @@ -0,0 +1,82 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_SET_FORMAT: + +================ +VIDEO_SET_FORMAT +================ + +Name +---- + +VIDEO_SET_FORMAT + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_SET_FORMAT + +``int ioctl(fd, VIDEO_SET_FORMAT, video_format_t format)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_SET_FORMAT for this command. + + - .. row 3 + + - video_format_t format + + - video format of TV as defined in section ??. + +Description +----------- + +This ioctl sets the screen format (aspect ratio) of the connected output +device (TV) so that the output of the decoder can be adjusted +accordingly. + +.. c:type:: video_format_t + +.. code-block:: c + + typedef enum { + VIDEO_FORMAT_4_3, /* Select 4:3 format */ + VIDEO_FORMAT_16_9, /* Select 16:9 format. */ + VIDEO_FORMAT_221_1 /* 2.21:1 */ + } video_format_t; + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. + + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EINVAL`` + + - format is not a valid video format. diff --git a/drivers/staging/media/av7110/video-set-streamtype.rst b/drivers/staging/media/av7110/video-set-streamtype.rst new file mode 100644 index 000000000000..1f31c048bdbc --- /dev/null +++ b/drivers/staging/media/av7110/video-set-streamtype.rst @@ -0,0 +1,61 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_SET_STREAMTYPE: + +==================== +VIDEO_SET_STREAMTYPE +==================== + +Name +---- + +VIDEO_SET_STREAMTYPE + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_SET_STREAMTYPE + +``int ioctl(fd, VIDEO_SET_STREAMTYPE, int type)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_SET_STREAMTYPE for this command. + + - .. row 3 + + - int type + + - stream type + +Description +----------- + +This ioctl tells the driver which kind of stream to expect being written +to it. If this call is not used the default of video PES is used. Some +drivers might not support this call and always expect PES. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video-slowmotion.rst b/drivers/staging/media/av7110/video-slowmotion.rst new file mode 100644 index 000000000000..1478fcc30cb8 --- /dev/null +++ b/drivers/staging/media/av7110/video-slowmotion.rst @@ -0,0 +1,72 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_SLOWMOTION: + +================ +VIDEO_SLOWMOTION +================ + +Name +---- + +VIDEO_SLOWMOTION + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_SLOWMOTION + +``int ioctl(fd, VIDEO_SLOWMOTION, int nFrames)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_SLOWMOTION for this command. + + - .. row 3 + + - int nFrames + + - The number of times to repeat each frame. + +Description +----------- + +This ioctl call asks the video device to repeat decoding frames N number +of times. This call can only be used if VIDEO_SOURCE_MEMORY is +selected. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. + + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EPERM`` + + - Mode VIDEO_SOURCE_MEMORY not selected. diff --git a/drivers/staging/media/av7110/video-stillpicture.rst b/drivers/staging/media/av7110/video-stillpicture.rst new file mode 100644 index 000000000000..d25384222a20 --- /dev/null +++ b/drivers/staging/media/av7110/video-stillpicture.rst @@ -0,0 +1,61 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_STILLPICTURE: + +================== +VIDEO_STILLPICTURE +================== + +Name +---- + +VIDEO_STILLPICTURE + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_STILLPICTURE + +``int ioctl(fd, VIDEO_STILLPICTURE, struct video_still_picture *sp)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_STILLPICTURE for this command. + + - .. row 3 + + - struct video_still_picture \*sp + + - Pointer to a location where an I-frame and size is stored. + +Description +----------- + +This ioctl call asks the Video Device to display a still picture +(I-frame). The input data shall contain an I-frame. If the pointer is +NULL, then the current displayed still picture is blanked. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video-stop.rst b/drivers/staging/media/av7110/video-stop.rst new file mode 100644 index 000000000000..96f61c5b48a2 --- /dev/null +++ b/drivers/staging/media/av7110/video-stop.rst @@ -0,0 +1,74 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_STOP: + +========== +VIDEO_STOP +========== + +Name +---- + +VIDEO_STOP + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_STOP + +``int ioctl(fd, VIDEO_STOP, boolean mode)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_STOP for this command. + + - .. row 3 + + - Boolean mode + + - Indicates how the screen shall be handled. + + - .. row 4 + + - + - TRUE: Blank screen when stop. + + - .. row 5 + + - + - FALSE: Show last decoded frame. + +Description +----------- + +This ioctl is for Digital TV devices only. To control a V4L2 decoder use the +V4L2 :ref:`VIDIOC_DECODER_CMD` instead. + +This ioctl call asks the Video Device to stop playing the current +stream. Depending on the input parameter, the screen can be blanked out +or displaying the last decoded frame. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video-try-command.rst b/drivers/staging/media/av7110/video-try-command.rst new file mode 100644 index 000000000000..79bf3dfb8a32 --- /dev/null +++ b/drivers/staging/media/av7110/video-try-command.rst @@ -0,0 +1,66 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_TRY_COMMAND: + +================= +VIDEO_TRY_COMMAND +================= + +Name +---- + +VIDEO_TRY_COMMAND + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_TRY_COMMAND + +``int ioctl(int fd, VIDEO_TRY_COMMAND, struct video_command *cmd)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_TRY_COMMAND for this command. + + - .. row 3 + + - struct video_command \*cmd + + - Try a decoder command. + +Description +----------- + +This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders +this ioctl has been replaced by the +:ref:`VIDIOC_TRY_DECODER_CMD ` ioctl. + +This ioctl tries a decoder command. The ``video_command`` struct is a +subset of the ``v4l2_decoder_cmd`` struct, so refer to the +:ref:`VIDIOC_TRY_DECODER_CMD ` documentation +for more information. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. diff --git a/drivers/staging/media/av7110/video.rst b/drivers/staging/media/av7110/video.rst new file mode 100644 index 000000000000..808705b769a1 --- /dev/null +++ b/drivers/staging/media/av7110/video.rst @@ -0,0 +1,36 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later + +.. _dvb_video: + +####################### +Digital TV Video Device +####################### + +The Digital TV video device controls the MPEG2 video decoder of the Digital +TV hardware. It can be accessed through **/dev/dvb/adapter0/video0**. Data +types and ioctl definitions can be accessed by including +**linux/dvb/video.h** in your application. + +Note that the Digital TV video device only controls decoding of the MPEG video +stream, not its presentation on the TV or computer screen. On PCs this +is typically handled by an associated video4linux device, e.g. +**/dev/video**, which allows scaling and defining output windows. + +Some Digital TV cards don't have their own MPEG decoder, which results in the +omission of the audio and video device as well as the video4linux +device. + +The ioctls that deal with SPUs (sub picture units) and navigation +packets are only supported on some MPEG decoders made for DVD playback. + +These ioctls were also used by V4L2 to control MPEG decoders implemented +in V4L2. The use of these ioctls for that purpose has been made obsolete +and proper V4L2 ioctls or controls have been created to replace that +functionality. + + +.. toctree:: + :maxdepth: 1 + + video_types + video_function_calls diff --git a/drivers/staging/media/av7110/video_function_calls.rst b/drivers/staging/media/av7110/video_function_calls.rst new file mode 100644 index 000000000000..20a897be5dca --- /dev/null +++ b/drivers/staging/media/av7110/video_function_calls.rst @@ -0,0 +1,35 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later + +.. _video_function_calls: + +******************** +Video Function Calls +******************** + +.. toctree:: + :maxdepth: 1 + + video-fopen + video-fclose + video-fwrite + video-stop + video-play + video-freeze + video-continue + video-select-source + video-set-blank + video-get-status + video-get-frame-count + video-get-pts + video-get-event + video-command + video-try-command + video-get-size + video-set-display-format + video-stillpicture + video-fast-forward + video-slowmotion + video-get-capabilities + video-clear-buffer + video-set-streamtype + video-set-format diff --git a/drivers/staging/media/av7110/video_types.rst b/drivers/staging/media/av7110/video_types.rst new file mode 100644 index 000000000000..c4557d328b7a --- /dev/null +++ b/drivers/staging/media/av7110/video_types.rst @@ -0,0 +1,248 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later + +.. _video_types: + +**************** +Video Data Types +**************** + + +.. _video-format-t: + +video_format_t +============== + +The ``video_format_t`` data type defined by + + +.. code-block:: c + + typedef enum { + VIDEO_FORMAT_4_3, /* Select 4:3 format */ + VIDEO_FORMAT_16_9, /* Select 16:9 format. */ + VIDEO_FORMAT_221_1 /* 2.21:1 */ + } video_format_t; + +is used in the VIDEO_SET_FORMAT function (??) to tell the driver which +aspect ratio the output hardware (e.g. TV) has. It is also used in the +data structures video_status (??) returned by VIDEO_GET_STATUS (??) +and video_event (??) returned by VIDEO_GET_EVENT (??) which report +about the display format of the current video stream. + + +.. _video-displayformat-t: + +video_displayformat_t +===================== + +In case the display format of the video stream and of the display +hardware differ the application has to specify how to handle the +cropping of the picture. This can be done using the +VIDEO_SET_DISPLAY_FORMAT call (??) which accepts + + +.. code-block:: c + + typedef enum { + VIDEO_PAN_SCAN, /* use pan and scan format */ + VIDEO_LETTER_BOX, /* use letterbox format */ + VIDEO_CENTER_CUT_OUT /* use center cut out format */ + } video_displayformat_t; + +as argument. + + +.. _video-stream-source-t: + +video_stream_source_t +===================== + +The video stream source is set through the VIDEO_SELECT_SOURCE call +and can take the following values, depending on whether we are replaying +from an internal (demuxer) or external (user write) source. + + +.. code-block:: c + + typedef enum { + VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */ + VIDEO_SOURCE_MEMORY /* If this source is selected, the stream + comes from the user through the write + system call */ + } video_stream_source_t; + +VIDEO_SOURCE_DEMUX selects the demultiplexer (fed either by the +frontend or the DVR device) as the source of the video stream. If +VIDEO_SOURCE_MEMORY is selected the stream comes from the application +through the **write()** system call. + + +.. _video-play-state-t: + +video_play_state_t +================== + +The following values can be returned by the VIDEO_GET_STATUS call +representing the state of video playback. + + +.. code-block:: c + + typedef enum { + VIDEO_STOPPED, /* Video is stopped */ + VIDEO_PLAYING, /* Video is currently playing */ + VIDEO_FREEZED /* Video is freezed */ + } video_play_state_t; + + +.. c:type:: video_command + +struct video_command +==================== + +The structure must be zeroed before use by the application This ensures +it can be extended safely in the future. + + +.. code-block:: c + + struct video_command { + __u32 cmd; + __u32 flags; + union { + struct { + __u64 pts; + } stop; + + struct { + /* 0 or 1000 specifies normal speed, + 1 specifies forward single stepping, + -1 specifies backward single stepping, + >>1: playback at speed/1000 of the normal speed, + <-1: reverse playback at (-speed/1000) of the normal speed. */ + __s32 speed; + __u32 format; + } play; + + struct { + __u32 data[16]; + } raw; + }; + }; + + +.. _video-size-t: + +video_size_t +============ + + +.. code-block:: c + + typedef struct { + int w; + int h; + video_format_t aspect_ratio; + } video_size_t; + + +.. c:type:: video_event + +struct video_event +================== + +The following is the structure of a video event as it is returned by the +VIDEO_GET_EVENT call. + + +.. code-block:: c + + struct video_event { + __s32 type; + #define VIDEO_EVENT_SIZE_CHANGED 1 + #define VIDEO_EVENT_FRAME_RATE_CHANGED 2 + #define VIDEO_EVENT_DECODER_STOPPED 3 + #define VIDEO_EVENT_VSYNC 4 + long timestamp; + union { + video_size_t size; + unsigned int frame_rate; /* in frames per 1000sec */ + unsigned char vsync_field; /* unknown/odd/even/progressive */ + } u; + }; + + +.. c:type:: video_status + +struct video_status +=================== + +The VIDEO_GET_STATUS call returns the following structure informing +about various states of the playback operation. + + +.. code-block:: c + + struct video_status { + int video_blank; /* blank video on freeze? */ + video_play_state_t play_state; /* current state of playback */ + video_stream_source_t stream_source; /* current source (demux/memory) */ + video_format_t video_format; /* current aspect ratio of stream */ + video_displayformat_t display_format;/* selected cropping mode */ + }; + +If video_blank is set video will be blanked out if the channel is +changed or if playback is stopped. Otherwise, the last picture will be +displayed. play_state indicates if the video is currently frozen, +stopped, or being played back. The stream_source corresponds to the +selected source for the video stream. It can come either from the +demultiplexer or from memory. The video_format indicates the aspect +ratio (one of 4:3 or 16:9) of the currently played video stream. +Finally, display_format corresponds to the selected cropping mode in +case the source video format is not the same as the format of the output +device. + + +.. c:type:: video_still_picture + +struct video_still_picture +========================== + +An I-frame displayed via the VIDEO_STILLPICTURE call is passed on +within the following structure. + + +.. code-block:: c + + /* pointer to and size of a single iframe in memory */ + struct video_still_picture { + char *iFrame; /* pointer to a single iframe in memory */ + int32_t size; + }; + + +.. _video_caps: + +video capabilities +================== + +A call to VIDEO_GET_CAPABILITIES returns an unsigned integer with the +following bits set according to the hardwares capabilities. + + +.. code-block:: c + + /* bit definitions for capabilities: */ + /* can the hardware decode MPEG1 and/or MPEG2? */ + #define VIDEO_CAP_MPEG1 1 + #define VIDEO_CAP_MPEG2 2 + /* can you send a system and/or program stream to video device? + (you still have to open the video and the audio device but only + send the stream to the video device) */ + #define VIDEO_CAP_SYS 4 + #define VIDEO_CAP_PROG 8 + /* can the driver also handle SPU, NAVI and CSS encoded data? + (CSS API is not present yet) */ + #define VIDEO_CAP_SPU 16 + #define VIDEO_CAP_NAVI 32 + #define VIDEO_CAP_CSS 64 -- cgit v1.3.1 From 55b54c269beef13d88dc30544df34763a90dc815 Mon Sep 17 00:00:00 2001 From: Kyle Tso Date: Tue, 1 Jun 2021 20:31:49 +0800 Subject: dt-bindings: connector: Add PD rev 2.0 VDO definition Add the VDO definition for USB PD rev 2.0 in the bindings and define a new property snk-vdos-v1 containing legacy VDOs as the responses to the port partner which only supports PD rev 2.0. Reviewed-by: Rob Herring Signed-off-by: Kyle Tso Link: https://lore.kernel.org/r/20210601123151.3441914-3-kyletso@google.com Signed-off-by: Greg Kroah-Hartman --- .../bindings/connector/usb-connector.yaml | 15 +++++ include/dt-bindings/usb/pd.h | 69 +++++++++++++++++++++- 2 files changed, 81 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/connector/usb-connector.yaml b/Documentation/devicetree/bindings/connector/usb-connector.yaml index 32509b98142e..92b49bc37939 100644 --- a/Documentation/devicetree/bindings/connector/usb-connector.yaml +++ b/Documentation/devicetree/bindings/connector/usb-connector.yaml @@ -149,6 +149,17 @@ properties: maxItems: 6 $ref: /schemas/types.yaml#/definitions/uint32-array + sink-vdos-v1: + description: An array of u32 with each entry, a Vendor Defined Message Object (VDO), + providing additional information corresponding to the product, the detailed bit + definitions and the order of each VDO can be found in + "USB Power Delivery Specification Revision 2.0, Version 1.3" chapter 6.4.4.3.1 Discover + Identity. User can specify the VDO array via VDO_IDH/_CERT/_PRODUCT/_CABLE/_AMA defined in + dt-bindings/usb/pd.h. + minItems: 3 + maxItems: 6 + $ref: /schemas/types.yaml#/definitions/uint32-array + op-sink-microwatt: description: Sink required operating power in microwatt, if source can't offer the power, Capability Mismatch is set. Required for power sink and @@ -207,6 +218,10 @@ properties: SNK_READY for non-pd link. type: boolean +dependencies: + sink-vdos-v1: [ 'sink-vdos' ] + sink-vdos: [ 'sink-vdos-v1' ] + required: - compatible diff --git a/include/dt-bindings/usb/pd.h b/include/dt-bindings/usb/pd.h index cb70b4ceedde..e6526b138174 100644 --- a/include/dt-bindings/usb/pd.h +++ b/include/dt-bindings/usb/pd.h @@ -106,6 +106,10 @@ * <20:16> :: Reserved, Shall be set to zero * <15:0> :: USB-IF assigned VID for this cable vendor */ + +/* PD Rev2.0 definition */ +#define IDH_PTYPE_UNDEF 0 + /* SOP Product Type (UFP) */ #define IDH_PTYPE_NOT_UFP 0 #define IDH_PTYPE_HUB 1 @@ -228,7 +232,25 @@ | ((pnum) & 0x1f)) /* - * Passive Cable VDO + * Cable VDO (for both Passive and Active Cable VDO in PD Rev2.0) + * --------- + * <31:28> :: Cable HW version + * <27:24> :: Cable FW version + * <23:20> :: Reserved, Shall be set to zero + * <19:18> :: type-C to Type-A/B/C/Captive (00b == A, 01 == B, 10 == C, 11 == Captive) + * <17> :: Reserved, Shall be set to zero + * <16:13> :: cable latency (0001 == <10ns(~1m length)) + * <12:11> :: cable termination type (11b == both ends active VCONN req) + * <10> :: SSTX1 Directionality support (0b == fixed, 1b == cfgable) + * <9> :: SSTX2 Directionality support + * <8> :: SSRX1 Directionality support + * <7> :: SSRX2 Directionality support + * <6:5> :: Vbus current handling capability (01b == 3A, 10b == 5A) + * <4> :: Vbus through cable (0b == no, 1b == yes) + * <3> :: SOP" controller present? (0b == no, 1b == yes) + * <2:0> :: USB SS Signaling support + * + * Passive Cable VDO (PD Rev3.0+) * --------- * <31:28> :: Cable HW version * <27:24> :: Cable FW version @@ -244,7 +266,7 @@ * <4:3> :: Reserved, Shall be set to zero * <2:0> :: USB highest speed * - * Active Cable VDO 1 + * Active Cable VDO 1 (PD Rev3.0+) * --------- * <31:28> :: Cable HW version * <27:24> :: Cable FW version @@ -266,7 +288,9 @@ #define CABLE_VDO_VER1_0 0 #define CABLE_VDO_VER1_3 3 -/* Connector Type */ +/* Connector Type (_ATYPE and _BTYPE are for PD Rev2.0 only) */ +#define CABLE_ATYPE 0 +#define CABLE_BTYPE 1 #define CABLE_CTYPE 2 #define CABLE_CAPTIVE 3 @@ -303,12 +327,22 @@ #define CABLE_CURR_3A 1 #define CABLE_CURR_5A 2 +/* USB SuperSpeed Signaling Support (PD Rev2.0) */ +#define CABLE_USBSS_U2_ONLY 0 +#define CABLE_USBSS_U31_GEN1 1 +#define CABLE_USBSS_U31_GEN2 2 + /* USB Highest Speed */ #define CABLE_USB2_ONLY 0 #define CABLE_USB32_GEN1 1 #define CABLE_USB32_4_GEN2 2 #define CABLE_USB4_GEN3 3 +#define VDO_CABLE(hw, fw, cbl, lat, term, tx1d, tx2d, rx1d, rx2d, cur, vps, sopp, usbss) \ + (((hw) & 0x7) << 28 | ((fw) & 0x7) << 24 | ((cbl) & 0x3) << 18 \ + | ((lat) & 0x7) << 13 | ((term) & 0x3) << 11 | (tx1d) << 10 \ + | (tx2d) << 9 | (rx1d) << 8 | (rx2d) << 7 | ((cur) & 0x3) << 5 \ + | (vps) << 4 | (sopp) << 3 | ((usbss) & 0x7)) #define VDO_PCABLE(hw, fw, ver, conn, lat, term, vbm, cur, spd) \ (((hw) & 0xf) << 28 | ((fw) & 0xf) << 24 | ((ver) & 0x7) << 21 \ | ((conn) & 0x3) << 18 | ((lat) & 0xf) << 13 | ((term) & 0x3) << 11 \ @@ -373,6 +407,35 @@ | ((hops) & 0x3) << 6 | (u2) << 5 | (u32) << 4 | (lane) << 3 \ | (iso) << 2 | (gen)) +/* + * AMA VDO (PD Rev2.0) + * --------- + * <31:28> :: Cable HW version + * <27:24> :: Cable FW version + * <23:12> :: Reserved, Shall be set to zero + * <11> :: SSTX1 Directionality support (0b == fixed, 1b == cfgable) + * <10> :: SSTX2 Directionality support + * <9> :: SSRX1 Directionality support + * <8> :: SSRX2 Directionality support + * <7:5> :: Vconn power + * <4> :: Vconn power required + * <3> :: Vbus power required + * <2:0> :: USB SS Signaling support + */ +#define VDO_AMA(hw, fw, tx1d, tx2d, rx1d, rx2d, vcpwr, vcr, vbr, usbss) \ + (((hw) & 0x7) << 28 | ((fw) & 0x7) << 24 \ + | (tx1d) << 11 | (tx2d) << 10 | (rx1d) << 9 | (rx2d) << 8 \ + | ((vcpwr) & 0x7) << 5 | (vcr) << 4 | (vbr) << 3 \ + | ((usbss) & 0x7)) + +#define PD_VDO_AMA_VCONN_REQ(vdo) (((vdo) >> 4) & 1) +#define PD_VDO_AMA_VBUS_REQ(vdo) (((vdo) >> 3) & 1) + +#define AMA_USBSS_U2_ONLY 0 +#define AMA_USBSS_U31_GEN1 1 +#define AMA_USBSS_U31_GEN2 2 +#define AMA_USBSS_BBONLY 3 + /* * VPD VDO * --------- -- cgit v1.3.1 From 52ea62e74ecf3dd60e6df0479320213470e2ae7f Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Fri, 4 Jun 2021 17:06:55 +0800 Subject: docs/zh_CN: add core api cachetlb translation Translate Documentation/core-api/cachetlb.rst into Chinese. Reviewed-by: Wu XiangCheng Signed-off-by: Yanteng Si Reviewed-by: Alex Shi Link: https://lore.kernel.org/r/20210604090655.1971227-1-siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/core-api/cachetlb.rst | 336 +++++++++++++++++++++ .../translations/zh_CN/core-api/index.rst | 7 +- 2 files changed, 342 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/core-api/cachetlb.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/core-api/cachetlb.rst b/Documentation/translations/zh_CN/core-api/cachetlb.rst new file mode 100644 index 000000000000..8376485a534d --- /dev/null +++ b/Documentation/translations/zh_CN/core-api/cachetlb.rst @@ -0,0 +1,336 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/core-api/cachetlb.rst + +:翻译: + + 司延腾 Yanteng Si + +:校译: + + 吴想成 Wu XiangCheng + +.. _cn_core-api_cachetlb: + +====================== +Linux下的缓存和TLB刷新 +====================== + +:作者: David S. Miller + +*译注:TLB,Translation Lookaside Buffer,页表缓存/变换旁查缓冲器* + +本文描述了由Linux虚拟内存子系统调用的缓存/TLB刷新接口。它列举了每个接 +口,描述了它的预期目的,以及接口被调用后的预期副作用。 + +下面描述的副作用是针对单处理器的实现,以及在单个处理器上发生的情况。若 +为SMP,则只需将定义简单地扩展一下,使发生在某个特定接口的副作用扩展到系 +统的所有处理器上。不要被这句话吓到,以为SMP的缓存/tlb刷新一定是很低 +效的,事实上,这是一个可以进行很多优化的领域。例如,如果可以证明一个用 +户地址空间从未在某个cpu上执行过(见mm_cpumask()),那么就不需要在该 +cpu上对这个地址空间进行刷新。 + +首先是TLB刷新接口,因为它们是最简单的。在Linux下,TLB被抽象为cpu +用来缓存从软件页表获得的虚拟->物理地址转换的东西。这意味着,如果软件页 +表发生变化,这个“TLB”缓存中就有可能出现过时(脏)的翻译。因此,当软件页表 +发生变化时,内核会在页表发生 *变化后* 调用以下一种刷新方法: + +1) ``void flush_tlb_all(void)`` + + 最严格的刷新。在这个接口运行后,任何以前的页表修改都会对cpu可见。 + + 这通常是在内核页表被改变时调用的,因为这种转换在本质上是“全局”的。 + +2) ``void flush_tlb_mm(struct mm_struct *mm)`` + + 这个接口从TLB中刷新整个用户地址空间。在运行后,这个接口必须确保 + 以前对地址空间‘mm’的任何页表修改对cpu来说是可见的。也就是说,在 + 运行后,TLB中不会有‘mm’的页表项。 + + 这个接口被用来处理整个地址空间的页表操作,比如在fork和exec过程 + 中发生的事情。 + +3) ``void flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end)`` + + 这里我们要从TLB中刷新一个特定范围的(用户)虚拟地址转换。在运行后, + 这个接口必须确保以前对‘start’到‘end-1’范围内的地址空间‘vma->vm_mm’ + 的任何页表修改对cpu来说是可见的。也就是说,在运行后,TLB中不会有 + ‘mm’的页表项用于‘start’到‘end-1’范围内的虚拟地址。 + + “vma”是用于该区域的备份存储。主要是用于munmap()类型的操作。 + + 提供这个接口是希望端口能够找到一个合适的有效方法来从TLB中删除多 + 个页面大小的转换,而不是让内核为每个可能被修改的页表项调用 + flush_tlb_page(见下文)。 + +4) ``void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)`` + + 这一次我们需要从TLB中删除PAGE_SIZE大小的转换。‘vma’是Linux用来跟 + 踪进程的mmap区域的支持结构体,地址空间可以通过vma->vm_mm获得。另 + 外,可以通过测试(vma->vm_flags & VM_EXEC)来查看这个区域是否是 + 可执行的(因此在split-tlb类型的设置中可能在“指令TLB”中)。 + + 在运行后,这个接口必须确保之前对用户虚拟地址“addr”的地址空间 + “vma->vm_mm”的页表修改对cpu来说是可见的。也就是说,在运行后,TLB + 中不会有虚拟地址‘addr’的‘vma->vm_mm’的页表项。 + + 这主要是在故障处理时使用。 + +5) ``void update_mmu_cache(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep)`` + + 在每个页面故障结束时,这个程序被调用,以告诉体系结构特定的代码,在 + 软件页表中,在地址空间“vma->vm_mm”的虚拟地址“地址”处,现在存在 + 一个翻译。 + + 可以用它所选择的任何方式使用这个信息来进行移植。例如,它可以使用这 + 个事件来为软件管理的TLB配置预装TLB转换。目前sparc64移植就是这么干 + 的。 + +接下来,我们有缓存刷新接口。一般来说,当Linux将现有的虚拟->物理映射 +改变为新的值时,其顺序将是以下形式之一:: + + 1) flush_cache_mm(mm); + change_all_page_tables_of(mm); + flush_tlb_mm(mm); + + 2) flush_cache_range(vma, start, end); + change_range_of_page_tables(mm, start, end); + flush_tlb_range(vma, start, end); + + 3) flush_cache_page(vma, addr, pfn); + set_pte(pte_pointer, new_pte_val); + flush_tlb_page(vma, addr); + +缓存级别的刷新将永远是第一位的,因为这允许我们正确处理那些缓存严格, +且在虚拟地址被从缓存中刷新时要求一个虚拟地址的虚拟->物理转换存在的系统。 +HyperSparc cpu就是这样一个具有这种属性的cpu。 + +下面的缓存刷新程序只需要在特定的cpu需要的范围内处理缓存刷新。大多数 +情况下,这些程序必须为cpu实现,这些cpu有虚拟索引的缓存,当虚拟->物 +理转换被改变或移除时,必须被刷新。因此,例如,IA32处理器的物理索引 +的物理标记的缓存没有必要实现这些接口,因为这些缓存是完全同步的,并 +且不依赖于翻译信息。 + +下面逐个列出这些程序: + +1) ``void flush_cache_mm(struct mm_struct *mm)`` + + 这个接口将整个用户地址空间从高速缓存中刷掉。也就是说,在运行后, + 将没有与‘mm’相关的缓存行。 + + 这个接口被用来处理整个地址空间的页表操作,比如在退出和执行过程 + 中发生的事情。 + +2) ``void flush_cache_dup_mm(struct mm_struct *mm)`` + + 这个接口将整个用户地址空间从高速缓存中刷新掉。也就是说,在运行 + 后,将没有与‘mm’相关的缓存行。 + + 这个接口被用来处理整个地址空间的页表操作,比如在fork过程中发生 + 的事情。 + + 这个选项与flush_cache_mm分开,以允许对VIPT缓存进行一些优化。 + +3) ``void flush_cache_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end)`` + + 在这里,我们要从缓存中刷新一个特定范围的(用户)虚拟地址。运行 + 后,在“start”到“end-1”范围内的虚拟地址的“vma->vm_mm”的缓存中 + 将没有页表项。 + + “vma”是被用于该区域的备份存储。主要是用于munmap()类型的操作。 + + 提供这个接口是希望端口能够找到一个合适的有效方法来从缓存中删 + 除多个页面大小的区域, 而不是让内核为每个可能被修改的页表项调 + 用 flush_cache_page (见下文)。 + +4) ``void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)`` + + 这一次我们需要从缓存中删除一个PAGE_SIZE大小的区域。“vma”是 + Linux用来跟踪进程的mmap区域的支持结构体,地址空间可以通过 + vma->vm_mm获得。另外,我们可以通过测试(vma->vm_flags & + VM_EXEC)来查看这个区域是否是可执行的(因此在“Harvard”类 + 型的缓存布局中可能是在“指令缓存”中)。 + + “pfn”表示“addr”所对应的物理页框(通过PAGE_SHIFT左移这个 + 值来获得物理地址)。正是这个映射应该从缓存中删除。 + + 在运行之后,对于虚拟地址‘addr’的‘vma->vm_mm’,在缓存中不会 + 有任何页表项,它被翻译成‘pfn’。 + + 这主要是在故障处理过程中使用。 + +5) ``void flush_cache_kmaps(void)`` + + 只有在平台使用高位内存的情况下才需要实现这个程序。它将在所有的 + kmaps失效之前被调用。 + + 运行后,内核虚拟地址范围PKMAP_ADDR(0)到PKMAP_ADDR(LAST_PKMAP) + 的缓存中将没有页表项。 + + 这个程序应该在asm/highmem.h中实现。 + +6) ``void flush_cache_vmap(unsigned long start, unsigned long end)`` + ``void flush_cache_vunmap(unsigned long start, unsigned long end)`` + + 在这里,在这两个接口中,我们从缓存中刷新一个特定范围的(内核) + 虚拟地址。运行后,在“start”到“end-1”范围内的虚拟地址的内核地 + 址空间的缓存中不会有页表项。 + + 这两个程序中的第一个是在vmap_range()安装了页表项之后调用的。 + 第二个是在vunmap_range()删除页表项之前调用的。 + +还有一类cpu缓存问题,目前需要一套完全不同的接口来正确处理。最大 +的问题是处理器的数据缓存中的虚拟别名。 + +.. note:: + + 这段内容有些晦涩,为了减轻中文阅读压力,特作此译注。 + + 别名(alias)属于缓存一致性问题,当不同的虚拟地址映射相同的 + 物理地址,而这些虚拟地址的index不同,此时就发生了别名现象(多 + 个虚拟地址被称为别名)。通俗点来说就是指同一个物理地址的数据被 + 加载到不同的cacheline中就会出现别名现象。 + + 常见的解决方法有两种:第一种是硬件维护一致性,设计特定的cpu电 + 路来解决问题(例如设计为PIPT的cache);第二种是软件维护一致性, + 就是下面介绍的sparc的解决方案——页面染色,涉及的技术细节太多, + 译者不便展开,请读者自行查阅相关资料。 + +您的移植是否容易在其D-cache中出现虚拟别名?嗯,如果您的D-cache +是虚拟索引的,且cache大于PAGE_SIZE(页大小),并且不能防止同一 +物理地址的多个cache行同时存在,您就会遇到这个问题。 + +如果你的D-cache有这个问题,首先正确定义asm/shmparam.h SHMLBA, +它基本上应该是你的虚拟寻址D-cache的大小(或者如果大小是可变的, +则是最大的可能大小)。这个设置将迫使SYSv IPC层只允许用户进程在 +这个值的倍数的地址上对共享内存进行映射。 + +.. note:: + + 这并不能解决共享mmaps的问题,请查看sparc64移植解决 + 这个问题的一个方法(特别是 SPARC_FLAG_MMAPSHARED)。 + +接下来,你必须解决所有其他情况下的D-cache别名问题。请记住这个事 +实,对于一个给定的页面映射到某个用户地址空间,总是至少还有一个映 +射,那就是内核在其线性映射中从PAGE_OFFSET开始。因此,一旦第一个 +用户将一个给定的物理页映射到它的地址空间,就意味着D-cache的别名 +问题有可能存在,因为内核已经将这个页映射到它的虚拟地址。 + + ``void copy_user_page(void *to, void *from, unsigned long addr, struct page *page)`` + ``void clear_user_page(void *to, unsigned long addr, struct page *page)`` + + 这两个程序在用户匿名或COW页中存储数据。它允许一个端口有效地 + 避免用户空间和内核之间的D-cache别名问题。 + + 例如,一个端口可以在复制过程中把“from”和“to”暂时映射到内核 + 的虚拟地址上。这两个页面的虚拟地址的选择方式是,内核的加载/存 + 储指令发生在虚拟地址上,而这些虚拟地址与用户的页面映射是相同 + 的“颜色”。例如,Sparc64就使用这种技术。 + + “addr”参数告诉了用户最终要映射这个页面的虚拟地址,“page”参 + 数给出了一个指向目标页结构体的指针。 + + 如果D-cache别名不是问题,这两个程序可以简单地直接调用 + memcpy/memset而不做其他事情。 + + ``void flush_dcache_page(struct page *page)`` + + 任何时候,当内核写到一个页面缓存页,或者内核要从一个页面缓存 + 页中读出,并且这个页面的用户空间共享/可写映射可能存在时, + 这个程序就会被调用。 + + .. note:: + + 这个程序只需要为有可能被映射到用户进程的地址空间的 + 页面缓存调用。因此,例如,处理页面缓存中vfs符号链 + 接的VFS层代码根本不需要调用这个接口。 + + “内核写入页面缓存的页面”这句话的意思是,具体来说,内核执行存 + 储指令,在该页面的页面->虚拟映射处弄脏该页面的数据。在这里,通 + 过刷新的手段处理D-cache的别名是很重要的,以确保这些内核存储对 + 该页的用户空间映射是可见的。 + + 推论的情况也同样重要,如果有用户对这个文件有共享+可写的映射, + 我们必须确保内核对这些页面的读取会看到用户所做的最新的存储。 + + 如果D-cache别名不是一个问题,这个程序可以简单地定义为该架构上 + 的nop。 + + 在page->flags (PG_arch_1)中有一个位是“架构私有”。内核保证, + 对于分页缓存的页面,当这样的页面第一次进入分页缓存时,它将清除 + 这个位。 + + 这使得这些接口可以更有效地被实现。如果目前没有用户进程映射这个 + 页面,它允许我们“推迟”(也许是无限期)实际的刷新过程。请看 + sparc64的flush_dcache_page和update_mmu_cache实现,以了解如 + 何做到这一点。 + + 这个想法是,首先在flush_dcache_page()时,如果page->mapping->i_mmap + 是一个空树,只需标记架构私有页标志位。之后,在update_mmu_cache() + 中,会对这个标志位进行检查,如果设置了,就进行刷新,并清除标志位。 + + .. important:: + + 通常很重要的是,如果你推迟刷新,实际的刷新发生在同一个 + CPU上,因为它将cpu存储到页面上,使其变脏。同样,请看 + sparc64关于如何处理这个问题的例子。 + + ``void copy_to_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long user_vaddr, void *dst, void *src, int len)`` + ``void copy_from_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long user_vaddr, void *dst, void *src, int len)`` + + 当内核需要复制任意的数据进出任意的用户页时(比如ptrace()),它将使 + 用这两个程序。 + + 任何必要的缓存刷新或其他需要发生的一致性操作都应该在这里发生。如果 + 处理器的指令缓存没有对cpu存储进行窥探,那么你很可能需要为 + copy_to_user_page()刷新指令缓存。 + + ``void flush_anon_page(struct vm_area_struct *vma, struct page *page, + unsigned long vmaddr)`` + + 当内核需要访问一个匿名页的内容时,它会调用这个函数(目前只有 + get_user_pages())。注意:flush_dcache_page()故意对匿名页不起作 + 用。默认的实现是nop(对于所有相干的架构应该保持这样)。对于不一致性 + 的架构,它应该刷新vmaddr处的页面缓存。 + + ``void flush_kernel_dcache_page(struct page *page)`` + + 当内核需要修改一个用kmap获得的用户页时,它会在所有修改完成后(但在 + kunmapping之前)调用这个函数,以使底层页面达到最新状态。这里假定用 + 户没有不一致性的缓存副本(即原始页面是从类似get_user_pages()的机制 + 中获得的)。默认的实现是一个nop,在所有相干的架构上都应该如此。在不 + 一致性的架构上,这应该刷新内核缓存中的页面(使用page_address(page))。 + + + ``void flush_icache_range(unsigned long start, unsigned long end)`` + + 当内核存储到它将执行的地址中时(例如在加载模块时),这个函数被调用。 + + 如果icache不对存储进行窥探,那么这个程序将需要对其进行刷新。 + + ``void flush_icache_page(struct vm_area_struct *vma, struct page *page)`` + + flush_icache_page的所有功能都可以在flush_dcache_page和update_mmu_cache + 中实现。在未来,我们希望能够完全删除这个接口。 + +最后一类API是用于I/O到内核内特意设置的别名地址范围。这种别名是通过使用 +vmap/vmalloc API设置的。由于内核I/O是通过物理页进行的,I/O子系统假定用户 +映射和内核偏移映射是唯一的别名。这对vmap别名来说是不正确的,所以内核中任何 +试图对vmap区域进行I/O的东西都必须手动管理一致性。它必须在做I/O之前刷新vmap +范围,并在I/O返回后使其失效。 + + ``void flush_kernel_vmap_range(void *vaddr, int size)`` + + 刷新vmap区域中指定的虚拟地址范围的内核缓存。这是为了确保内核在vmap范围 + 内修改的任何数据对物理页是可见的。这个设计是为了使这个区域可以安全地执 + 行I/O。注意,这个API并 *没有* 刷新该区域的偏移映射别名。 + + ``void invalidate_kernel_vmap_range(void *vaddr, int size) invalidates`` + + 在vmap区域的一个给定的虚拟地址范围的缓存,这可以防止处理器在物理页的I/O + 发生时通过投机性地读取数据而使缓存变脏。这只对读入vmap区域的数据是必要的。 diff --git a/Documentation/translations/zh_CN/core-api/index.rst b/Documentation/translations/zh_CN/core-api/index.rst index a8b2afcbf5bc..b4bde9396339 100644 --- a/Documentation/translations/zh_CN/core-api/index.rst +++ b/Documentation/translations/zh_CN/core-api/index.rst @@ -76,9 +76,14 @@ Todolist: 缓存管理,CPU热插拔管理等。 -Todolist: +.. toctree:: + :maxdepth: 1 cachetlb + +Todolist: + + cpu_hotplug memory-hotplug genericirq -- cgit v1.3.1 From b0cbba2e44c629f1b4efb31701b1d3f3ade6926e Mon Sep 17 00:00:00 2001 From: Hailong Liu Date: Thu, 3 Jun 2021 22:52:27 +0800 Subject: docs/zh_CN: Add zh_CN/admin-guide/lockup-watchdogs.rst Add translation zh_CN/admin-guide/lockup-watchdogs.rst and link it to zh_CN/admin-guide/index.rst while clean its todo entry. Reviewed-by: Yanteng Si Signed-off-by: Hailong Liu Link: https://lore.kernel.org/r/20210603145227.30956-1-liuhailongg6@163.com Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/admin-guide/index.rst | 2 +- .../zh_CN/admin-guide/lockup-watchdogs.rst | 66 ++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/admin-guide/lockup-watchdogs.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/admin-guide/index.rst b/Documentation/translations/zh_CN/admin-guide/index.rst index be835ec8e632..460034cbc2ab 100644 --- a/Documentation/translations/zh_CN/admin-guide/index.rst +++ b/Documentation/translations/zh_CN/admin-guide/index.rst @@ -65,6 +65,7 @@ Todolist: clearing-warn-once cpu-load + lockup-watchdogs unicode Todolist: @@ -100,7 +101,6 @@ Todolist: laptops/index lcd-panel-cgram ldm - lockup-watchdogs LSM/index md media/index diff --git a/Documentation/translations/zh_CN/admin-guide/lockup-watchdogs.rst b/Documentation/translations/zh_CN/admin-guide/lockup-watchdogs.rst new file mode 100644 index 000000000000..55ed3f4af442 --- /dev/null +++ b/Documentation/translations/zh_CN/admin-guide/lockup-watchdogs.rst @@ -0,0 +1,66 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/admin-guide/lockup-watchdogs.rst +:Translator: Hailong Liu + +.. _cn_lockup-watchdogs: + + +================================================= +Softlockup与hardlockup检测机制(又名:nmi_watchdog) +================================================= + +Linux中内核实现了一种用以检测系统发生softlockup和hardlockup的看门狗机制。 + +Softlockup是一种会引发系统在内核态中一直循环超过20秒(详见下面“实现”小节)导致 +其他任务没有机会得到运行的BUG。一旦检测到'softlockup'发生,默认情况下系统会打 +印当前堆栈跟踪信息并进入锁定状态。也可配置使其在检测到'softlockup'后进入panic +状态;通过sysctl命令设置“kernel.softlockup_panic”、使用内核启动参数 +“softlockup_panic”(详见Documentation/admin-guide/kernel-parameters.rst)以及使 +能内核编译选项“BOOTPARAM_SOFTLOCKUP_PANIC”都可实现这种配置。 + +而'hardlockup'是一种会引发系统在内核态一直循环超过10秒钟(详见"实现"小节)导致其 +他中断没有机会运行的缺陷。与'softlockup'情况类似,除了使用sysctl命令设置 +'hardlockup_panic'、使能内核选项“BOOTPARAM_HARDLOCKUP_PANIC”以及使用内核参数 +"nmi_watchdog"(详见:”Documentation/admin-guide/kernel-parameters.rst“)外,一旦检 +测到'hardlockup'默认情况下系统打印当前堆栈跟踪信息,然后进入锁定状态。 + +这个panic选项也可以与panic_timeout结合使用(这个panic_timeout是通过稍具迷惑性的 +sysctl命令"kernel.panic"来设置),使系统在panic指定时间后自动重启。 + +实现 +==== + +Softlockup和hardlockup分别建立在hrtimer(高精度定时器)和perf两个子系统上而实现。 +这也就意味着理论上任何架构只要实现了这两个子系统就支持这两种检测机制。 + +Hrtimer用于周期性产生中断并唤醒watchdog线程;NMI perf事件则以”watchdog_thresh“ +(编译时默认初始化为10秒,也可通过”watchdog_thresh“这个sysctl接口来进行配置修改) +为间隔周期产生以检测 hardlockups。如果一个CPU在这个时间段内没有检测到hrtimer中 +断发生,'hardlockup 检测器'(即NMI perf事件处理函数)将会视系统配置而选择产生内核 +警告或者直接panic。 + +而watchdog线程本质上是一个高优先级内核线程,每调度一次就对时间戳进行一次更新。 +如果时间戳在2*watchdog_thresh(这个是softlockup的触发门限)这段时间都未更新,那么 +"softlocup 检测器"(内部hrtimer定时器回调函数)会将相关的调试信息打印到系统日志中, +然后如果系统配置了进入panic流程则进入panic,否则内核继续执行。 + +Hrtimer定时器的周期是2*watchdog_thresh/5,也就是说在hardlockup被触发前hrtimer有 +2~3次机会产生时钟中断。 + +如上所述,内核相当于为系统管理员提供了一个可调节hrtimer定时器和perf事件周期长度 +的调节旋钮。如何通过这个旋钮为特定使用场景配置一个合理的周期值要对lockups检测的 +响应速度和lockups检测开销这二者之间进行权衡。 + +默认情况下所有在线cpu上都会运行一个watchdog线程。不过在内核配置了”NO_HZ_FULL“的 +情况下watchdog线程默认只会运行在管家(housekeeping)cpu上,而”nohz_full“启动参数指 +定的cpu上则不会有watchdog线程运行。试想,如果我们允许watchdog线程在”nohz_full“指 +定的cpu上运行,这些cpu上必须得运行时钟定时器来激发watchdog线程调度;这样一来就会 +使”nohz_full“保护用户程序免受内核干扰的功能失效。当然,副作用就是”nohz_full“指定 +的cpu即使在内核产生了lockup问题我们也无法检测到。不过,至少我们可以允许watchdog +线程在管家(non-tickless)核上继续运行以便我们能继续正常的监测这些cpus上的lockups +事件。 + +不论哪种情况都可以通过sysctl命令kernel.watchdog_cpumask来对没有运行watchdog线程 +的cpu集合进行调节。对于nohz_full而言,如果nohz_full cpu上有异常挂住的情况,通过 +这种方式打开这些cpu上的watchdog进行调试可能会有所作用。 -- cgit v1.3.1 From c003555a026f56dae1d6b522045a7917150ceabb Mon Sep 17 00:00:00 2001 From: Wan Jiabing Date: Thu, 3 Jun 2021 22:11:17 +0800 Subject: docs/zh_CN: add translations in zh_CN/dev-tools/kasan Add new zh translations * zh_CN/dev-tools/kasan.rst and link it to zh_CN/dev-tools/index.rst Reviewed-by: Fangrui Song Signed-off-by: Wan Jiabing Reviewed-by: Alex Shi Link: https://lore.kernel.org/r/20210603141127.101689-1-wanjiabing@vivo.com Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/dev-tools/index.rst | 2 +- .../translations/zh_CN/dev-tools/kasan.rst | 417 +++++++++++++++++++++ 2 files changed, 418 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/dev-tools/kasan.rst (limited to 'Documentation') diff --git a/Documentation/translations/zh_CN/dev-tools/index.rst b/Documentation/translations/zh_CN/dev-tools/index.rst index fd73c479917b..e6c99f2f543f 100644 --- a/Documentation/translations/zh_CN/dev-tools/index.rst +++ b/Documentation/translations/zh_CN/dev-tools/index.rst @@ -19,13 +19,13 @@ :maxdepth: 2 gcov + kasan Todolist: - coccinelle - sparse - kcov - - kasan - ubsan - kmemleak - kcsan diff --git a/Documentation/translations/zh_CN/dev-tools/kasan.rst b/Documentation/translations/zh_CN/dev-tools/kasan.rst new file mode 100644 index 000000000000..23db9d419047 --- /dev/null +++ b/Documentation/translations/zh_CN/dev-tools/kasan.rst @@ -0,0 +1,417 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/dev-tools/kasan.rst +:Translator: 万家兵 Wan Jiabing + +内核地址消毒剂(KASAN) +===================== + +概述 +---- + +KernelAddressSANitizer(KASAN)是一种动态内存安全错误检测工具,主要功能是 +检查内存越界访问和使用已释放内存的问题。KASAN有三种模式: + +1. 通用KASAN(与用户空间的ASan类似) +2. 基于软件标签的KASAN(与用户空间的HWASan类似) +3. 基于硬件标签的KASAN(基于硬件内存标签) + +由于通用KASAN的内存开销较大,通用KASAN主要用于调试。基于软件标签的KASAN +可用于dogfood测试,因为它具有较低的内存开销,并允许将其用于实际工作量。 +基于硬件标签的KASAN具有较低的内存和性能开销,因此可用于生产。同时可用于 +检测现场内存问题或作为安全缓解措施。 + +软件KASAN模式(#1和#2)使用编译时工具在每次内存访问之前插入有效性检查, +因此需要一个支持它的编译器版本。 + +通用KASAN在GCC和Clang受支持。GCC需要8.3.0或更高版本。任何受支持的Clang +版本都是兼容的,但从Clang 11才开始支持检测全局变量的越界访问。 + +基于软件标签的KASAN模式仅在Clang中受支持。 + +硬件KASAN模式(#3)依赖硬件来执行检查,但仍需要支持内存标签指令的编译器 +版本。GCC 10+和Clang 11+支持此模式。 + +两种软件KASAN模式都适用于SLUB和SLAB内存分配器,而基于硬件标签的KASAN目前 +仅支持SLUB。 + +目前x86_64、arm、arm64、xtensa、s390、riscv架构支持通用KASAN模式,仅 +arm64架构支持基于标签的KASAN模式。 + +用法 +---- + +要启用KASAN,请使用以下命令配置内核:: + + CONFIG_KASAN=y + +同时在 ``CONFIG_KASAN_GENERIC`` (启用通用KASAN模式), ``CONFIG_KASAN_SW_TAGS`` +(启用基于硬件标签的KASAN模式),和 ``CONFIG_KASAN_HW_TAGS`` (启用基于硬件标签 +的KASAN模式)之间进行选择。 + +对于软件模式,还可以在 ``CONFIG_KASAN_OUTLINE`` 和 ``CONFIG_KASAN_INLINE`` +之间进行选择。outline和inline是编译器插桩类型。前者产生较小的二进制文件, +而后者快1.1-2倍。 + +要将受影响的slab对象的alloc和free堆栈跟踪包含到报告中,请启用 +``CONFIG_STACKTRACE`` 。要包括受影响物理页面的分配和释放堆栈跟踪的话, +请启用 ``CONFIG_PAGE_OWNER`` 并使用 ``page_owner=on`` 进行引导。 + +错误报告 +~~~~~~~~ + +典型的KASAN报告如下所示:: + + ================================================================== + BUG: KASAN: slab-out-of-bounds in kmalloc_oob_right+0xa8/0xbc [test_kasan] + Write of size 1 at addr ffff8801f44ec37b by task insmod/2760 + + CPU: 1 PID: 2760 Comm: insmod Not tainted 4.19.0-rc3+ #698 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014 + Call Trace: + dump_stack+0x94/0xd8 + print_address_description+0x73/0x280 + kasan_report+0x144/0x187 + __asan_report_store1_noabort+0x17/0x20 + kmalloc_oob_right+0xa8/0xbc [test_kasan] + kmalloc_tests_init+0x16/0x700 [test_kasan] + do_one_initcall+0xa5/0x3ae + do_init_module+0x1b6/0x547 + load_module+0x75df/0x8070 + __do_sys_init_module+0x1c6/0x200 + __x64_sys_init_module+0x6e/0xb0 + do_syscall_64+0x9f/0x2c0 + entry_SYSCALL_64_after_hwframe+0x44/0xa9 + RIP: 0033:0x7f96443109da + RSP: 002b:00007ffcf0b51b08 EFLAGS: 00000202 ORIG_RAX: 00000000000000af + RAX: ffffffffffffffda RBX: 000055dc3ee521a0 RCX: 00007f96443109da + RDX: 00007f96445cff88 RSI: 0000000000057a50 RDI: 00007f9644992000 + RBP: 000055dc3ee510b0 R08: 0000000000000003 R09: 0000000000000000 + R10: 00007f964430cd0a R11: 0000000000000202 R12: 00007f96445cff88 + R13: 000055dc3ee51090 R14: 0000000000000000 R15: 0000000000000000 + + Allocated by task 2760: + save_stack+0x43/0xd0 + kasan_kmalloc+0xa7/0xd0 + kmem_cache_alloc_trace+0xe1/0x1b0 + kmalloc_oob_right+0x56/0xbc [test_kasan] + kmalloc_tests_init+0x16/0x700 [test_kasan] + do_one_initcall+0xa5/0x3ae + do_init_module+0x1b6/0x547 + load_module+0x75df/0x8070 + __do_sys_init_module+0x1c6/0x200 + __x64_sys_init_module+0x6e/0xb0 + do_syscall_64+0x9f/0x2c0 + entry_SYSCALL_64_after_hwframe+0x44/0xa9 + + Freed by task 815: + save_stack+0x43/0xd0 + __kasan_slab_free+0x135/0x190 + kasan_slab_free+0xe/0x10 + kfree+0x93/0x1a0 + umh_complete+0x6a/0xa0 + call_usermodehelper_exec_async+0x4c3/0x640 + ret_from_fork+0x35/0x40 + + The buggy address belongs to the object at ffff8801f44ec300 + which belongs to the cache kmalloc-128 of size 128 + The buggy address is located 123 bytes inside of + 128-byte region [ffff8801f44ec300, ffff8801f44ec380) + The buggy address belongs to the page: + page:ffffea0007d13b00 count:1 mapcount:0 mapping:ffff8801f7001640 index:0x0 + flags: 0x200000000000100(slab) + raw: 0200000000000100 ffffea0007d11dc0 0000001a0000001a ffff8801f7001640 + raw: 0000000000000000 0000000080150015 00000001ffffffff 0000000000000000 + page dumped because: kasan: bad access detected + + Memory state around the buggy address: + ffff8801f44ec200: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb + ffff8801f44ec280: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc + >ffff8801f44ec300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 + ^ + ffff8801f44ec380: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb + ffff8801f44ec400: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc + ================================================================== + +报告标题总结了发生的错误类型以及导致该错误的访问类型。紧随其后的是错误访问的 +堆栈跟踪、所访问内存分配位置的堆栈跟踪(对于访问了slab对象的情况)以及对象 +被释放的位置的堆栈跟踪(对于访问已释放内存的问题报告)。接下来是对访问的 +slab对象的描述以及关于访问的内存页的信息。 + +最后,报告展示了访问地址周围的内存状态。在内部,KASAN单独跟踪每个内存颗粒的 +内存状态,根据KASAN模式分为8或16个对齐字节。报告的内存状态部分中的每个数字 +都显示了围绕访问地址的其中一个内存颗粒的状态。 + +对于通用KASAN,每个内存颗粒的大小为8个字节。每个颗粒的状态被编码在一个影子字节 +中。这8个字节可以是可访问的,部分访问的,已释放的或成为Redzone的一部分。KASAN +对每个影子字节使用以下编码:00表示对应内存区域的所有8个字节都可以访问;数字N +(1 <= N <= 7)表示前N个字节可访问,其他(8 - N)个字节不可访问;任何负值都表示 +无法访问整个8字节。KASAN使用不同的负值来区分不同类型的不可访问内存,如redzones +或已释放的内存(参见 mm/kasan/kasan.h)。 + +在上面的报告中,箭头指向影子字节 ``03`` ,表示访问的地址是部分可访问的。 + +对于基于标签的KASAN模式,报告最后的部分显示了访问地址周围的内存标签 +(参考 `实施细则`_ 章节)。 + +请注意,KASAN错误标题(如 ``slab-out-of-bounds`` 或 ``use-after-free`` ) +是尽量接近的:KASAN根据其拥有的有限信息打印出最可能的错误类型。错误的实际类型 +可能会有所不同。 + +通用KASAN还报告两个辅助调用堆栈跟踪。这些堆栈跟踪指向代码中与对象交互但不直接 +出现在错误访问堆栈跟踪中的位置。目前,这包括 call_rcu() 和排队的工作队列。 + +启动参数 +~~~~~~~~ + +KASAN受通用 ``panic_on_warn`` 命令行参数的影响。启用该功能后,KASAN在打印错误 +报告后会引起内核恐慌。 + +默认情况下,KASAN只为第一次无效内存访问打印错误报告。使用 ``kasan_multi_shot`` , +KASAN会针对每个无效访问打印报告。这有效地禁用了KASAN报告的 ``panic_on_warn`` 。 + +基于硬件标签的KASAN模式(请参阅下面有关各种模式的部分)旨在在生产中用作安全缓解 +措施。因此,它支持允许禁用KASAN或控制其功能的引导参数。 + +- ``kasan=off`` 或 ``=on`` 控制KASAN是否启用 (默认: ``on`` )。 + +- ``kasan.mode=sync`` 或 ``=async`` 控制KASAN是否配置为同步或异步执行模式(默认: + ``sync`` )。同步模式:当标签检查错误发生时,立即检测到错误访问。异步模式: + 延迟错误访问检测。当标签检查错误发生时,信息存储在硬件中(在arm64的 + TFSR_EL1寄存器中)。内核会定期检查硬件,并且仅在这些检查期间报告标签错误。 + +- ``kasan.stacktrace=off`` 或 ``=on`` 禁用或启用alloc和free堆栈跟踪收集 + (默认: ``on`` )。 + +- ``kasan.fault=report`` 或 ``=panic`` 控制是只打印KASAN报告还是同时使内核恐慌 + (默认: ``report`` )。即使启用了 ``kasan_multi_shot`` ,也会发生内核恐慌。 + +实施细则 +-------- + +通用KASAN +~~~~~~~~~ + +软件KASAN模式使用影子内存来记录每个内存字节是否可以安全访问,并使用编译时工具 +在每次内存访问之前插入影子内存检查。 + +通用KASAN将1/8的内核内存专用于其影子内存(16TB以覆盖x86_64上的128TB),并使用 +具有比例和偏移量的直接映射将内存地址转换为其相应的影子地址。 + +这是将地址转换为其相应影子地址的函数:: + + static inline void *kasan_mem_to_shadow(const void *addr) + { + return (void *)((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT) + + KASAN_SHADOW_OFFSET; + } + +在这里 ``KASAN_SHADOW_SCALE_SHIFT = 3`` 。 + +编译时工具用于插入内存访问检查。编译器在每次访问大小为1、2、4、8或16的内存之前 +插入函数调用( ``__asan_load*(addr)`` , ``__asan_store*(addr)``)。这些函数通过 +检查相应的影子内存来检查内存访问是否有效。 + +使用inline插桩,编译器不进行函数调用,而是直接插入代码来检查影子内存。此选项 +显著地增大了内核体积,但与outline插桩内核相比,它提供了x1.1-x2的性能提升。 + +通用KASAN是唯一一种通过隔离延迟重新使用已释放对象的模式 +(参见 mm/kasan/quarantine.c 以了解实现)。 + +基于软件标签的KASAN模式 +~~~~~~~~~~~~~~~~~~~~~~~ + +基于软件标签的KASAN使用软件内存标签方法来检查访问有效性。目前仅针对arm64架构实现。 + +基于软件标签的KASAN使用arm64 CPU的顶部字节忽略(TBI)特性在内核指针的顶部字节中 +存储一个指针标签。它使用影子内存来存储与每个16字节内存单元相关的内存标签(因此, +它将内核内存的1/16专用于影子内存)。 + +在每次内存分配时,基于软件标签的KASAN都会生成一个随机标签,用这个标签标记分配 +的内存,并将相同的标签嵌入到返回的指针中。 + +基于软件标签的KASAN使用编译时工具在每次内存访问之前插入检查。这些检查确保正在 +访问的内存的标签等于用于访问该内存的指针的标签。如果标签不匹配,基于软件标签 +的KASAN会打印错误报告。 + +基于软件标签的KASAN也有两种插桩模式(outline,发出回调来检查内存访问;inline, +执行内联的影子内存检查)。使用outline插桩模式,会从执行访问检查的函数打印错误 +报告。使用inline插桩,编译器会发出 ``brk`` 指令,并使用专用的 ``brk`` 处理程序 +来打印错误报告。 + +基于软件标签的KASAN使用0xFF作为匹配所有指针标签(不检查通过带有0xFF指针标签 +的指针进行的访问)。值0xFE当前保留用于标记已释放的内存区域。 + +基于软件标签的KASAN目前仅支持对Slab和page_alloc内存进行标记。 + +基于硬件标签的KASAN模式 +~~~~~~~~~~~~~~~~~~~~~~~ + +基于硬件标签的KASAN在概念上类似于软件模式,但它是使用硬件内存标签作为支持而 +不是编译器插桩和影子内存。 + +基于硬件标签的KASAN目前仅针对arm64架构实现,并且基于ARMv8.5指令集架构中引入 +的arm64内存标记扩展(MTE)和最高字节忽略(TBI)。 + +特殊的arm64指令用于为每次内存分配指定内存标签。相同的标签被指定给指向这些分配 +的指针。在每次内存访问时,硬件确保正在访问的内存的标签等于用于访问该内存的指针 +的标签。如果标签不匹配,则会生成故障并打印报告。 + +基于硬件标签的KASAN使用0xFF作为匹配所有指针标签(不检查通过带有0xFF指针标签的 +指针进行的访问)。值0xFE当前保留用于标记已释放的内存区域。 + +基于硬件标签的KASAN目前仅支持对Slab和page_alloc内存进行标记。 + +如果硬件不支持MTE(ARMv8.5之前),则不会启用基于硬件标签的KASAN。在这种情况下, +所有KASAN引导参数都将被忽略。 + +请注意,启用CONFIG_KASAN_HW_TAGS始终会导致启用内核中的TBI。即使提供了 +``kasan.mode=off`` 或硬件不支持MTE(但支持TBI)。 + +基于硬件标签的KASAN只报告第一个发现的错误。之后,MTE标签检查将被禁用。 + +影子内存 +-------- + +内核将内存映射到地址空间的几个不同部分。内核虚拟地址的范围很大:没有足够的真实 +内存来支持内核可以访问的每个地址的真实影子区域。因此,KASAN只为地址空间的某些 +部分映射真实的影子。 + +默认行为 +~~~~~~~~ + +默认情况下,体系结构仅将实际内存映射到用于线性映射的阴影区域(以及可能的其他 +小区域)。对于所有其他区域 —— 例如vmalloc和vmemmap空间 —— 一个只读页面被映射 +到阴影区域上。这个只读的影子页面声明所有内存访问都是允许的。 + +这给模块带来了一个问题:它们不存在于线性映射中,而是存在于专用的模块空间中。 +通过连接模块分配器,KASAN临时映射真实的影子内存以覆盖它们。例如,这允许检测 +对模块全局变量的无效访问。 + +这也造成了与 ``VMAP_STACK`` 的不兼容:如果堆栈位于vmalloc空间中,它将被分配 +只读页面的影子内存,并且内核在尝试为堆栈变量设置影子数据时会出错。 + +CONFIG_KASAN_VMALLOC +~~~~~~~~~~~~~~~~~~~~ + +使用 ``CONFIG_KASAN_VMALLOC`` ,KASAN可以以更大的内存使用为代价覆盖vmalloc +空间。目前,这在x86、riscv、s390和powerpc上受支持。 + +这通过连接到vmalloc和vmap并动态分配真实的影子内存来支持映射。 + +vmalloc空间中的大多数映射都很小,需要不到一整页的阴影空间。因此,为每个映射 +分配一个完整的影子页面将是一种浪费。此外,为了确保不同的映射使用不同的影子 +页面,映射必须与 ``KASAN_GRANULE_SIZE * PAGE_SIZE`` 对齐。 + +相反,KASAN跨多个映射共享后备空间。当vmalloc空间中的映射使用影子区域的特定 +页面时,它会分配一个后备页面。此页面稍后可以由其他vmalloc映射共享。 + +KASAN连接到vmap基础架构以懒清理未使用的影子内存。 + +为了避免交换映射的困难,KASAN预测覆盖vmalloc空间的阴影区域部分将不会被早期 +的阴影页面覆盖,但是将不会被映射。这将需要更改特定于arch的代码。 + +这允许在x86上支持 ``VMAP_STACK`` ,并且可以简化对没有固定模块区域的架构的支持。 + +对于开发者 +---------- + +忽略访问 +~~~~~~~~ + +软件KASAN模式使用编译器插桩来插入有效性检查。此类检测可能与内核的某些部分 +不兼容,因此需要禁用。 + +内核的其他部分可能会访问已分配对象的元数据。通常,KASAN会检测并报告此类访问, +但在某些情况下(例如,在内存分配器中),这些访问是有效的。 + +对于软件KASAN模式,要禁用特定文件或目录的检测,请将 ``KASAN_SANITIZE`` 添加 +到相应的内核Makefile中: + +- 对于单个文件(例如,main.o):: + + KASAN_SANITIZE_main.o := n + +- 对于一个目录下的所有文件:: + + KASAN_SANITIZE := n + +对于软件KASAN模式,要在每个函数的基础上禁用检测,请使用KASAN特定的 +``__no_sanitize_address`` 函数属性或通用的 ``noinstr`` 。 + +请注意,禁用编译器插桩(基于每个文件或每个函数)会使KASAN忽略在软件KASAN模式 +的代码中直接发生的访问。当访问是间接发生的(通过调用检测函数)或使用没有编译器 +插桩的基于硬件标签的模式时,它没有帮助。 + +对于软件KASAN模式,要在当前任务的一部分内核代码中禁用KASAN报告,请使用 +``kasan_disable_current()``/``kasan_enable_current()`` 部分注释这部分代码。 +这也会禁用通过函数调用发生的间接访问的报告。 + +对于基于标签的KASAN模式(包括硬件模式),要禁用访问检查,请使用 +``kasan_reset_tag()`` 或 ``page_kasan_tag_reset()`` 。请注意,通过 +``page_kasan_tag_reset()`` 临时禁用访问检查需要通过 ``page_kasan_tag`` +/ ``page_kasan_tag_set`` 保存和恢复每页KASAN标签。 + +测试 +~~~~ + +有一些KASAN测试可以验证KASAN是否正常工作并可以检测某些类型的内存损坏。 +测试由两部分组成: + +1. 与KUnit测试框架集成的测试。使用 ``CONFIG_KASAN_KUNIT_TEST`` 启用。 +这些测试可以通过几种不同的方式自动运行和部分验证;请参阅下面的说明。 + +2. 与KUnit不兼容的测试。使用 ``CONFIG_KASAN_MODULE_TEST`` 启用并且只能作为模块 +运行。这些测试只能通过加载内核模块并检查内核日志以获取KASAN报告来手动验证。 + +如果检测到错误,每个KUnit兼容的KASAN测试都会打印多个KASAN报告之一,然后测试打印 +其编号和状态。 + +当测试通过:: + + ok 28 - kmalloc_double_kzfree + +当由于 ``kmalloc`` 失败而导致测试失败时:: + + # kmalloc_large_oob_right: ASSERTION FAILED at lib/test_kasan.c:163 + Expected ptr is not null, but is + not ok 4 - kmalloc_large_oob_right + +当由于缺少KASAN报告而导致测试失败时:: + + # kmalloc_double_kzfree: EXPECTATION FAILED at lib/test_kasan.c:629 + Expected kasan_data->report_expected == kasan_data->report_found, but + kasan_data->report_expected == 1 + kasan_data->report_found == 0 + not ok 28 - kmalloc_double_kzfree + +最后打印所有KASAN测试的累积状态。成功:: + + ok 1 - kasan + +或者,如果其中一项测试失败:: + + not ok 1 - kasan + +有几种方法可以运行与KUnit兼容的KASAN测试。 + +1. 可加载模块 + + 启用 ``CONFIG_KUNIT`` 后,KASAN-KUnit测试可以构建为可加载模块,并通过使用 + ``insmod`` 或 ``modprobe`` 加载 ``test_kasan.ko`` 来运行。 + +2. 内置 + + 通过内置 ``CONFIG_KUNIT`` ,也可以内置KASAN-KUnit测试。在这种情况下, + 测试将在启动时作为后期初始化调用运行。 + +3. 使用kunit_tool + + 通过内置 ``CONFIG_KUNIT`` 和 ``CONFIG_KASAN_KUNIT_TEST`` ,还可以使用 + ``kunit_tool`` 以更易读的方式查看KUnit测试结果。这不会打印通过测试 + 的KASAN报告。有关 ``kunit_tool`` 更多最新信息,请参阅 + `KUnit文档 `_ 。 + +.. _KUnit: https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html -- cgit v1.3.1 From f9ce26c56d37fa6d32f700dfc77f4ceb445ce215 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 2 Jun 2021 13:29:14 -0700 Subject: docs: networking: Replace strncpy() with strscpy() Replace example code's use of strncpy() with strscpy() functions. Using strncpy() is considered deprecated: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings Signed-off-by: Kees Cook Acked-by: Dmitry Torokhov Link: https://lore.kernel.org/r/20210602202914.4079123-1-keescook@chromium.org Signed-off-by: Jonathan Corbet --- Documentation/input/joydev/joystick-api.rst | 2 +- Documentation/networking/packet_mmap.rst | 2 +- Documentation/networking/tuntap.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/input/joydev/joystick-api.rst b/Documentation/input/joydev/joystick-api.rst index af5934c10c1c..5db6dc6fe1c5 100644 --- a/Documentation/input/joydev/joystick-api.rst +++ b/Documentation/input/joydev/joystick-api.rst @@ -263,7 +263,7 @@ possible overrun should the name be too long:: char name[128]; if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0) - strncpy(name, "Unknown", sizeof(name)); + strscpy(name, "Unknown", sizeof(name)); printf("Name: %s\n", name); diff --git a/Documentation/networking/packet_mmap.rst b/Documentation/networking/packet_mmap.rst index 500ef60b1b82..c5da1a5d93de 100644 --- a/Documentation/networking/packet_mmap.rst +++ b/Documentation/networking/packet_mmap.rst @@ -153,7 +153,7 @@ As capture, each frame contains two parts:: struct ifreq s_ifr; ... - strncpy (s_ifr.ifr_name, "eth0", sizeof(s_ifr.ifr_name)); + strscpy_pad (s_ifr.ifr_name, "eth0", sizeof(s_ifr.ifr_name)); /* get interface index of eth0 */ ioctl(this->socket, SIOCGIFINDEX, &s_ifr); diff --git a/Documentation/networking/tuntap.rst b/Documentation/networking/tuntap.rst index a59d1dd6fdcc..4d7087f727be 100644 --- a/Documentation/networking/tuntap.rst +++ b/Documentation/networking/tuntap.rst @@ -107,7 +107,7 @@ Note that the character pointer becomes overwritten with the real device name */ ifr.ifr_flags = IFF_TUN; if( *dev ) - strncpy(ifr.ifr_name, dev, IFNAMSIZ); + strscpy_pad(ifr.ifr_name, dev, IFNAMSIZ); if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){ close(fd); -- cgit v1.3.1 From e53eeac9a9d78dc550b889897f5315424bb63e10 Mon Sep 17 00:00:00 2001 From: Gao Mingfei Date: Tue, 1 Jun 2021 08:51:45 +0000 Subject: docs: block: fix stat.rst document error Update the description of the device stat files to include the proper number of fields. Signed-off-by: Gao Mingfei Link: https://lore.kernel.org/r/20210601085145.3273-1-g199209@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/block/stat.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/block/stat.rst b/Documentation/block/stat.rst index 77311335c08b..a1cd9db2058f 100644 --- a/Documentation/block/stat.rst +++ b/Documentation/block/stat.rst @@ -18,7 +18,7 @@ A. each, it would be impossible to guarantee that a set of readings represent a single point in time. -The stat file consists of a single line of text containing 11 decimal +The stat file consists of a single line of text containing 17 decimal values separated by whitespace. The fields are summarized in the following table, and described in more detail below. -- cgit v1.3.1 From fb7b26a8b1d0b82c79e93deb12d624011c7a4e0e Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Mon, 31 May 2021 22:42:35 +0900 Subject: docs: Fix typo in Documentation/arm/marvell.rst Fix typo in the documentation, changed from 'comatible' to 'compatible. Signed-off-by: Nobuhiro Iwamatsu Link: https://lore.kernel.org/r/20210531134235.720351-1-iwamatsu@nigauri.org Signed-off-by: Jonathan Corbet --- Documentation/arm/marvell.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/arm/marvell.rst b/Documentation/arm/marvell.rst index c50be711ec72..db2246493d18 100644 --- a/Documentation/arm/marvell.rst +++ b/Documentation/arm/marvell.rst @@ -259,7 +259,7 @@ Storage family https://web.archive.org/web/20191129073953/http://www.marvell.com/storage/armada-sp/ Core: - Sheeva ARMv7 comatible Quad-core PJ4C + Sheeva ARMv7 compatible Quad-core PJ4C (not supported in upstream Linux kernel) -- cgit v1.3.1 From acda97acb2e98c97895d81d20494bf6a4bc67c6c Mon Sep 17 00:00:00 2001 From: Igor Matheus Andrade Torrente Date: Mon, 31 May 2021 10:05:15 -0300 Subject: docs: convert dax.txt to rst Change the file extension and add the rst constructs to integrate this doc to the documentation infrastructure and take advantage of rst features. Signed-off-by: Igor Matheus Andrade Torrente Link: https://lore.kernel.org/r/20210531130515.10309-1-igormtorrente@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/filesystems/dax.rst | 291 ++++++++++++++++++++++++++++++++++++ Documentation/filesystems/dax.txt | 257 ------------------------------- Documentation/filesystems/index.rst | 1 + 3 files changed, 292 insertions(+), 257 deletions(-) create mode 100644 Documentation/filesystems/dax.rst delete mode 100644 Documentation/filesystems/dax.txt (limited to 'Documentation') diff --git a/Documentation/filesystems/dax.rst b/Documentation/filesystems/dax.rst new file mode 100644 index 000000000000..9a1b8fd9e82b --- /dev/null +++ b/Documentation/filesystems/dax.rst @@ -0,0 +1,291 @@ +======================= +Direct Access for files +======================= + +Motivation +---------- + +The page cache is usually used to buffer reads and writes to files. +It is also used to provide the pages which are mapped into userspace +by a call to mmap. + +For block devices that are memory-like, the page cache pages would be +unnecessary copies of the original storage. The `DAX` code removes the +extra copy by performing reads and writes directly to the storage device. +For file mappings, the storage device is mapped directly into userspace. + + +Usage +----- + +If you have a block device which supports `DAX`, you can make a filesystem +on it as usual. The `DAX` code currently only supports files with a block +size equal to your kernel's `PAGE_SIZE`, so you may need to specify a block +size when creating the filesystem. + +Currently 3 filesystems support `DAX`: ext2, ext4 and xfs. Enabling `DAX` on them +is different. + +Enabling DAX on ext2 +-------------------- + +When mounting the filesystem, use the ``-o dax`` option on the command line or +add 'dax' to the options in ``/etc/fstab``. This works to enable `DAX` on all files +within the filesystem. It is equivalent to the ``-o dax=always`` behavior below. + + +Enabling DAX on xfs and ext4 +---------------------------- + +Summary +------- + + 1. There exists an in-kernel file access mode flag `S_DAX` that corresponds to + the statx flag `STATX_ATTR_DAX`. See the manpage for statx(2) for details + about this access mode. + + 2. There exists a persistent flag `FS_XFLAG_DAX` that can be applied to regular + files and directories. This advisory flag can be set or cleared at any + time, but doing so does not immediately affect the `S_DAX` state. + + 3. If the persistent `FS_XFLAG_DAX` flag is set on a directory, this flag will + be inherited by all regular files and subdirectories that are subsequently + created in this directory. Files and subdirectories that exist at the time + this flag is set or cleared on the parent directory are not modified by + this modification of the parent directory. + + 4. There exist dax mount options which can override `FS_XFLAG_DAX` in the + setting of the `S_DAX` flag. Given underlying storage which supports `DAX` the + following hold: + + ``-o dax=inode`` means "follow `FS_XFLAG_DAX`" and is the default. + + ``-o dax=never`` means "never set `S_DAX`, ignore `FS_XFLAG_DAX`." + + ``-o dax=always`` means "always set `S_DAX` ignore `FS_XFLAG_DAX`." + + ``-o dax`` is a legacy option which is an alias for ``dax=always``. + + .. warning:: + + The option ``-o dax`` may be removed in the future so ``-o dax=always`` is + the preferred method for specifying this behavior. + + .. note:: + + Modifications to and the inheritance behavior of `FS_XFLAG_DAX` remain + the same even when the filesystem is mounted with a dax option. However, + in-core inode state (`S_DAX`) will be overridden until the filesystem is + remounted with dax=inode and the inode is evicted from kernel memory. + + 5. The `S_DAX` policy can be changed via: + + a) Setting the parent directory `FS_XFLAG_DAX` as needed before files are + created + + b) Setting the appropriate dax="foo" mount option + + c) Changing the `FS_XFLAG_DAX` flag on existing regular files and + directories. This has runtime constraints and limitations that are + described in 6) below. + + 6. When changing the `S_DAX` policy via toggling the persistent `FS_XFLAG_DAX` + flag, the change to existing regular files won't take effect until the + files are closed by all processes. + + +Details +------- + +There are 2 per-file dax flags. One is a persistent inode setting (`FS_XFLAG_DAX`) +and the other is a volatile flag indicating the active state of the feature +(`S_DAX`). + +`FS_XFLAG_DAX` is preserved within the filesystem. This persistent config +setting can be set, cleared and/or queried using the `FS_IOC_FS`[`GS`]`ETXATTR` ioctl +(see ioctl_xfs_fsgetxattr(2)) or an utility such as 'xfs_io'. + +New files and directories automatically inherit `FS_XFLAG_DAX` from +their parent directory **when created**. Therefore, setting `FS_XFLAG_DAX` at +directory creation time can be used to set a default behavior for an entire +sub-tree. + +To clarify inheritance, here are 3 examples: + +Example A: + +.. code-block:: shell + + mkdir -p a/b/c + xfs_io -c 'chattr +x' a + mkdir a/b/c/d + mkdir a/e + + ------[outcome]------ + + dax: a,e + no dax: b,c,d + +Example B: + +.. code-block:: shell + + mkdir a + xfs_io -c 'chattr +x' a + mkdir -p a/b/c/d + + ------[outcome]------ + + dax: a,b,c,d + no dax: + +Example C: + +.. code-block:: shell + + mkdir -p a/b/c + xfs_io -c 'chattr +x' c + mkdir a/b/c/d + + ------[outcome]------ + + dax: c,d + no dax: a,b + +The current enabled state (`S_DAX`) is set when a file inode is instantiated in +memory by the kernel. It is set based on the underlying media support, the +value of `FS_XFLAG_DAX` and the filesystem's dax mount option. + +statx can be used to query `S_DAX`. + +.. note:: + + That only regular files will ever have `S_DAX` set and therefore statx + will never indicate that `S_DAX` is set on directories. + +Setting the `FS_XFLAG_DAX` flag (specifically or through inheritance) occurs even +if the underlying media does not support dax and/or the filesystem is +overridden with a mount option. + + +Implementation Tips for Block Driver Writers +-------------------------------------------- + +To support `DAX` in your block driver, implement the 'direct_access' +block device operation. It is used to translate the sector number +(expressed in units of 512-byte sectors) to a page frame number (pfn) +that identifies the physical page for the memory. It also returns a +kernel virtual address that can be used to access the memory. + +The direct_access method takes a 'size' parameter that indicates the +number of bytes being requested. The function should return the number +of bytes that can be contiguously accessed at that offset. It may also +return a negative errno if an error occurs. + +In order to support this method, the storage must be byte-accessible by +the CPU at all times. If your device uses paging techniques to expose +a large amount of memory through a smaller window, then you cannot +implement direct_access. Equally, if your device can occasionally +stall the CPU for an extended period, you should also not attempt to +implement direct_access. + +These block devices may be used for inspiration: +- brd: RAM backed block device driver +- dcssblk: s390 dcss block device driver +- pmem: NVDIMM persistent memory driver + + +Implementation Tips for Filesystem Writers +------------------------------------------ + +Filesystem support consists of: + +* Adding support to mark inodes as being `DAX` by setting the `S_DAX` flag in + i_flags +* Implementing ->read_iter and ->write_iter operations which use + :c:func:`dax_iomap_rw()` when inode has `S_DAX` flag set +* Implementing an mmap file operation for `DAX` files which sets the + `VM_MIXEDMAP` and `VM_HUGEPAGE` flags on the `VMA`, and setting the vm_ops to + include handlers for fault, pmd_fault, page_mkwrite, pfn_mkwrite. These + handlers should probably call :c:func:`dax_iomap_fault()` passing the + appropriate fault size and iomap operations. +* Calling :c:func:`iomap_zero_range()` passing appropriate iomap operations + instead of :c:func:`block_truncate_page()` for `DAX` files +* Ensuring that there is sufficient locking between reads, writes, + truncates and page faults + +The iomap handlers for allocating blocks must make sure that allocated blocks +are zeroed out and converted to written extents before being returned to avoid +exposure of uninitialized data through mmap. + +These filesystems may be used for inspiration: + +.. seealso:: + + ext2: see Documentation/filesystems/ext2.rst + +.. seealso:: + + xfs: see Documentation/admin-guide/xfs.rst + +.. seealso:: + + ext4: see Documentation/filesystems/ext4/ + + +Handling Media Errors +--------------------- + +The libnvdimm subsystem stores a record of known media error locations for +each pmem block device (in gendisk->badblocks). If we fault at such location, +or one with a latent error not yet discovered, the application can expect +to receive a `SIGBUS`. Libnvdimm also allows clearing of these errors by simply +writing the affected sectors (through the pmem driver, and if the underlying +NVDIMM supports the clear_poison DSM defined by ACPI). + +Since `DAX` IO normally doesn't go through the ``driver/bio`` path, applications or +sysadmins have an option to restore the lost data from a prior ``backup/inbuilt`` +redundancy in the following ways: + +1. Delete the affected file, and restore from a backup (sysadmin route): + This will free the filesystem blocks that were being used by the file, + and the next time they're allocated, they will be zeroed first, which + happens through the driver, and will clear bad sectors. + +2. Truncate or hole-punch the part of the file that has a bad-block (at least + an entire aligned sector has to be hole-punched, but not necessarily an + entire filesystem block). + +These are the two basic paths that allow `DAX` filesystems to continue operating +in the presence of media errors. More robust error recovery mechanisms can be +built on top of this in the future, for example, involving redundancy/mirroring +provided at the block layer through DM, or additionally, at the filesystem +level. These would have to rely on the above two tenets, that error clearing +can happen either by sending an IO through the driver, or zeroing (also through +the driver). + + +Shortcomings +------------ + +Even if the kernel or its modules are stored on a filesystem that supports +`DAX` on a block device that supports `DAX`, they will still be copied into RAM. + +The DAX code does not work correctly on architectures which have virtually +mapped caches such as ARM, MIPS and SPARC. + +Calling :c:func:`get_user_pages()` on a range of user memory that has been +mmaped from a `DAX` file will fail when there are no 'struct page' to describe +those pages. This problem has been addressed in some device drivers +by adding optional struct page support for pages under the control of +the driver (see `CONFIG_NVDIMM_PFN` in ``drivers/nvdimm`` for an example of +how to do this). In the non struct page cases `O_DIRECT` reads/writes to +those memory ranges from a non-`DAX` file will fail + + +.. note:: + + `O_DIRECT` reads/writes _of a `DAX` file do work, it is the memory that + is being accessed that is key here). Other things that will not work in + the non struct page case include RDMA, :c:func:`sendfile()` and + :c:func:`splice()`. diff --git a/Documentation/filesystems/dax.txt b/Documentation/filesystems/dax.txt deleted file mode 100644 index e03c20564f3a..000000000000 --- a/Documentation/filesystems/dax.txt +++ /dev/null @@ -1,257 +0,0 @@ -Direct Access for files ------------------------ - -Motivation ----------- - -The page cache is usually used to buffer reads and writes to files. -It is also used to provide the pages which are mapped into userspace -by a call to mmap. - -For block devices that are memory-like, the page cache pages would be -unnecessary copies of the original storage. The DAX code removes the -extra copy by performing reads and writes directly to the storage device. -For file mappings, the storage device is mapped directly into userspace. - - -Usage ------ - -If you have a block device which supports DAX, you can make a filesystem -on it as usual. The DAX code currently only supports files with a block -size equal to your kernel's PAGE_SIZE, so you may need to specify a block -size when creating the filesystem. - -Currently 3 filesystems support DAX: ext2, ext4 and xfs. Enabling DAX on them -is different. - -Enabling DAX on ext2 ------------------------------ - -When mounting the filesystem, use the "-o dax" option on the command line or -add 'dax' to the options in /etc/fstab. This works to enable DAX on all files -within the filesystem. It is equivalent to the '-o dax=always' behavior below. - - -Enabling DAX on xfs and ext4 ----------------------------- - -Summary -------- - - 1. There exists an in-kernel file access mode flag S_DAX that corresponds to - the statx flag STATX_ATTR_DAX. See the manpage for statx(2) for details - about this access mode. - - 2. There exists a persistent flag FS_XFLAG_DAX that can be applied to regular - files and directories. This advisory flag can be set or cleared at any - time, but doing so does not immediately affect the S_DAX state. - - 3. If the persistent FS_XFLAG_DAX flag is set on a directory, this flag will - be inherited by all regular files and subdirectories that are subsequently - created in this directory. Files and subdirectories that exist at the time - this flag is set or cleared on the parent directory are not modified by - this modification of the parent directory. - - 4. There exist dax mount options which can override FS_XFLAG_DAX in the - setting of the S_DAX flag. Given underlying storage which supports DAX the - following hold: - - "-o dax=inode" means "follow FS_XFLAG_DAX" and is the default. - - "-o dax=never" means "never set S_DAX, ignore FS_XFLAG_DAX." - - "-o dax=always" means "always set S_DAX ignore FS_XFLAG_DAX." - - "-o dax" is a legacy option which is an alias for "dax=always". - This may be removed in the future so "-o dax=always" is - the preferred method for specifying this behavior. - - NOTE: Modifications to and the inheritance behavior of FS_XFLAG_DAX remain - the same even when the filesystem is mounted with a dax option. However, - in-core inode state (S_DAX) will be overridden until the filesystem is - remounted with dax=inode and the inode is evicted from kernel memory. - - 5. The S_DAX policy can be changed via: - - a) Setting the parent directory FS_XFLAG_DAX as needed before files are - created - - b) Setting the appropriate dax="foo" mount option - - c) Changing the FS_XFLAG_DAX flag on existing regular files and - directories. This has runtime constraints and limitations that are - described in 6) below. - - 6. When changing the S_DAX policy via toggling the persistent FS_XFLAG_DAX - flag, the change to existing regular files won't take effect until the - files are closed by all processes. - - -Details -------- - -There are 2 per-file dax flags. One is a persistent inode setting (FS_XFLAG_DAX) -and the other is a volatile flag indicating the active state of the feature -(S_DAX). - -FS_XFLAG_DAX is preserved within the filesystem. This persistent config -setting can be set, cleared and/or queried using the FS_IOC_FS[GS]ETXATTR ioctl -(see ioctl_xfs_fsgetxattr(2)) or an utility such as 'xfs_io'. - -New files and directories automatically inherit FS_XFLAG_DAX from -their parent directory _when_ _created_. Therefore, setting FS_XFLAG_DAX at -directory creation time can be used to set a default behavior for an entire -sub-tree. - -To clarify inheritance, here are 3 examples: - -Example A: - -mkdir -p a/b/c -xfs_io -c 'chattr +x' a -mkdir a/b/c/d -mkdir a/e - - dax: a,e - no dax: b,c,d - -Example B: - -mkdir a -xfs_io -c 'chattr +x' a -mkdir -p a/b/c/d - - dax: a,b,c,d - no dax: - -Example C: - -mkdir -p a/b/c -xfs_io -c 'chattr +x' c -mkdir a/b/c/d - - dax: c,d - no dax: a,b - - -The current enabled state (S_DAX) is set when a file inode is instantiated in -memory by the kernel. It is set based on the underlying media support, the -value of FS_XFLAG_DAX and the filesystem's dax mount option. - -statx can be used to query S_DAX. NOTE that only regular files will ever have -S_DAX set and therefore statx will never indicate that S_DAX is set on -directories. - -Setting the FS_XFLAG_DAX flag (specifically or through inheritance) occurs even -if the underlying media does not support dax and/or the filesystem is -overridden with a mount option. - - - -Implementation Tips for Block Driver Writers --------------------------------------------- - -To support DAX in your block driver, implement the 'direct_access' -block device operation. It is used to translate the sector number -(expressed in units of 512-byte sectors) to a page frame number (pfn) -that identifies the physical page for the memory. It also returns a -kernel virtual address that can be used to access the memory. - -The direct_access method takes a 'size' parameter that indicates the -number of bytes being requested. The function should return the number -of bytes that can be contiguously accessed at that offset. It may also -return a negative errno if an error occurs. - -In order to support this method, the storage must be byte-accessible by -the CPU at all times. If your device uses paging techniques to expose -a large amount of memory through a smaller window, then you cannot -implement direct_access. Equally, if your device can occasionally -stall the CPU for an extended period, you should also not attempt to -implement direct_access. - -These block devices may be used for inspiration: -- brd: RAM backed block device driver -- dcssblk: s390 dcss block device driver -- pmem: NVDIMM persistent memory driver - - -Implementation Tips for Filesystem Writers ------------------------------------------- - -Filesystem support consists of -- adding support to mark inodes as being DAX by setting the S_DAX flag in - i_flags -- implementing ->read_iter and ->write_iter operations which use dax_iomap_rw() - when inode has S_DAX flag set -- implementing an mmap file operation for DAX files which sets the - VM_MIXEDMAP and VM_HUGEPAGE flags on the VMA, and setting the vm_ops to - include handlers for fault, pmd_fault, page_mkwrite, pfn_mkwrite. These - handlers should probably call dax_iomap_fault() passing the appropriate - fault size and iomap operations. -- calling iomap_zero_range() passing appropriate iomap operations instead of - block_truncate_page() for DAX files -- ensuring that there is sufficient locking between reads, writes, - truncates and page faults - -The iomap handlers for allocating blocks must make sure that allocated blocks -are zeroed out and converted to written extents before being returned to avoid -exposure of uninitialized data through mmap. - -These filesystems may be used for inspiration: -- ext2: see Documentation/filesystems/ext2.rst -- ext4: see Documentation/filesystems/ext4/ -- xfs: see Documentation/admin-guide/xfs.rst - - -Handling Media Errors ---------------------- - -The libnvdimm subsystem stores a record of known media error locations for -each pmem block device (in gendisk->badblocks). If we fault at such location, -or one with a latent error not yet discovered, the application can expect -to receive a SIGBUS. Libnvdimm also allows clearing of these errors by simply -writing the affected sectors (through the pmem driver, and if the underlying -NVDIMM supports the clear_poison DSM defined by ACPI). - -Since DAX IO normally doesn't go through the driver/bio path, applications or -sysadmins have an option to restore the lost data from a prior backup/inbuilt -redundancy in the following ways: - -1. Delete the affected file, and restore from a backup (sysadmin route): - This will free the filesystem blocks that were being used by the file, - and the next time they're allocated, they will be zeroed first, which - happens through the driver, and will clear bad sectors. - -2. Truncate or hole-punch the part of the file that has a bad-block (at least - an entire aligned sector has to be hole-punched, but not necessarily an - entire filesystem block). - -These are the two basic paths that allow DAX filesystems to continue operating -in the presence of media errors. More robust error recovery mechanisms can be -built on top of this in the future, for example, involving redundancy/mirroring -provided at the block layer through DM, or additionally, at the filesystem -level. These would have to rely on the above two tenets, that error clearing -can happen either by sending an IO through the driver, or zeroing (also through -the driver). - - -Shortcomings ------------- - -Even if the kernel or its modules are stored on a filesystem that supports -DAX on a block device that supports DAX, they will still be copied into RAM. - -The DAX code does not work correctly on architectures which have virtually -mapped caches such as ARM, MIPS and SPARC. - -Calling get_user_pages() on a range of user memory that has been mmaped -from a DAX file will fail when there are no 'struct page' to describe -those pages. This problem has been addressed in some device drivers -by adding optional struct page support for pages under the control of -the driver (see CONFIG_NVDIMM_PFN in drivers/nvdimm for an example of -how to do this). In the non struct page cases O_DIRECT reads/writes to -those memory ranges from a non-DAX file will fail (note that O_DIRECT -reads/writes _of a DAX file_ do work, it is the memory that is being -accessed that is key here). Other things that will not work in the -non struct page case include RDMA, sendfile() and splice(). diff --git a/Documentation/filesystems/index.rst b/Documentation/filesystems/index.rst index d4853cb919d2..246af51b277a 100644 --- a/Documentation/filesystems/index.rst +++ b/Documentation/filesystems/index.rst @@ -77,6 +77,7 @@ Documentation for filesystem implementations. coda configfs cramfs + dax debugfs dlmfs ecryptfs -- cgit v1.3.1 From e22808071d4d23596e6cc8f62588225515789031 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 1 Jun 2021 13:31:55 +0200 Subject: dt-bindings: irqchip: renesas-irqc: Add R-Car M3-W+ support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document support for the Interrupt Controller for External Devices (INT-EC) in the Renesas R-Car M3-W+ (r8a77961) SoC. Signed-off-by: Geert Uytterhoeven Reviewed-by: Niklas Söderlund Reviewed-by: Yoshihiro Shimoda Acked-by: Rob Herring Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/55d2c30cb14b2e10193a7fd4aa7670c70f360037.1622546880.git.geert+renesas@glider.be --- Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.yaml | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.yaml b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.yaml index b67b8cbd33fc..abb22db3bb28 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.yaml @@ -29,6 +29,7 @@ properties: - renesas,intc-ex-r8a774c0 # RZ/G2E - renesas,intc-ex-r8a7795 # R-Car H3 - renesas,intc-ex-r8a7796 # R-Car M3-W + - renesas,intc-ex-r8a77961 # R-Car M3-W+ - renesas,intc-ex-r8a77965 # R-Car M3-N - renesas,intc-ex-r8a77970 # R-Car V3M - renesas,intc-ex-r8a77980 # R-Car V3H -- cgit v1.3.1 From 1a6a9044b96729abacede172d7591c714a5b81d1 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 1 Jun 2021 10:53:53 +0300 Subject: x86/setup: Remove CONFIG_X86_RESERVE_LOW and reservelow= options The CONFIG_X86_RESERVE_LOW build time and reservelow= command line option allowed to control the amount of memory under 1M that would be reserved at boot to avoid using memory that can be potentially clobbered by BIOS. Since the entire range under 1M is always reserved there is no need for these options anymore and they can be removed. Signed-off-by: Mike Rapoport Signed-off-by: Borislav Petkov Link: https://lkml.kernel.org/r/20210601075354.5149-3-rppt@kernel.org --- Documentation/admin-guide/kernel-parameters.txt | 5 ----- arch/x86/Kconfig | 29 ------------------------- arch/x86/kernel/setup.c | 24 -------------------- 3 files changed, 58 deletions(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index cb89dbdedc46..d7d813032c51 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -4775,11 +4775,6 @@ Reserves a hole at the top of the kernel virtual address space. - reservelow= [X86] - Format: nn[K] - Set the amount of memory to reserve for BIOS at - the bottom of the address space. - reset_devices [KNL] Force drivers to reset the underlying device during initialization. diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 0045e1b44190..86dae426798b 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1693,35 +1693,6 @@ config X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK Set whether the default state of memory_corruption_check is on or off. -config X86_RESERVE_LOW - int "Amount of low memory, in kilobytes, to reserve for the BIOS" - default 64 - range 4 640 - help - Specify the amount of low memory to reserve for the BIOS. - - The first page contains BIOS data structures that the kernel - must not use, so that page must always be reserved. - - By default we reserve the first 64K of physical RAM, as a - number of BIOSes are known to corrupt that memory range - during events such as suspend/resume or monitor cable - insertion, so it must not be used by the kernel. - - You can set this to 4 if you are absolutely sure that you - trust the BIOS to get all its memory reservations and usages - right. If you know your BIOS have problems beyond the - default 64K area, you can set this to 640 to avoid using the - entire low memory range. - - If you have doubts about the BIOS (e.g. suspend/resume does - not work or there's kernel crashes after certain hardware - hotplug events) then you might want to enable - X86_CHECK_BIOS_CORRUPTION=y to allow the kernel to check - typical corruption patterns. - - Leave this to the default value of 64 if you are unsure. - config MATH_EMULATION bool depends on MODIFY_LDT_SYSCALL diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 1e720626069a..7638ac6c3d80 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -695,30 +695,6 @@ static void __init e820_add_kernel_range(void) e820__range_add(start, size, E820_TYPE_RAM); } -static unsigned reserve_low = CONFIG_X86_RESERVE_LOW << 10; - -static int __init parse_reservelow(char *p) -{ - unsigned long long size; - - if (!p) - return -EINVAL; - - size = memparse(p, &p); - - if (size < 4096) - size = 4096; - - if (size > 640*1024) - size = 640*1024; - - reserve_low = size; - - return 0; -} - -early_param("reservelow", parse_reservelow); - static void __init early_reserve_memory(void) { /* -- cgit v1.3.1 From 269b4dd3e8b34edec44c5bb0016ee96353638618 Mon Sep 17 00:00:00 2001 From: John Cox Date: Fri, 30 Apr 2021 18:48:13 +0200 Subject: media: hevc: Add sps_max_sub_layers_minus1 to v4l2_ctrl_hevc_sps sps_max_sub_layers_minus1 is needed if the driver wishes to determine whether or not a frame might be used for reference. Signed-off-by: John Cox Reviewed-by: Benjamin Gaignard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 3 +++ include/media/hevc-ctrls.h | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index 0b8061666c57..2b5edab55bb4 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -2707,6 +2707,9 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - * - __u8 - ``chroma_format_idc`` - + * - __u8 + - ``sps_max_sub_layers_minus1`` + - * - __u64 - ``flags`` - See :ref:`Sequence Parameter Set Flags ` diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h index 226fcfa0e026..36e4c93707ae 100644 --- a/include/media/hevc-ctrls.h +++ b/include/media/hevc-ctrls.h @@ -75,8 +75,7 @@ struct v4l2_ctrl_hevc_sps { __u8 num_short_term_ref_pic_sets; __u8 num_long_term_ref_pics_sps; __u8 chroma_format_idc; - - __u8 padding; + __u8 sps_max_sub_layers_minus1; __u64 flags; }; -- cgit v1.3.1 From 54203301d02a3afff13a002f3c2cffb30f59a2fb Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 15 Apr 2021 10:55:30 +0200 Subject: media: dt-bindings: media: atmel-isc: convert to yaml Convert the Atmel ISC to yaml binding format. Signed-off-by: Eugen Hristev Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/atmel,isc.yaml | 114 +++++++++++++++++++++ .../devicetree/bindings/media/atmel-isc.txt | 65 ------------ 2 files changed, 114 insertions(+), 65 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/atmel,isc.yaml delete mode 100644 Documentation/devicetree/bindings/media/atmel-isc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/atmel,isc.yaml b/Documentation/devicetree/bindings/media/atmel,isc.yaml new file mode 100644 index 000000000000..3e4bb8892d94 --- /dev/null +++ b/Documentation/devicetree/bindings/media/atmel,isc.yaml @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2016-2021 Microchip Technology, Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/atmel,isc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Atmel Image Sensor Controller (ISC) + +maintainers: + - Eugen Hristev + +description: | + The Image Sensor Controller (ISC) device provides the video input capabilities for the + Atmel/Microchip AT91 SAMA family of devices. + + The ISC has a single parallel input that supports RAW Bayer, RGB or YUV video, + with both external synchronization and BT.656 synchronization for the latter. + +properties: + compatible: + const: atmel,sama5d2-isc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 3 + maxItems: 3 + + clock-names: + items: + - const: hclock + - const: iscck + - const: gck + + '#clock-cells': + const: 0 + + clock-output-names: + const: isc-mck + + port: + $ref: /schemas/graph.yaml#/properties/port + description: + Input port node, single endpoint describing the input pad. + + properties: + endpoint: + $ref: video-interfaces.yaml# + + properties: + remote-endpoint: true + + bus-width: + enum: [8, 9, 10, 11, 12] + default: 12 + + hsync-active: + enum: [0, 1] + default: 1 + + vsync-active: + enum: [0, 1] + default: 1 + + pclk-sample: + enum: [0, 1] + default: 1 + + required: + - remote-endpoint + + additionalProperties: false + + additionalProperties: false + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + - clock-output-names + - port + +additionalProperties: false + +examples: + - | + #include + + isc: isc@f0008000 { + compatible = "atmel,sama5d2-isc"; + reg = <0xf0008000 0x4000>; + interrupts = <46 IRQ_TYPE_LEVEL_HIGH 5>; + clocks = <&isc_clk>, <&iscck>, <&isc_gclk>; + clock-names = "hclock", "iscck", "gck"; + #clock-cells = <0>; + clock-output-names = "isc-mck"; + + port { + isc_0: endpoint { + remote-endpoint = <&ov7740_0>; + hsync-active = <1>; + vsync-active = <0>; + pclk-sample = <1>; + bus-width = <8>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/media/atmel-isc.txt b/Documentation/devicetree/bindings/media/atmel-isc.txt deleted file mode 100644 index bbe0e87c6188..000000000000 --- a/Documentation/devicetree/bindings/media/atmel-isc.txt +++ /dev/null @@ -1,65 +0,0 @@ -Atmel Image Sensor Controller (ISC) ----------------------------------------------- - -Required properties for ISC: -- compatible - Must be "atmel,sama5d2-isc". -- reg - Physical base address and length of the registers set for the device. -- interrupts - Should contain IRQ line for the ISC. -- clocks - List of clock specifiers, corresponding to entries in - the clock-names property; - Please refer to clock-bindings.txt. -- clock-names - Required elements: "hclock", "iscck", "gck". -- #clock-cells - Should be 0. -- clock-output-names - Should be "isc-mck". -- pinctrl-names, pinctrl-0 - Please refer to pinctrl-bindings.txt. - -ISC supports a single port node with parallel bus. It should contain one -'port' child node with child 'endpoint' node. Please refer to the bindings -defined in Documentation/devicetree/bindings/media/video-interfaces.txt. - -Example: -isc: isc@f0008000 { - compatible = "atmel,sama5d2-isc"; - reg = <0xf0008000 0x4000>; - interrupts = <46 IRQ_TYPE_LEVEL_HIGH 5>; - clocks = <&isc_clk>, <&iscck>, <&isc_gclk>; - clock-names = "hclock", "iscck", "gck"; - #clock-cells = <0>; - clock-output-names = "isc-mck"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_isc_base &pinctrl_isc_data_8bit &pinctrl_isc_data_9_10 &pinctrl_isc_data_11_12>; - - port { - isc_0: endpoint { - remote-endpoint = <&ov7740_0>; - hsync-active = <1>; - vsync-active = <0>; - pclk-sample = <1>; - }; - }; -}; - -i2c1: i2c@fc028000 { - ov7740: camera@21 { - compatible = "ovti,ov7740"; - reg = <0x21>; - clocks = <&isc>; - clock-names = "xvclk"; - assigned-clocks = <&isc>; - assigned-clock-rates = <24000000>; - - port { - ov7740_0: endpoint { - remote-endpoint = <&isc_0>; - }; - }; - }; -}; -- cgit v1.3.1 From 7b8d3d03df83aae74519b34022e95dec577af1df Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 15 Apr 2021 20:45:00 +0200 Subject: media: dt-bindings: media: add microchip,xisc device bindings Add bindings for the Microchip eXtended Image Sensor Controller. Based on the atmel,isc.yaml binding. Signed-off-by: Eugen Hristev Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/microchip,xisc.yaml | 129 +++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/microchip,xisc.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/microchip,xisc.yaml b/Documentation/devicetree/bindings/media/microchip,xisc.yaml new file mode 100644 index 000000000000..41afe2e5f133 --- /dev/null +++ b/Documentation/devicetree/bindings/media/microchip,xisc.yaml @@ -0,0 +1,129 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2021 Microchip Technology, Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/microchip,xisc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip eXtended Image Sensor Controller (XISC) + +maintainers: + - Eugen Hristev + +description: | + The eXtended Image Sensor Controller (XISC) device provides the video input capabilities for the + Microchip AT91 SAM family of devices. + + The XISC has a single internal parallel input that supports RAW Bayer, RGB or YUV video. + The source can be either a demuxer from a CSI2 type of bus, or a simple direct bridge to a + parallel sensor. + + The XISC provides one clock output that is used to clock the demuxer/bridge. + +properties: + compatible: + const: microchip,sama7g5-isc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: hclock + + '#clock-cells': + const: 0 + + clock-output-names: + const: isc-mck + + microchip,mipi-mode: + type: boolean + description: + As the XISC is usually connected to a demux/bridge, the XISC receives + the same type of input, however, it should be aware of the type of + signals received. The mipi-mode enables different internal handling + of the data and clock lines. + + port: + $ref: /schemas/graph.yaml#/properties/port + description: + Input port node, single endpoint describing the input pad. + + properties: + endpoint: + $ref: video-interfaces.yaml# + + properties: + bus-type: + enum: [5, 6] + + remote-endpoint: true + + bus-width: + enum: [8, 9, 10, 11, 12] + default: 12 + + hsync-active: + enum: [0, 1] + default: 1 + + vsync-active: + enum: [0, 1] + default: 1 + + pclk-sample: + enum: [0, 1] + default: 1 + + required: + - remote-endpoint + - bus-type + + additionalProperties: false + + additionalProperties: false + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + - clock-output-names + - port + +additionalProperties: false + +examples: + - | + #include + #include + #include + + xisc: xisc@e1408000 { + compatible = "microchip,sama7g5-isc"; + reg = <0xe1408000 0x2000>; + interrupts = ; + clocks = <&pmc PMC_TYPE_PERIPHERAL 56>; + clock-names = "hclock"; + #clock-cells = <0>; + clock-output-names = "isc-mck"; + + port { + xisc_in: endpoint { + bus-type = <5>; /* Parallel */ + remote-endpoint = <&csi2dc_out>; + hsync-active = <1>; + vsync-active = <1>; + bus-width = <12>; + }; + }; + }; + -- cgit v1.3.1 From 53a370f621a04a06bd2402c13580d7e4eb172c98 Mon Sep 17 00:00:00 2001 From: Alexander Voronov Date: Tue, 1 Jun 2021 22:28:12 +0200 Subject: media: rc: add keymap for Toshiba CT-90405 remote This is an NEC remote control device shipped with some Toshiba TVs. Signed-off-by: Alexander Voronov Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/rc.yaml | 1 + drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-ct-90405.c | 86 +++++++++++++++++++++++++ include/media/rc-map.h | 1 + 4 files changed, 89 insertions(+) create mode 100644 drivers/media/rc/keymaps/rc-ct-90405.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/rc.yaml b/Documentation/devicetree/bindings/media/rc.yaml index 12d838b05632..d4c541c4b164 100644 --- a/Documentation/devicetree/bindings/media/rc.yaml +++ b/Documentation/devicetree/bindings/media/rc.yaml @@ -45,6 +45,7 @@ properties: - rc-cec - rc-cinergy - rc-cinergy-1400 + - rc-ct-90405 - rc-d680-dmb - rc-delock-61959 - rc-dib0700-nec diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index f609dfe7fd76..5fe5c9e1a46d 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-budget-ci-old.o \ rc-cinergy-1400.o \ rc-cinergy.o \ + rc-ct-90405.o \ rc-d680-dmb.o \ rc-delock-61959.o \ rc-dib0700-nec.o \ diff --git a/drivers/media/rc/keymaps/rc-ct-90405.c b/drivers/media/rc/keymaps/rc-ct-90405.c new file mode 100644 index 000000000000..8914c83c9d9f --- /dev/null +++ b/drivers/media/rc/keymaps/rc-ct-90405.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Toshiba CT-90405 remote controller keytable + * + * Copyright (C) 2021 Alexander Voronov + */ + +#include +#include + +static struct rc_map_table ct_90405[] = { + { 0x4014, KEY_SWITCHVIDEOMODE }, + { 0x4012, KEY_POWER }, + { 0x4044, KEY_TV }, + { 0x40be43, KEY_3D_MODE }, + { 0x400c, KEY_SUBTITLE }, + { 0x4001, KEY_NUMERIC_1 }, + { 0x4002, KEY_NUMERIC_2 }, + { 0x4003, KEY_NUMERIC_3 }, + { 0x4004, KEY_NUMERIC_4 }, + { 0x4005, KEY_NUMERIC_5 }, + { 0x4006, KEY_NUMERIC_6 }, + { 0x4007, KEY_NUMERIC_7 }, + { 0x4008, KEY_NUMERIC_8 }, + { 0x4009, KEY_NUMERIC_9 }, + { 0x4062, KEY_AUDIO_DESC }, + { 0x4000, KEY_NUMERIC_0 }, + { 0x401a, KEY_VOLUMEUP }, + { 0x401e, KEY_VOLUMEDOWN }, + { 0x4016, KEY_INFO }, + { 0x4010, KEY_MUTE }, + { 0x401b, KEY_CHANNELUP }, + { 0x401f, KEY_CHANNELDOWN }, + { 0x40da, KEY_VENDOR }, + { 0x4066, KEY_PLAYER }, + { 0x4017, KEY_TEXT }, + { 0x4047, KEY_LIST }, + { 0x4073, KEY_PAGEUP }, + { 0x4045, KEY_PROGRAM }, + { 0x4043, KEY_EXIT }, + { 0x4074, KEY_PAGEDOWN }, + { 0x4064, KEY_BACK }, + { 0x405b, KEY_MENU }, + { 0x4019, KEY_UP }, + { 0x4040, KEY_RIGHT }, + { 0x401d, KEY_DOWN }, + { 0x4042, KEY_LEFT }, + { 0x4021, KEY_OK }, + { 0x4053, KEY_REWIND }, + { 0x4067, KEY_PLAY }, + { 0x400d, KEY_FASTFORWARD }, + { 0x4054, KEY_PREVIOUS }, + { 0x4068, KEY_STOP }, + { 0x406a, KEY_PAUSE }, + { 0x4015, KEY_NEXT }, + { 0x4048, KEY_RED }, + { 0x4049, KEY_GREEN }, + { 0x404a, KEY_YELLOW }, + { 0x404b, KEY_BLUE }, + { 0x406f, KEY_RECORD } +}; + +static struct rc_map_list ct_90405_map = { + .map = { + .scan = ct_90405, + .size = ARRAY_SIZE(ct_90405), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_CT_90405, + } +}; + +static int __init init_rc_map_ct_90405(void) +{ + return rc_map_register(&ct_90405_map); +} + +static void __exit exit_rc_map_ct_90405(void) +{ + rc_map_unregister(&ct_90405_map); +} + +module_init(init_rc_map_ct_90405) +module_exit(exit_rc_map_ct_90405) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Alexander Voronov "); diff --git a/include/media/rc-map.h b/include/media/rc-map.h index b50443d6fd77..793b54342dff 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -231,6 +231,7 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_CEC "rc-cec" #define RC_MAP_CINERGY "rc-cinergy" #define RC_MAP_CINERGY_1400 "rc-cinergy-1400" +#define RC_MAP_CT_90405 "rc-ct-90405" #define RC_MAP_D680_DMB "rc-d680-dmb" #define RC_MAP_DELOCK_61959 "rc-delock-61959" #define RC_MAP_DIB0700_NEC_TABLE "rc-dib0700-nec" -- cgit v1.3.1 From 4dd0f63b51c24afd2f34afbae2e728cf00c390e6 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 3 Jun 2021 13:49:56 +0200 Subject: media: hevc: Add fields and flags for hevc PPS Add fields and flags as they are defined in 7.4.3.3.1 "General picture parameter set RBSP semantics of the H.265 ITU specification. Signed-off-by: Benjamin Gaignard Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 14 ++++++++++++++ include/media/hevc-ctrls.h | 4 ++++ 2 files changed, 18 insertions(+) (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index 2b5edab55bb4..15468dcfaf08 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -2786,6 +2786,12 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - * - __u8 - ``num_extra_slice_header_bits`` - + * - __u8 + - ``num_ref_idx_l0_default_active_minus1`` + - Specifies the inferred value of num_ref_idx_l0_active_minus1 + * - __u8 + - ``num_ref_idx_l1_default_active_minus1`` + - Specifies the inferred value of num_ref_idx_l1_active_minus1 * - __s8 - ``init_qp_minus26`` - @@ -2896,6 +2902,14 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - * - ``V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT`` - 0x00040000 - + * - ``V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT`` + - 0x00080000 + - Specifies the presence of deblocking filter control syntax elements in + the PPS + * - ``V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING`` + - 0x00100000 + - Specifies that tile column boundaries and likewise tile row boundaries + are distributed uniformly across the picture .. raw:: latex diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h index 36e4c93707ae..3b525fd6e618 100644 --- a/include/media/hevc-ctrls.h +++ b/include/media/hevc-ctrls.h @@ -99,10 +99,14 @@ struct v4l2_ctrl_hevc_sps { #define V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER (1ULL << 16) #define V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT (1ULL << 17) #define V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT (1ULL << 18) +#define V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT (1ULL << 19) +#define V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING (1ULL << 20) struct v4l2_ctrl_hevc_pps { /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture parameter set */ __u8 num_extra_slice_header_bits; + __u8 num_ref_idx_l0_default_active_minus1; + __u8 num_ref_idx_l1_default_active_minus1; __s8 init_qp_minus26; __u8 diff_cu_qp_delta_depth; __s8 pps_cb_qp_offset; -- cgit v1.3.1 From d395a78db9eabd12633b39e05c80e803543b6590 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 3 Jun 2021 13:49:57 +0200 Subject: media: hevc: Add decode params control Add decode params control and the associated structure to group all the information that are needed to decode a reference frame as is described in ITU-T Rec. H.265 section "8.3.2 Decoding process for reference picture set". Adapt Cedrus driver to these changes. Signed-off-by: Benjamin Gaignard Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/ext-ctrls-codec.rst | 94 +++++++++++++++++----- .../userspace-api/media/v4l/vidioc-queryctrl.rst | 6 ++ drivers/media/v4l2-core/v4l2-ctrls-core.c | 21 +++-- drivers/media/v4l2-core/v4l2-ctrls-defs.c | 4 + drivers/staging/media/sunxi/cedrus/cedrus.c | 6 ++ drivers/staging/media/sunxi/cedrus/cedrus.h | 1 + drivers/staging/media/sunxi/cedrus/cedrus_dec.c | 2 + drivers/staging/media/sunxi/cedrus/cedrus_h265.c | 12 +-- include/media/hevc-ctrls.h | 29 ++++--- 9 files changed, 136 insertions(+), 39 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index 15468dcfaf08..8c6e2a11ed95 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -3000,9 +3000,6 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - * - __u8 - ``pic_struct`` - - * - __u8 - - ``num_active_dpb_entries`` - - The number of entries in ``dpb``. * - __u8 - ``ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` - The list of L0 reference elements as indices in the DPB. @@ -3010,22 +3007,8 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - - ``ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` - The list of L1 reference elements as indices in the DPB. * - __u8 - - ``num_rps_poc_st_curr_before`` - - The number of reference pictures in the short-term set that come before - the current frame. - * - __u8 - - ``num_rps_poc_st_curr_after`` - - The number of reference pictures in the short-term set that come after - the current frame. - * - __u8 - - ``num_rps_poc_lt_curr`` - - The number of reference pictures in the long-term set. - * - __u8 - - ``padding[7]`` + - ``padding`` - Applications and drivers must set this to zero. - * - struct :c:type:`v4l2_hevc_dpb_entry` - - ``dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` - - The decoded picture buffer, for meta-data about reference frames. * - struct :c:type:`v4l2_hevc_pred_weight_table` - ``pred_weight_table`` - The prediction weight coefficients for inter-picture prediction. @@ -3281,3 +3264,78 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - encoding the next frame queued after setting this control. This provides a bitmask which consists of bits [0, LTR_COUNT-1]. This is applicable to the H264 and HEVC encoders. + +``V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS (struct)`` + Specifies various decode parameters, especially the references picture order + count (POC) for all the lists (short, long, before, current, after) and the + number of entries for each of them. + These parameters are defined according to :ref:`hevc`. + They are described in section 8.3 "Slice decoding process" of the + specification. + +.. c:type:: v4l2_ctrl_hevc_decode_params + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_ctrl_hevc_decode_params + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __s32 + - ``pic_order_cnt_val`` + - PicOrderCntVal as described in section 8.3.1 "Decoding process + for picture order count" of the specification. + * - __u8 + - ``num_active_dpb_entries`` + - The number of entries in ``dpb``. + * - struct :c:type:`v4l2_hevc_dpb_entry` + - ``dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` + - The decoded picture buffer, for meta-data about reference frames. + * - __u8 + - ``num_poc_st_curr_before`` + - The number of reference pictures in the short-term set that come before + the current frame. + * - __u8 + - ``num_poc_st_curr_after`` + - The number of reference pictures in the short-term set that come after + the current frame. + * - __u8 + - ``num_poc_lt_curr`` + - The number of reference pictures in the long-term set. + * - __u8 + - ``poc_st_curr_before[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` + - PocStCurrBefore as described in section 8.3.2 "Decoding process for reference + picture set. + * - __u8 + - ``poc_st_curr_after[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` + - PocStCurrAfter as described in section 8.3.2 "Decoding process for reference + picture set. + * - __u8 + - ``poc_lt_curr[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` + - PocLtCurr as described in section 8.3.2 "Decoding process for reference + picture set. + * - __u64 + - ``flags`` + - See :ref:`Decode Parameters Flags ` + +.. _hevc_decode_params_flags: + +``Decode Parameters Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC`` + - 0x00000001 + - + * - ``V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC`` + - 0x00000002 + - + * - ``V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR`` + - 0x00000004 + - diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst index 07e54029e1e9..f9ecf6276129 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst @@ -501,6 +501,12 @@ See also the examples in :ref:`control`. - n/a - A struct :c:type:`v4l2_ctrl_vp8_frame`, containing VP8 frame parameters for stateless video decoders. + * - ``V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS`` + - n/a + - n/a + - n/a + - A struct :c:type:`v4l2_ctrl_hevc_decode_params`, containing HEVC + decoding parameters for stateless video decoders. .. raw:: latex diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c index 081439224357..c4b5082849b6 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -337,6 +337,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, struct v4l2_ctrl_hevc_pps *p_hevc_pps; struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params; struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering; + struct v4l2_ctrl_hevc_decode_params *p_hevc_decode_params; struct v4l2_area *area; void *p = ptr.p + idx * ctrl->elem_size; unsigned int i; @@ -616,23 +617,26 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, zero_padding(*p_hevc_pps); break; - case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: - p_hevc_slice_params = p; + case V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS: + p_hevc_decode_params = p; - if (p_hevc_slice_params->num_active_dpb_entries > + if (p_hevc_decode_params->num_active_dpb_entries > V4L2_HEVC_DPB_ENTRIES_NUM_MAX) return -EINVAL; - zero_padding(p_hevc_slice_params->pred_weight_table); - - for (i = 0; i < p_hevc_slice_params->num_active_dpb_entries; + for (i = 0; i < p_hevc_decode_params->num_active_dpb_entries; i++) { struct v4l2_hevc_dpb_entry *dpb_entry = - &p_hevc_slice_params->dpb[i]; + &p_hevc_decode_params->dpb[i]; zero_padding(*dpb_entry); } + break; + case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: + p_hevc_slice_params = p; + + zero_padding(p_hevc_slice_params->pred_weight_table); zero_padding(*p_hevc_slice_params); break; @@ -1236,6 +1240,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params); break; + case V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS: + elem_size = sizeof(struct v4l2_ctrl_hevc_decode_params); + break; case V4L2_CTRL_TYPE_HDR10_CLL_INFO: elem_size = sizeof(struct v4l2_ctrl_hdr10_cll_info); break; diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c index 7963c7b43450..b6344bbf1e00 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c @@ -996,6 +996,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_HEVC_SPS: return "HEVC Sequence Parameter Set"; case V4L2_CID_MPEG_VIDEO_HEVC_PPS: return "HEVC Picture Parameter Set"; case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: return "HEVC Slice Parameters"; + case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS: return "HEVC Decode Parameters"; case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: return "HEVC Decode Mode"; case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: return "HEVC Start Code"; @@ -1487,6 +1488,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: *type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS; break; + case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS: + *type = V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS; + break; case V4L2_CID_UNIT_CELL_SIZE: *type = V4L2_CTRL_TYPE_AREA; *flags |= V4L2_CTRL_FLAG_READ_ONLY; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index fa348c09f844..c0d005dafc6c 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -157,6 +157,12 @@ static const struct cedrus_control cedrus_controls[] = { }, .codec = CEDRUS_CODEC_VP8, }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS, + }, + .codec = CEDRUS_CODEC_H265, + }, }; #define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index bbcdcd0787cf..88afba17b78b 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -77,6 +77,7 @@ struct cedrus_h265_run { const struct v4l2_ctrl_hevc_sps *sps; const struct v4l2_ctrl_hevc_pps *pps; const struct v4l2_ctrl_hevc_slice_params *slice_params; + const struct v4l2_ctrl_hevc_decode_params *decode_params; }; struct cedrus_vp8_run { diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index 97e410d92506..40e8c4123f76 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -70,6 +70,8 @@ void cedrus_device_run(void *priv) V4L2_CID_MPEG_VIDEO_HEVC_PPS); run.h265.slice_params = cedrus_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS); + run.h265.decode_params = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS); break; case V4L2_PIX_FMT_VP8_FRAME: diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c index 10744fab7cea..6821e3d05d34 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c @@ -245,6 +245,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, const struct v4l2_ctrl_hevc_sps *sps; const struct v4l2_ctrl_hevc_pps *pps; const struct v4l2_ctrl_hevc_slice_params *slice_params; + const struct v4l2_ctrl_hevc_decode_params *decode_params; const struct v4l2_hevc_pred_weight_table *pred_weight_table; dma_addr_t src_buf_addr; dma_addr_t src_buf_end_addr; @@ -256,6 +257,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, sps = run->h265.sps; pps = run->h265.pps; slice_params = run->h265.slice_params; + decode_params = run->h265.decode_params; pred_weight_table = &slice_params->pred_weight_table; /* MV column buffer size and allocation. */ @@ -487,7 +489,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, reg = VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_TC_OFFSET_DIV2(slice_params->slice_tc_offset_div2) | VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_BETA_OFFSET_DIV2(slice_params->slice_beta_offset_div2) | - VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_POC_BIGEST_IN_RPS_ST(slice_params->num_rps_poc_st_curr_after == 0) | + VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_POC_BIGEST_IN_RPS_ST(decode_params->num_poc_st_curr_after == 0) | VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CR_QP_OFFSET(slice_params->slice_cr_qp_offset) | VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CB_QP_OFFSET(slice_params->slice_cb_qp_offset) | VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_QP_DELTA(slice_params->slice_qp_delta); @@ -527,8 +529,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, cedrus_write(dev, VE_DEC_H265_NEIGHBOR_INFO_ADDR, reg); /* Write decoded picture buffer in pic list. */ - cedrus_h265_frame_info_write_dpb(ctx, slice_params->dpb, - slice_params->num_active_dpb_entries); + cedrus_h265_frame_info_write_dpb(ctx, decode_params->dpb, + decode_params->num_active_dpb_entries); /* Output frame. */ @@ -545,7 +547,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, /* Reference picture list 0 (for P/B frames). */ if (slice_params->slice_type != V4L2_HEVC_SLICE_TYPE_I) { - cedrus_h265_ref_pic_list_write(dev, slice_params->dpb, + cedrus_h265_ref_pic_list_write(dev, decode_params->dpb, slice_params->ref_idx_l0, slice_params->num_ref_idx_l0_active_minus1 + 1, VE_DEC_H265_SRAM_OFFSET_REF_PIC_LIST0); @@ -564,7 +566,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, /* Reference picture list 1 (for B frames). */ if (slice_params->slice_type == V4L2_HEVC_SLICE_TYPE_B) { - cedrus_h265_ref_pic_list_write(dev, slice_params->dpb, + cedrus_h265_ref_pic_list_write(dev, decode_params->dpb, slice_params->ref_idx_l1, slice_params->num_ref_idx_l1_active_minus1 + 1, VE_DEC_H265_SRAM_OFFSET_REF_PIC_LIST1); diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h index 3b525fd6e618..1b702c3230fb 100644 --- a/include/media/hevc-ctrls.h +++ b/include/media/hevc-ctrls.h @@ -19,6 +19,7 @@ #define V4L2_CID_MPEG_VIDEO_HEVC_SPS (V4L2_CID_CODEC_BASE + 1008) #define V4L2_CID_MPEG_VIDEO_HEVC_PPS (V4L2_CID_CODEC_BASE + 1009) #define V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS (V4L2_CID_CODEC_BASE + 1010) +#define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS (V4L2_CID_CODEC_BASE + 1012) #define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (V4L2_CID_CODEC_BASE + 1015) #define V4L2_CID_MPEG_VIDEO_HEVC_START_CODE (V4L2_CID_CODEC_BASE + 1016) @@ -26,6 +27,7 @@ #define V4L2_CTRL_TYPE_HEVC_SPS 0x0120 #define V4L2_CTRL_TYPE_HEVC_PPS 0x0121 #define V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS 0x0122 +#define V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS 0x0124 enum v4l2_mpeg_video_hevc_decode_mode { V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED, @@ -194,18 +196,10 @@ struct v4l2_ctrl_hevc_slice_params { __u8 pic_struct; /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ - __u8 num_active_dpb_entries; __u8 ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; __u8 ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; - __u8 num_rps_poc_st_curr_before; - __u8 num_rps_poc_st_curr_after; - __u8 num_rps_poc_lt_curr; - - __u8 padding; - - /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ - struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + __u8 padding[5]; /* ISO/IEC 23008-2, ITU-T Rec. H.265: Weighted prediction parameter */ struct v4l2_hevc_pred_weight_table pred_weight_table; @@ -213,4 +207,21 @@ struct v4l2_ctrl_hevc_slice_params { __u64 flags; }; +#define V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC 0x1 +#define V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC 0x2 +#define V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR 0x4 + +struct v4l2_ctrl_hevc_decode_params { + __s32 pic_order_cnt_val; + __u8 num_active_dpb_entries; + struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + __u8 num_poc_st_curr_before; + __u8 num_poc_st_curr_after; + __u8 num_poc_lt_curr; + __u8 poc_st_curr_before[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + __u8 poc_st_curr_after[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + __u8 poc_lt_curr[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + __u64 flags; +}; + #endif -- cgit v1.3.1 From 35f51f6091bcf2cb90d9ac2f41465c415a34632e Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 3 Jun 2021 13:50:01 +0200 Subject: media: uapi: Add a control for HANTRO driver The HEVC HANTRO driver needs to know the number of bits to skip at the beginning of the slice header. That is a hardware specific requirement so create a dedicated control for this purpose. Signed-off-by: Benjamin Gaignard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/drivers/hantro.rst | 19 +++++++++++++++++++ Documentation/userspace-api/media/drivers/index.rst | 1 + include/media/hevc-ctrls.h | 13 +++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 Documentation/userspace-api/media/drivers/hantro.rst (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/drivers/hantro.rst b/Documentation/userspace-api/media/drivers/hantro.rst new file mode 100644 index 000000000000..cd9754b4e005 --- /dev/null +++ b/Documentation/userspace-api/media/drivers/hantro.rst @@ -0,0 +1,19 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Hantro video decoder driver +=========================== + +The Hantro video decoder driver implements the following driver-specific controls: + +``V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP (integer)`` + Specifies to Hantro HEVC video decoder driver the number of data (in bits) to + skip in the slice segment header. + If non-IDR, the bits to be skipped go from syntax element "pic_output_flag" + to before syntax element "slice_temporal_mvp_enabled_flag". + If IDR, the skipped bits are just "pic_output_flag" + (separate_colour_plane_flag is not supported). + +.. note:: + + This control is not yet part of the public kernel API and + it is expected to change. diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst index 1a9038f5f9fa..12e3c512d718 100644 --- a/Documentation/userspace-api/media/drivers/index.rst +++ b/Documentation/userspace-api/media/drivers/index.rst @@ -33,6 +33,7 @@ For more details see the file COPYING in the source distribution of Linux. ccs cx2341x-uapi + hantro imx-uapi max2175 meye-uapi diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h index 1b702c3230fb..53c0038c792b 100644 --- a/include/media/hevc-ctrls.h +++ b/include/media/hevc-ctrls.h @@ -224,4 +224,17 @@ struct v4l2_ctrl_hevc_decode_params { __u64 flags; }; +/* MPEG-class control IDs specific to the Hantro driver as defined by V4L2 */ +#define V4L2_CID_CODEC_HANTRO_BASE (V4L2_CTRL_CLASS_CODEC | 0x1200) +/* + * V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP - + * the number of data (in bits) to skip in the + * slice segment header. + * If non-IDR, the bits to be skipped go from syntax element "pic_output_flag" + * to before syntax element "slice_temporal_mvp_enabled_flag". + * If IDR, the skipped bits are just "pic_output_flag" + * (separate_colour_plane_flag is not supported). + */ +#define V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP (V4L2_CID_CODEC_HANTRO_BASE + 0) + #endif -- cgit v1.3.1 From b1bd5cba3306691c771d558e94baa73e8b0b96b7 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Thu, 3 Jun 2021 13:24:55 +0800 Subject: KVM: X86: MMU: Use the correct inherited permissions to get shadow page When computing the access permissions of a shadow page, use the effective permissions of the walk up to that point, i.e. the logic AND of its parents' permissions. Two guest PxE entries that point at the same table gfn need to be shadowed with different shadow pages if their parents' permissions are different. KVM currently uses the effective permissions of the last non-leaf entry for all non-leaf entries. Because all non-leaf SPTEs have full ("uwx") permissions, and the effective permissions are recorded only in role.access and merged into the leaves, this can lead to incorrect reuse of a shadow page and eventually to a missing guest protection page fault. For example, here is a shared pagetable: pgd[] pud[] pmd[] virtual address pointers /->pmd1(u--)->pte1(uw-)->page1 <- ptr1 (u--) /->pud1(uw-)--->pmd2(uw-)->pte2(uw-)->page2 <- ptr2 (uw-) pgd-| (shared pmd[] as above) \->pud2(u--)--->pmd1(u--)->pte1(uw-)->page1 <- ptr3 (u--) \->pmd2(uw-)->pte2(uw-)->page2 <- ptr4 (u--) pud1 and pud2 point to the same pmd table, so: - ptr1 and ptr3 points to the same page. - ptr2 and ptr4 points to the same page. (pud1 and pud2 here are pud entries, while pmd1 and pmd2 here are pmd entries) - First, the guest reads from ptr1 first and KVM prepares a shadow page table with role.access=u--, from ptr1's pud1 and ptr1's pmd1. "u--" comes from the effective permissions of pgd, pud1 and pmd1, which are stored in pt->access. "u--" is used also to get the pagetable for pud1, instead of "uw-". - Then the guest writes to ptr2 and KVM reuses pud1 which is present. The hypervisor set up a shadow page for ptr2 with pt->access is "uw-" even though the pud1 pmd (because of the incorrect argument to kvm_mmu_get_page in the previous step) has role.access="u--". - Then the guest reads from ptr3. The hypervisor reuses pud1's shadow pmd for pud2, because both use "u--" for their permissions. Thus, the shadow pmd already includes entries for both pmd1 and pmd2. - At last, the guest writes to ptr4. This causes no vmexit or pagefault, because pud1's shadow page structures included an "uw-" page even though its role.access was "u--". Any kind of shared pagetable might have the similar problem when in virtual machine without TDP enabled if the permissions are different from different ancestors. In order to fix the problem, we change pt->access to be an array, and any access in it will not include permissions ANDed from child ptes. The test code is: https://lore.kernel.org/kvm/20210603050537.19605-1-jiangshanlai@gmail.com/ Remember to test it with TDP disabled. The problem had existed long before the commit 41074d07c78b ("KVM: MMU: Fix inherited permissions for emulated guest pte updates"), and it is hard to find which is the culprit. So there is no fixes tag here. Signed-off-by: Lai Jiangshan Message-Id: <20210603052455.21023-1-jiangshanlai@gmail.com> Cc: stable@vger.kernel.org Fixes: cea0f0e7ea54 ("[PATCH] KVM: MMU: Shadow page table caching") Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/mmu.rst | 4 ++-- arch/x86/kvm/mmu/paging_tmpl.h | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/mmu.rst b/Documentation/virt/kvm/mmu.rst index 5bfe28b0728e..20d85daed395 100644 --- a/Documentation/virt/kvm/mmu.rst +++ b/Documentation/virt/kvm/mmu.rst @@ -171,8 +171,8 @@ Shadow pages contain the following information: shadow pages) so role.quadrant takes values in the range 0..3. Each quadrant maps 1GB virtual address space. role.access: - Inherited guest access permissions in the form uwx. Note execute - permission is positive, not negative. + Inherited guest access permissions from the parent ptes in the form uwx. + Note execute permission is positive, not negative. role.invalid: The page is invalid and should not be used. It is a root page that is currently pinned (by a cpu hardware register pointing to it); once it is diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index 70b7e44e3035..823a5919f9fa 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -90,8 +90,8 @@ struct guest_walker { gpa_t pte_gpa[PT_MAX_FULL_LEVELS]; pt_element_t __user *ptep_user[PT_MAX_FULL_LEVELS]; bool pte_writable[PT_MAX_FULL_LEVELS]; - unsigned pt_access; - unsigned pte_access; + unsigned int pt_access[PT_MAX_FULL_LEVELS]; + unsigned int pte_access; gfn_t gfn; struct x86_exception fault; }; @@ -418,13 +418,15 @@ retry_walk: } walker->ptes[walker->level - 1] = pte; + + /* Convert to ACC_*_MASK flags for struct guest_walker. */ + walker->pt_access[walker->level - 1] = FNAME(gpte_access)(pt_access ^ walk_nx_mask); } while (!is_last_gpte(mmu, walker->level, pte)); pte_pkey = FNAME(gpte_pkeys)(vcpu, pte); accessed_dirty = have_ad ? pte_access & PT_GUEST_ACCESSED_MASK : 0; /* Convert to ACC_*_MASK flags for struct guest_walker. */ - walker->pt_access = FNAME(gpte_access)(pt_access ^ walk_nx_mask); walker->pte_access = FNAME(gpte_access)(pte_access ^ walk_nx_mask); errcode = permission_fault(vcpu, mmu, walker->pte_access, pte_pkey, access); if (unlikely(errcode)) @@ -463,7 +465,8 @@ retry_walk: } pgprintk("%s: pte %llx pte_access %x pt_access %x\n", - __func__, (u64)pte, walker->pte_access, walker->pt_access); + __func__, (u64)pte, walker->pte_access, + walker->pt_access[walker->level - 1]); return 1; error: @@ -643,7 +646,7 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gpa_t addr, bool huge_page_disallowed = exec && nx_huge_page_workaround_enabled; struct kvm_mmu_page *sp = NULL; struct kvm_shadow_walk_iterator it; - unsigned direct_access, access = gw->pt_access; + unsigned int direct_access, access; int top_level, level, req_level, ret; gfn_t base_gfn = gw->gfn; @@ -675,6 +678,7 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gpa_t addr, sp = NULL; if (!is_shadow_present_pte(*it.sptep)) { table_gfn = gw->table_gfn[it.level - 2]; + access = gw->pt_access[it.level - 2]; sp = kvm_mmu_get_page(vcpu, table_gfn, addr, it.level-1, false, access); } -- cgit v1.3.1 From 22a558f567ab40b6ea779d0f535d3e32c35c099a Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Tue, 8 Jun 2021 14:31:20 +0200 Subject: doc: Fix warning in Documentation/security/IMA-templates.rst This patch fixes the warning: Documentation/security/IMA-templates.rst:81: WARNING: Inline substitution_reference start-string without end-string. Reported-by: Stephen Rothwell Signed-off-by: Roberto Sassu Signed-off-by: Mimi Zohar --- Documentation/security/IMA-templates.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst index 5adc22f99496..1a91d92950a7 100644 --- a/Documentation/security/IMA-templates.rst +++ b/Documentation/security/IMA-templates.rst @@ -78,7 +78,7 @@ descriptors by adding their identifier to the format string - 'iuid': the inode UID; - 'igid': the inode GID; - 'imode': the inode mode; - - 'xattrnames': a list of xattr names (separated by |), only if the xattr is + - 'xattrnames': a list of xattr names (separated by ``|``), only if the xattr is present; - 'xattrlengths': a list of xattr lengths (u32), only if the xattr is present; - 'xattrvalues': a list of xattr values; -- cgit v1.3.1 From 8929ef8d4dfd53a05913e22561784ece5f6419c7 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Thu, 8 Apr 2021 21:24:36 +0100 Subject: media: dt-bindings: media: renesas,drif: Fix fck definition dt_binding_check reports the below error with the latest schema: Documentation/devicetree/bindings/media/renesas,drif.yaml: properties:clock-names:maxItems: False schema does not allow 1 Documentation/devicetree/bindings/media/renesas,drif.yaml: ignoring, error in schema: properties: clock-names: maxItems This patch fixes the problem. Signed-off-by: Fabrizio Castro Reviewed-by: Laurent Pinchart Reviewed-by: Rob Herring Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20210408202436.3706-1-fabrizio.castro.jz@renesas.com --- Documentation/devicetree/bindings/media/renesas,drif.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/renesas,drif.yaml b/Documentation/devicetree/bindings/media/renesas,drif.yaml index ce505a7c006a..9cd56ff2c316 100644 --- a/Documentation/devicetree/bindings/media/renesas,drif.yaml +++ b/Documentation/devicetree/bindings/media/renesas,drif.yaml @@ -67,9 +67,7 @@ properties: maxItems: 1 clock-names: - maxItems: 1 - items: - - const: fck + const: fck resets: maxItems: 1 -- cgit v1.3.1 From faffc5d8576ed827e2e8e4d2a3771dbb52667381 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Mon, 31 May 2021 22:46:55 +0900 Subject: dt-bindings: hwmon: Fix typo in TI ADS7828 bindings Fix typo in example for DT binding, changed from 'comatible' to 'compatible'. Signed-off-by: Nobuhiro Iwamatsu Link: https://lore.kernel.org/r/20210531134655.720462-1-iwamatsu@nigauri.org Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/ti,ads7828.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/hwmon/ti,ads7828.yaml b/Documentation/devicetree/bindings/hwmon/ti,ads7828.yaml index 33ee575bb09d..926be9a29044 100644 --- a/Documentation/devicetree/bindings/hwmon/ti,ads7828.yaml +++ b/Documentation/devicetree/bindings/hwmon/ti,ads7828.yaml @@ -49,7 +49,7 @@ examples: #size-cells = <0>; adc@48 { - comatible = "ti,ads7828"; + compatible = "ti,ads7828"; reg = <0x48>; vref-supply = <&vref>; ti,differential-input; -- cgit v1.3.1 From 0159bb020ca9a43b17aa9149f1199643c1d49426 Mon Sep 17 00:00:00 2001 From: "Joel Fernandes (Google)" Date: Wed, 2 Jun 2021 21:31:36 -0400 Subject: Documentation: Add usecases, design and interface for core scheduling Now that core scheduling is merged, update the documentation. Co-developed-by: Chris Hyser Signed-off-by: Chris Hyser Co-developed-by: Josh Don Signed-off-by: Josh Don Signed-off-by: Joel Fernandes (Google) Signed-off-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r/20210603013136.370918-1-joel@joelfernandes.org --- .../admin-guide/hw-vuln/core-scheduling.rst | 223 +++++++++++++++++++++ Documentation/admin-guide/hw-vuln/index.rst | 1 + 2 files changed, 224 insertions(+) create mode 100644 Documentation/admin-guide/hw-vuln/core-scheduling.rst (limited to 'Documentation') diff --git a/Documentation/admin-guide/hw-vuln/core-scheduling.rst b/Documentation/admin-guide/hw-vuln/core-scheduling.rst new file mode 100644 index 000000000000..7b410aef9c5c --- /dev/null +++ b/Documentation/admin-guide/hw-vuln/core-scheduling.rst @@ -0,0 +1,223 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=============== +Core Scheduling +=============== +Core scheduling support allows userspace to define groups of tasks that can +share a core. These groups can be specified either for security usecases (one +group of tasks don't trust another), or for performance usecases (some +workloads may benefit from running on the same core as they don't need the same +hardware resources of the shared core, or may prefer different cores if they +do share hardware resource needs). This document only describes the security +usecase. + +Security usecase +---------------- +A cross-HT attack involves the attacker and victim running on different Hyper +Threads of the same core. MDS and L1TF are examples of such attacks. The only +full mitigation of cross-HT attacks is to disable Hyper Threading (HT). Core +scheduling is a scheduler feature that can mitigate some (not all) cross-HT +attacks. It allows HT to be turned on safely by ensuring that only tasks in a +user-designated trusted group can share a core. This increase in core sharing +can also improve performance, however it is not guaranteed that performance +will always improve, though that is seen to be the case with a number of real +world workloads. In theory, core scheduling aims to perform at least as good as +when Hyper Threading is disabled. In practice, this is mostly the case though +not always: as synchronizing scheduling decisions across 2 or more CPUs in a +core involves additional overhead - especially when the system is lightly +loaded. When ``total_threads <= N_CPUS/2``, the extra overhead may cause core +scheduling to perform more poorly compared to SMT-disabled, where N_CPUS is the +total number of CPUs. Please measure the performance of your workloads always. + +Usage +----- +Core scheduling support is enabled via the ``CONFIG_SCHED_CORE`` config option. +Using this feature, userspace defines groups of tasks that can be co-scheduled +on the same core. The core scheduler uses this information to make sure that +tasks that are not in the same group never run simultaneously on a core, while +doing its best to satisfy the system's scheduling requirements. + +Core scheduling can be enabled via the ``PR_SCHED_CORE`` prctl interface. +This interface provides support for the creation of core scheduling groups, as +well as admission and removal of tasks from created groups:: + + #include + + int prctl(int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5); + +option: + ``PR_SCHED_CORE`` + +arg2: + Command for operation, must be one off: + + - ``PR_SCHED_CORE_GET`` -- get core_sched cookie of ``pid``. + - ``PR_SCHED_CORE_CREATE`` -- create a new unique cookie for ``pid``. + - ``PR_SCHED_CORE_SHARE_TO`` -- push core_sched cookie to ``pid``. + - ``PR_SCHED_CORE_SHARE_FROM`` -- pull core_sched cookie from ``pid``. + +arg3: + ``pid`` of the task for which the operation applies. + +arg4: + ``pid_type`` for which the operation applies. It is of type ``enum pid_type``. + For example, if arg4 is ``PIDTYPE_TGID``, then the operation of this command + will be performed for all tasks in the task group of ``pid``. + +arg5: + userspace pointer to an unsigned long for storing the cookie returned by + ``PR_SCHED_CORE_GET`` command. Should be 0 for all other commands. + +In order for a process to push a cookie to, or pull a cookie from a process, it +is required to have the ptrace access mode: `PTRACE_MODE_READ_REALCREDS` to the +process. + +Building hierarchies of tasks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The simplest way to build hierarchies of threads/processes which share a +cookie and thus a core is to rely on the fact that the core-sched cookie is +inherited across forks/clones and execs, thus setting a cookie for the +'initial' script/executable/daemon will place every spawned child in the +same core-sched group. + +Cookie Transferral +~~~~~~~~~~~~~~~~~~ +Transferring a cookie between the current and other tasks is possible using +PR_SCHED_CORE_SHARE_FROM and PR_SCHED_CORE_SHARE_TO to inherit a cookie from a +specified task or a share a cookie with a task. In combination this allows a +simple helper program to pull a cookie from a task in an existing core +scheduling group and share it with already running tasks. + +Design/Implementation +--------------------- +Each task that is tagged is assigned a cookie internally in the kernel. As +mentioned in `Usage`_, tasks with the same cookie value are assumed to trust +each other and share a core. + +The basic idea is that, every schedule event tries to select tasks for all the +siblings of a core such that all the selected tasks running on a core are +trusted (same cookie) at any point in time. Kernel threads are assumed trusted. +The idle task is considered special, as it trusts everything and everything +trusts it. + +During a schedule() event on any sibling of a core, the highest priority task on +the sibling's core is picked and assigned to the sibling calling schedule(), if +the sibling has the task enqueued. For rest of the siblings in the core, +highest priority task with the same cookie is selected if there is one runnable +in their individual run queues. If a task with same cookie is not available, +the idle task is selected. Idle task is globally trusted. + +Once a task has been selected for all the siblings in the core, an IPI is sent to +siblings for whom a new task was selected. Siblings on receiving the IPI will +switch to the new task immediately. If an idle task is selected for a sibling, +then the sibling is considered to be in a `forced idle` state. I.e., it may +have tasks on its on runqueue to run, however it will still have to run idle. +More on this in the next section. + +Forced-idling of hyperthreads +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The scheduler tries its best to find tasks that trust each other such that all +tasks selected to be scheduled are of the highest priority in a core. However, +it is possible that some runqueues had tasks that were incompatible with the +highest priority ones in the core. Favoring security over fairness, one or more +siblings could be forced to select a lower priority task if the highest +priority task is not trusted with respect to the core wide highest priority +task. If a sibling does not have a trusted task to run, it will be forced idle +by the scheduler (idle thread is scheduled to run). + +When the highest priority task is selected to run, a reschedule-IPI is sent to +the sibling to force it into idle. This results in 4 cases which need to be +considered depending on whether a VM or a regular usermode process was running +on either HT:: + + HT1 (attack) HT2 (victim) + A idle -> user space user space -> idle + B idle -> user space guest -> idle + C idle -> guest user space -> idle + D idle -> guest guest -> idle + +Note that for better performance, we do not wait for the destination CPU +(victim) to enter idle mode. This is because the sending of the IPI would bring +the destination CPU immediately into kernel mode from user space, or VMEXIT +in the case of guests. At best, this would only leak some scheduler metadata +which may not be worth protecting. It is also possible that the IPI is received +too late on some architectures, but this has not been observed in the case of +x86. + +Trust model +~~~~~~~~~~~ +Core scheduling maintains trust relationships amongst groups of tasks by +assigning them a tag that is the same cookie value. +When a system with core scheduling boots, all tasks are considered to trust +each other. This is because the core scheduler does not have information about +trust relationships until userspace uses the above mentioned interfaces, to +communicate them. In other words, all tasks have a default cookie value of 0. +and are considered system-wide trusted. The forced-idling of siblings running +cookie-0 tasks is also avoided. + +Once userspace uses the above mentioned interfaces to group sets of tasks, tasks +within such groups are considered to trust each other, but do not trust those +outside. Tasks outside the group also don't trust tasks within. + +Limitations of core-scheduling +------------------------------ +Core scheduling tries to guarantee that only trusted tasks run concurrently on a +core. But there could be small window of time during which untrusted tasks run +concurrently or kernel could be running concurrently with a task not trusted by +kernel. + +IPI processing delays +~~~~~~~~~~~~~~~~~~~~~ +Core scheduling selects only trusted tasks to run together. IPI is used to notify +the siblings to switch to the new task. But there could be hardware delays in +receiving of the IPI on some arch (on x86, this has not been observed). This may +cause an attacker task to start running on a CPU before its siblings receive the +IPI. Even though cache is flushed on entry to user mode, victim tasks on siblings +may populate data in the cache and micro architectural buffers after the attacker +starts to run and this is a possibility for data leak. + +Open cross-HT issues that core scheduling does not solve +-------------------------------------------------------- +1. For MDS +~~~~~~~~~~ +Core scheduling cannot protect against MDS attacks between an HT running in +user mode and another running in kernel mode. Even though both HTs run tasks +which trust each other, kernel memory is still considered untrusted. Such +attacks are possible for any combination of sibling CPU modes (host or guest mode). + +2. For L1TF +~~~~~~~~~~~ +Core scheduling cannot protect against an L1TF guest attacker exploiting a +guest or host victim. This is because the guest attacker can craft invalid +PTEs which are not inverted due to a vulnerable guest kernel. The only +solution is to disable EPT (Extended Page Tables). + +For both MDS and L1TF, if the guest vCPU is configured to not trust each +other (by tagging separately), then the guest to guest attacks would go away. +Or it could be a system admin policy which considers guest to guest attacks as +a guest problem. + +Another approach to resolve these would be to make every untrusted task on the +system to not trust every other untrusted task. While this could reduce +parallelism of the untrusted tasks, it would still solve the above issues while +allowing system processes (trusted tasks) to share a core. + +3. Protecting the kernel (IRQ, syscall, VMEXIT) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Unfortunately, core scheduling does not protect kernel contexts running on +sibling hyperthreads from one another. Prototypes of mitigations have been posted +to LKML to solve this, but it is debatable whether such windows are practically +exploitable, and whether the performance overhead of the prototypes are worth +it (not to mention, the added code complexity). + +Other Use cases +--------------- +The main use case for Core scheduling is mitigating the cross-HT vulnerabilities +with SMT enabled. There are other use cases where this feature could be used: + +- Isolating tasks that needs a whole core: Examples include realtime tasks, tasks + that uses SIMD instructions etc. +- Gang scheduling: Requirements for a group of tasks that needs to be scheduled + together could also be realized using core scheduling. One example is vCPUs of + a VM. diff --git a/Documentation/admin-guide/hw-vuln/index.rst b/Documentation/admin-guide/hw-vuln/index.rst index ca4dbdd9016d..f12cda55538b 100644 --- a/Documentation/admin-guide/hw-vuln/index.rst +++ b/Documentation/admin-guide/hw-vuln/index.rst @@ -15,3 +15,4 @@ are configurable at compile, boot or run time. tsx_async_abort multihit.rst special-register-buffer-data-sampling.rst + core-scheduling.rst -- cgit v1.3.1 From 405e94e9aed2a38bdcd22efe53c36c6cd53185a6 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 13 Sep 2018 10:42:25 +0100 Subject: irqdomain: Kill irq_domain_add_legacy_isa This helper doesn't have a user anymore, let's remove it. Signed-off-by: Marc Zyngier --- Documentation/core-api/irq/irq-domain.rst | 1 - include/linux/irqdomain.h | 11 ----------- 2 files changed, 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/core-api/irq/irq-domain.rst b/Documentation/core-api/irq/irq-domain.rst index 8214e215a8bf..53283b3729a1 100644 --- a/Documentation/core-api/irq/irq-domain.rst +++ b/Documentation/core-api/irq/irq-domain.rst @@ -146,7 +146,6 @@ Legacy irq_domain_add_simple() irq_domain_add_legacy() - irq_domain_add_legacy_isa() irq_domain_create_simple() irq_domain_create_legacy() diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 62a8e3d23829..9f884c948739 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -45,9 +45,6 @@ struct cpumask; struct seq_file; struct irq_affinity_desc; -/* Number of irqs reserved for a legacy isa controller */ -#define NUM_ISA_INTERRUPTS 16 - #define IRQ_DOMAIN_IRQ_SPEC_PARAMS 16 /** @@ -355,14 +352,6 @@ static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_nod { return __irq_domain_add(of_node_to_fwnode(of_node), 0, max_irq, max_irq, ops, host_data); } -static inline struct irq_domain *irq_domain_add_legacy_isa( - struct device_node *of_node, - const struct irq_domain_ops *ops, - void *host_data) -{ - return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops, - host_data); -} static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node, const struct irq_domain_ops *ops, void *host_data) -- cgit v1.3.1 From 0e5a89dbb49920cea22193044bbbfd76a9b0f458 Mon Sep 17 00:00:00 2001 From: Hubert Jasudowicz Date: Wed, 9 Jun 2021 23:51:12 +0200 Subject: doc: Remove references to IBM Calgary The Calgary IOMMU driver has been removed in 90dc392fc445 ("x86: Remove the calgary IOMMU driver") Clean up stale docs that refer to it. Signed-off-by: Hubert Jasudowicz Signed-off-by: Borislav Petkov Link: https://lkml.kernel.org/r/1bd2b57dd1db53df09e520b8170ff61418805de4.1623274832.git.hubert.jasudowicz@gmail.com --- Documentation/x86/x86_64/boot-options.rst | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) (limited to 'Documentation') diff --git a/Documentation/x86/x86_64/boot-options.rst b/Documentation/x86/x86_64/boot-options.rst index 324cefff92e7..5f62b3b86357 100644 --- a/Documentation/x86/x86_64/boot-options.rst +++ b/Documentation/x86/x86_64/boot-options.rst @@ -247,16 +247,11 @@ Multiple x86-64 PCI-DMA mapping implementations exist, for example: Kernel boot message: "PCI-DMA: Using software bounce buffering for IO (SWIOTLB)" - 4. : IBM Calgary hardware IOMMU. Used in IBM - pSeries and xSeries servers. This hardware IOMMU supports DMA address - mapping with memory protection, etc. - Kernel boot message: "PCI-DMA: Using Calgary IOMMU" - :: iommu=[][,noagp][,off][,force][,noforce] [,memaper[=]][,merge][,fullflush][,nomerge] - [,noaperture][,calgary] + [,noaperture] General iommu options: @@ -295,8 +290,6 @@ iommu options only relevant to the AMD GART hardware IOMMU: Don't initialize the AGP driver and use full aperture. panic Always panic when IOMMU overflows. - calgary - Use the Calgary IOMMU if it is available iommu options only relevant to the software bounce buffering (SWIOTLB) IOMMU implementation: @@ -307,28 +300,6 @@ implementation: force Force all IO through the software TLB. -Settings for the IBM Calgary hardware IOMMU currently found in IBM -pSeries and xSeries machines - - calgary=[64k,128k,256k,512k,1M,2M,4M,8M] - Set the size of each PCI slot's translation table when using the - Calgary IOMMU. This is the size of the translation table itself - in main memory. The smallest table, 64k, covers an IO space of - 32MB; the largest, 8MB table, can cover an IO space of 4GB. - Normally the kernel will make the right choice by itself. - calgary=[translate_empty_slots] - Enable translation even on slots that have no devices attached to - them, in case a device will be hotplugged in the future. - calgary=[disable=] - Disable translation on a given PHB. For - example, the built-in graphics adapter resides on the first bridge - (PCI bus number 0); if translation (isolation) is enabled on this - bridge, X servers that access the hardware directly from user - space might stop working. Use this option if you have devices that - are accessed from userspace directly on some PCI host bridge. - panic - Always panic when IOMMU overflows - Miscellaneous ============= -- cgit v1.3.1 From 124d77c22c6183c76aa4bb71c29ee0c842562a5f Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 1 Jun 2021 15:11:28 +0000 Subject: dt-bindings: crypto: Add documentation for sl3516-ce This patch adds documentation for Device-Tree bindings for the SL3516-ce cryptographic offloader driver. Reviewed-by: Linus Walleij Reviewed-by: Rob Herring Signed-off-by: Corentin Labbe Signed-off-by: Herbert Xu --- .../bindings/crypto/cortina,sl3516-crypto.yaml | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/crypto/cortina,sl3516-crypto.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/crypto/cortina,sl3516-crypto.yaml b/Documentation/devicetree/bindings/crypto/cortina,sl3516-crypto.yaml new file mode 100644 index 000000000000..b633b8d0e6f0 --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/cortina,sl3516-crypto.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/crypto/cortina,sl3516-crypto.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SL3516 cryptographic offloader driver + +maintainers: + - Corentin Labbe + +properties: + compatible: + enum: + - cortina,sl3516-crypto + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + - resets + +additionalProperties: false + +examples: + - | + #include + #include + #include + + crypto@62000000 { + compatible = "cortina,sl3516-crypto"; + reg = <0x62000000 0x10000>; + interrupts = <7 IRQ_TYPE_EDGE_RISING>; + resets = <&syscon GEMINI_RESET_SECURITY>; + clocks = <&syscon GEMINI_CLK_GATE_SECURITY>; + }; -- cgit v1.3.1 From 4e08a559a18c1b6424e56859c74adb4b29c17318 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 9 Jun 2021 16:51:08 +0100 Subject: dt-bindings: interrupt-controller: arm,gic-v3: Describe GICv3 optional properties Describe the optional GICv3 properties: - clocks - clock-names - power-domains - resets Signed-off-by: Lad Prabhakar Reviewed-by: Biju Das Reviewed-by: Geert Uytterhoeven Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20210609155108.16590-1-prabhakar.mahadev-lad.rj@bp.renesas.com --- .../bindings/interrupt-controller/arm,gic-v3.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml index 1ecd1831cf02..c84f9fe7f254 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml @@ -145,6 +145,19 @@ properties: required: - affinity + clocks: + maxItems: 1 + + clock-names: + items: + - const: aclk + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + dependencies: mbi-ranges: [ msi-controller ] msi-controller: [ mbi-ranges ] -- cgit v1.3.1 From 154ae8bb3c830f0a568a5194ce7e631aa6bcfe8b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 2 Jun 2021 20:18:02 +0200 Subject: cpuidle: teo: Use kerneldoc documentation in admin-guide There are two descriptions of the TEO (Timer Events Oriented) cpuidle governor in the kernel source tree, one in the C file containing its code and one in cpuidle.rst which is part of admin-guide. Instead of trying to keep them both in sync and in order to reduce text duplication, include the governor description from the C file directly into cpuidle.rst. Signed-off-by: Rafael J. Wysocki --- Documentation/admin-guide/pm/cpuidle.rst | 77 +------------------------------- drivers/cpuidle/governors/teo.c | 12 +++-- 2 files changed, 10 insertions(+), 79 deletions(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/pm/cpuidle.rst b/Documentation/admin-guide/pm/cpuidle.rst index 10fde58d0869..aec2cd2aaea7 100644 --- a/Documentation/admin-guide/pm/cpuidle.rst +++ b/Documentation/admin-guide/pm/cpuidle.rst @@ -347,81 +347,8 @@ for tickless systems. It follows the same basic strategy as the ``menu`` `one `_: it always tries to find the deepest idle state suitable for the given conditions. However, it applies a different approach to that problem. -First, it does not use sleep length correction factors, but instead it attempts -to correlate the observed idle duration values with the available idle states -and use that information to pick up the idle state that is most likely to -"match" the upcoming CPU idle interval. Second, it does not take the tasks -that were running on the given CPU in the past and are waiting on some I/O -operations to complete now at all (there is no guarantee that they will run on -the same CPU when they become runnable again) and the pattern detection code in -it avoids taking timer wakeups into account. It also only uses idle duration -values less than the current time till the closest timer (with the scheduler -tick excluded) for that purpose. - -Like in the ``menu`` governor `case `_, the first step is to obtain -the *sleep length*, which is the time until the closest timer event with the -assumption that the scheduler tick will be stopped (that also is the upper bound -on the time until the next CPU wakeup). That value is then used to preselect an -idle state on the basis of three metrics maintained for each idle state provided -by the ``CPUIdle`` driver: ``hits``, ``misses`` and ``early_hits``. - -The ``hits`` and ``misses`` metrics measure the likelihood that a given idle -state will "match" the observed (post-wakeup) idle duration if it "matches" the -sleep length. They both are subject to decay (after a CPU wakeup) every time -the target residency of the idle state corresponding to them is less than or -equal to the sleep length and the target residency of the next idle state is -greater than the sleep length (that is, when the idle state corresponding to -them "matches" the sleep length). The ``hits`` metric is increased if the -former condition is satisfied and the target residency of the given idle state -is less than or equal to the observed idle duration and the target residency of -the next idle state is greater than the observed idle duration at the same time -(that is, it is increased when the given idle state "matches" both the sleep -length and the observed idle duration). In turn, the ``misses`` metric is -increased when the given idle state "matches" the sleep length only and the -observed idle duration is too short for its target residency. - -The ``early_hits`` metric measures the likelihood that a given idle state will -"match" the observed (post-wakeup) idle duration if it does not "match" the -sleep length. It is subject to decay on every CPU wakeup and it is increased -when the idle state corresponding to it "matches" the observed (post-wakeup) -idle duration and the target residency of the next idle state is less than or -equal to the sleep length (i.e. the idle state "matching" the sleep length is -deeper than the given one). - -The governor walks the list of idle states provided by the ``CPUIdle`` driver -and finds the last (deepest) one with the target residency less than or equal -to the sleep length. Then, the ``hits`` and ``misses`` metrics of that idle -state are compared with each other and it is preselected if the ``hits`` one is -greater (which means that that idle state is likely to "match" the observed idle -duration after CPU wakeup). If the ``misses`` one is greater, the governor -preselects the shallower idle state with the maximum ``early_hits`` metric -(or if there are multiple shallower idle states with equal ``early_hits`` -metric which also is the maximum, the shallowest of them will be preselected). -[If there is a wakeup latency constraint coming from the `PM QoS framework -`_ which is hit before reaching the deepest idle state with the -target residency within the sleep length, the deepest idle state with the exit -latency within the constraint is preselected without consulting the ``hits``, -``misses`` and ``early_hits`` metrics.] - -Next, the governor takes several idle duration values observed most recently -into consideration and if at least a half of them are greater than or equal to -the target residency of the preselected idle state, that idle state becomes the -final candidate to ask for. Otherwise, the average of the most recent idle -duration values below the target residency of the preselected idle state is -computed and the governor walks the idle states shallower than the preselected -one and finds the deepest of them with the target residency within that average. -That idle state is then taken as the final candidate to ask for. - -Still, at this point the governor may need to refine the idle state selection if -it has not decided to `stop the scheduler tick `_. That -generally happens if the target residency of the idle state selected so far is -less than the tick period and the tick has not been stopped already (in a -previous iteration of the idle loop). Then, like in the ``menu`` governor -`case `_, the sleep length used in the previous computations may not -reflect the real time until the closest timer event and if it really is greater -than that time, a shallower state with a suitable target residency may need to -be selected. - +.. kernel-doc:: drivers/cpuidle/governors/teo.c + :doc: teo-description .. _idle-states-representation: diff --git a/drivers/cpuidle/governors/teo.c b/drivers/cpuidle/governors/teo.c index 7c2024f91fd7..1e0b2f828abb 100644 --- a/drivers/cpuidle/governors/teo.c +++ b/drivers/cpuidle/governors/teo.c @@ -4,6 +4,10 @@ * * Copyright (C) 2018 - 2021 Intel Corporation * Author: Rafael J. Wysocki + */ + +/** + * DOC: teo-description * * The idea of this governor is based on the observation that on many systems * timer events are two or more orders of magnitude more frequent than any @@ -28,7 +32,7 @@ * * The computations carried out by this governor are based on using bins whose * boundaries are aligned with the target residency parameter values of the CPU - * idle states provided by the cpuidle driver in the ascending order. That is, + * idle states provided by the %CPUIdle driver in the ascending order. That is, * the first bin spans from 0 up to, but not including, the target residency of * the second idle state (idle state 1), the second bin spans from the target * residency of idle state 1 up to, but not including, the target residency of @@ -51,8 +55,8 @@ * situations are referred to as "intercepts" below). * * In addition to the metrics described above, the governor counts recent - * intercepts (that is, intercepts that have occurred during the last NR_RECENT - * invocations of it for the given CPU) for each bin. + * intercepts (that is, intercepts that have occurred during the last + * %NR_RECENT invocations of it for the given CPU) for each bin. * * In order to select an idle state for a CPU, the governor takes the following * steps (modulo the possible latency constraint that must be taken into account @@ -76,7 +80,7 @@ * shallower than the candidate one. * * 2. If the second sum is greater than the first one or the third sum is - * greater than NR_RECENT / 2, the CPU is likely to wake up early, so look + * greater than %NR_RECENT / 2, the CPU is likely to wake up early, so look * for an alternative idle state to select. * * - Traverse the idle states shallower than the candidate one in the -- cgit v1.3.1 From 4ec4f059088b48585c337328e05fa930c64d1ba8 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 9 Jun 2021 12:06:10 +0200 Subject: PM: runtime: Clarify documentation when callbacks are unassigned Recent changes to the PM core allows ->runtime_suspend|resume callbacks to be unassigned. In the earlier behaviour the PM core would return -ENOSYS, when trying to runtime resume a device, for example. Let's update the documentation to clarify this. Signed-off-by: Ulf Hansson Acked-by: Alan Stern Signed-off-by: Rafael J. Wysocki --- Documentation/power/runtime_pm.rst | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'Documentation') diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst index b48cac5f9048..d6bf84f061f4 100644 --- a/Documentation/power/runtime_pm.rst +++ b/Documentation/power/runtime_pm.rst @@ -831,6 +831,15 @@ or driver about runtime power changes. Instead, the driver for the device's parent must take responsibility for telling the device's driver when the parent's power state changes. +Note that, in some cases it may not be desirable for subsystems/drivers to call +pm_runtime_no_callbacks() for their devices. This could be because a subset of +the runtime PM callbacks needs to be implemented, a platform dependent PM +domain could get attached to the device or that the device is power managed +through a supplier device link. For these reasons and to avoid boilerplate code +in subsystems/drivers, the PM core allows runtime PM callbacks to be +unassigned. More precisely, if a callback pointer is NULL, the PM core will act +as though there was a callback and it returned 0. + 9. Autosuspend, or automatically-delayed suspends ================================================= -- cgit v1.3.1 From a9edc03f13dbd51095b38ef0371d24e7ec7ae693 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 10 Jun 2021 20:00:44 -0700 Subject: docs: fix a cross-ref Commit acda97acb2e98c9 changes dax.txt to dax.rst. Fix the references accordingly. Cc: Igor Matheus Andrade Torrente Signed-off-by: Kir Kolyshkin Link: https://lore.kernel.org/r/20210611030044.1982911-4-kolyshkin@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/admin-guide/ext4.rst | 2 +- Documentation/filesystems/ext2.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/ext4.rst b/Documentation/admin-guide/ext4.rst index d2795ca6821e..4c559e08d11e 100644 --- a/Documentation/admin-guide/ext4.rst +++ b/Documentation/admin-guide/ext4.rst @@ -392,7 +392,7 @@ When mounting an ext4 filesystem, the following option are accepted: dax Use direct access (no page cache). See - Documentation/filesystems/dax.txt. Note that this option is + Documentation/filesystems/dax.rst. Note that this option is incompatible with data=journal. inlinecrypt diff --git a/Documentation/filesystems/ext2.rst b/Documentation/filesystems/ext2.rst index c2fce22cfd03..154101cf0e4f 100644 --- a/Documentation/filesystems/ext2.rst +++ b/Documentation/filesystems/ext2.rst @@ -25,7 +25,7 @@ check=none, nocheck (*) Don't do extra checking of bitmaps on mount (check=normal and check=strict options removed) dax Use direct access (no page cache). See - Documentation/filesystems/dax.txt. + Documentation/filesystems/dax.rst. debug Extra debugging information is sent to the kernel syslog. Useful for developers. -- cgit v1.3.1 From 6a45d70cda6a6e3fa3cffe37d47495fb3c4a4bfa Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 28 Apr 2021 18:05:00 -0500 Subject: dt-bindings: mmc: sdhci-am654: Remove duplicate ti,j721e-sdhci-4bit The commit 7c7905df68c5 ("dt-bindings: mmc: sdhci-am654: fix compatible for j7200") switched the compatible property from a regular enum to an more appropriate combinatorial oneOf convention, and in the process has introduced a duplicate ti,j721e-sdhci-4bit. This generated the following warning on J721E boards that use the ti,j721e-sdhci-4bit for two nodes: "mmc@4fb0000: compatible: More than one condition true in oneOf schema" "mmc@4f98000: compatible: More than one condition true in oneOf schema" Remove the duplicate to fix this. Fixes: 7c7905df68c5 ("dt-bindings: mmc: sdhci-am654: fix compatible for j7200") Signed-off-by: Suman Anna Link: https://lore.kernel.org/r/20210428230500.19214-1-s-anna@ti.com Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/sdhci-am654.yaml | 1 - 1 file changed, 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/sdhci-am654.yaml b/Documentation/devicetree/bindings/mmc/sdhci-am654.yaml index 3a79e39253d2..29399e88ac53 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-am654.yaml +++ b/Documentation/devicetree/bindings/mmc/sdhci-am654.yaml @@ -19,7 +19,6 @@ properties: - const: ti,am654-sdhci-5.1 - const: ti,j721e-sdhci-8bit - const: ti,j721e-sdhci-4bit - - const: ti,j721e-sdhci-4bit - const: ti,am64-sdhci-8bit - const: ti,am64-sdhci-4bit - items: -- cgit v1.3.1 From 873e90883069a4e32bc6ecd150b0107f9aa542b8 Mon Sep 17 00:00:00 2001 From: Liang Chen Date: Thu, 29 Apr 2021 16:11:44 +0800 Subject: dt-bindings: mmc: rockchip-dw-mshc: add description for rk3568 Add "rockchip,rk3568-dw-mshc", "rockchip,rk3288-dw-mshc" compatibles for mmc nodes on a rk3568 platform to rockchip-dw-mshc.yaml. Let's also take to opportunity to clean up some old redundant comments around previous compatibles. Signed-off-by: Liang Chen Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210429081151.17558-4-cl@rock-chips.com Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml index 3762f1c8de96..eaa3b0ef24f6 100644 --- a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml +++ b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml @@ -29,21 +29,14 @@ properties: - const: rockchip,rk3288-dw-mshc - items: - enum: - # for Rockchip PX30 - rockchip,px30-dw-mshc - # for Rockchip RK3036 - rockchip,rk3036-dw-mshc - # for Rockchip RK322x - rockchip,rk3228-dw-mshc - # for Rockchip RK3308 - rockchip,rk3308-dw-mshc - # for Rockchip RK3328 - rockchip,rk3328-dw-mshc - # for Rockchip RK3368 - rockchip,rk3368-dw-mshc - # for Rockchip RK3399 - rockchip,rk3399-dw-mshc - # for Rockchip RV1108 + - rockchip,rk3568-dw-mshc - rockchip,rv1108-dw-mshc - const: rockchip,rk3288-dw-mshc -- cgit v1.3.1 From 110a8688c6cd11e81a1805d5dc24a7a6b5d86a18 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 10 May 2021 14:13:21 +0200 Subject: dt-bindings: mmc: renesas,mmcif: Convert to json-schema Convert the Renesas Multi Media Card Interface (MMCIF) Device Tree binding documentation to json-schema. Document missing properties. Update the example to match reality. Signed-off-by: Geert Uytterhoeven Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/04b97315fed0f4f512356b68f9f5bb6ed7adc41f.1620648698.git.geert+renesas@glider.be Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/renesas,mmcif.txt | 53 -------- .../devicetree/bindings/mmc/renesas,mmcif.yaml | 135 +++++++++++++++++++++ 2 files changed, 135 insertions(+), 53 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mmc/renesas,mmcif.txt create mode 100644 Documentation/devicetree/bindings/mmc/renesas,mmcif.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt b/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt deleted file mode 100644 index 291532ac0446..000000000000 --- a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt +++ /dev/null @@ -1,53 +0,0 @@ -* Renesas Multi Media Card Interface (MMCIF) Controller - -This file documents differences between the core properties in mmc.txt -and the properties used by the MMCIF device. - - -Required properties: - -- compatible: should be "renesas,mmcif-", "renesas,sh-mmcif" as a - fallback. Examples with are: - - "renesas,mmcif-r7s72100" for the MMCIF found in r7s72100 SoCs - - "renesas,mmcif-r8a73a4" for the MMCIF found in r8a73a4 SoCs - - "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs - - "renesas,mmcif-r8a7742" for the MMCIF found in r8a7742 SoCs - - "renesas,mmcif-r8a7743" for the MMCIF found in r8a7743 SoCs - - "renesas,mmcif-r8a7744" for the MMCIF found in r8a7744 SoCs - - "renesas,mmcif-r8a7745" for the MMCIF found in r8a7745 SoCs - - "renesas,mmcif-r8a7778" for the MMCIF found in r8a7778 SoCs - - "renesas,mmcif-r8a7790" for the MMCIF found in r8a7790 SoCs - - "renesas,mmcif-r8a7791" for the MMCIF found in r8a7791 SoCs - - "renesas,mmcif-r8a7793" for the MMCIF found in r8a7793 SoCs - - "renesas,mmcif-r8a7794" for the MMCIF found in r8a7794 SoCs - - "renesas,mmcif-sh73a0" for the MMCIF found in sh73a0 SoCs - -- interrupts: Some SoCs have only 1 shared interrupt, while others have either - 2 or 3 individual interrupts (error, int, card detect). Below is the number - of interrupts for each SoC: - 1: r8a73a4, r8a7742, r8a7743, r8a7744, r8a7745, r8a7778, r8a7790, r8a7791, - r8a7793, r8a7794 - 2: r8a7740, sh73a0 - 3: r7s72100 - -- clocks: reference to the functional clock - -- dmas: reference to the DMA channels, one per channel name listed in the - dma-names property. -- dma-names: must contain "tx" for the transmit DMA channel and "rx" for the - receive DMA channel. -- max-frequency: Maximum operating clock frequency, driver uses default clock - frequency if it is not set. - - -Example: R8A7790 (R-Car H2) MMCIF0 - - mmcif0: mmc@ee200000 { - compatible = "renesas,mmcif-r8a7790", "renesas,sh-mmcif"; - reg = <0 0xee200000 0 0x80>; - interrupts = <0 169 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&mstp3_clks R8A7790_CLK_MMCIF0>; - dmas = <&dmac0 0xd1>, <&dmac0 0xd2>; - dma-names = "tx", "rx"; - max-frequency = <97500000>; - }; diff --git a/Documentation/devicetree/bindings/mmc/renesas,mmcif.yaml b/Documentation/devicetree/bindings/mmc/renesas,mmcif.yaml new file mode 100644 index 000000000000..c36ba561c387 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/renesas,mmcif.yaml @@ -0,0 +1,135 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mmc/renesas,mmcif.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas Multi Media Card Interface (MMCIF) Controller + +maintainers: + - Wolfram Sang + +allOf: + - $ref: "mmc-controller.yaml" + +properties: + compatible: + items: + - enum: + - renesas,mmcif-r7s72100 # RZ/A1H + - renesas,mmcif-r8a73a4 # R-Mobile APE6 + - renesas,mmcif-r8a7740 # R-Mobile A1 + - renesas,mmcif-r8a7742 # RZ/G1H + - renesas,mmcif-r8a7743 # RZ/G1M + - renesas,mmcif-r8a7744 # RZ/G1N + - renesas,mmcif-r8a7745 # RZ/G1E + - renesas,mmcif-r8a7778 # R-Car M1A + - renesas,mmcif-r8a7790 # R-Car H2 + - renesas,mmcif-r8a7791 # R-Car M2-W + - renesas,mmcif-r8a7793 # R-Car M2-N + - renesas,mmcif-r8a7794 # R-Car E2 + - renesas,mmcif-sh73a0 # SH-Mobile AG5 + - const: renesas,sh-mmcif + + reg: + maxItems: 1 + + interrupts: true + + clocks: + maxItems: 1 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + dmas: + minItems: 2 + maxItems: 4 + description: + Must contain a list of pairs of references to DMA specifiers, one for + transmission, and one for reception. + + dma-names: + minItems: 2 + maxItems: 4 + items: + enum: + - tx + - rx + + max-frequency: true + +required: + - compatible + - reg + - interrupts + - clocks + - power-domains + +if: + properties: + compatible: + contains: + const: renesas,mmcif-r7s72100 +then: + properties: + interrupts: + items: + - description: Error interrupt + - description: Normal operation interrupt + - description: Card detection interrupt +else: + if: + properties: + compatible: + contains: + enum: + - renesas,mmcif-r8a7740 + - renesas,mmcif-sh73a0 + then: + properties: + interrupts: + items: + - description: Error interrupt + - description: Normal operation interrupt + else: + if: + properties: + compatible: + contains: + enum: + - renesas,mmcif-r8a73a4 + - renesas,mmcif-r8a7778 + then: + properties: + interrupts: + maxItems: 1 + else: + properties: + interrupts: + maxItems: 1 + required: + - resets + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + + mmcif0: mmc@ee200000 { + compatible = "renesas,mmcif-r8a7790", "renesas,sh-mmcif"; + reg = <0xee200000 0x80>; + interrupts = ; + clocks = <&cpg CPG_MOD 315>; + power-domains = <&sysc R8A7790_PD_ALWAYS_ON>; + resets = <&cpg 315>; + dmas = <&dmac0 0xd1>, <&dmac0 0xd2>, <&dmac1 0xd1>, <&dmac1 0xd2>; + dma-names = "tx", "rx", "tx", "rx"; + max-frequency = <97500000>; + }; -- cgit v1.3.1 From 4d895de3505f7eb9734f679a340c976f8949ab43 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 10 May 2021 21:03:58 +0200 Subject: dt-bindings: mmc: add no-mmc-hs400 flag HS400 requires a data strobe line in addition to the usual MMC signal lines. If a board design neglects to wire up this signal, HS400 mode is not available, even if both the controller and the eMMC are claiming to support this mode. Add a DT flag to allow boards to disable the HS400 support in this case. Signed-off-by: Lucas Stach Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210510190400.105162-1-l.stach@pengutronix.de Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/mmc-controller.yaml | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/mmc-controller.yaml b/Documentation/devicetree/bindings/mmc/mmc-controller.yaml index e141330c1114..ac80d09df3a9 100644 --- a/Documentation/devicetree/bindings/mmc/mmc-controller.yaml +++ b/Documentation/devicetree/bindings/mmc/mmc-controller.yaml @@ -220,6 +220,11 @@ properties: description: eMMC HS400 enhanced strobe mode is supported + no-mmc-hs400: + $ref: /schemas/types.yaml#/definitions/flag + description: + All eMMC HS400 modes are not supported. + dsr: description: Value the card Driver Stage Register (DSR) should be programmed -- cgit v1.3.1 From 8931acce6b771dfe01d23e6d36e0b09f717c90c2 Mon Sep 17 00:00:00 2001 From: Andreas Färber Date: Mon, 17 May 2021 01:05:48 +0200 Subject: dt-bindings: mmc: rockchip-dw-mshc: Add Rockchip RK1808 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a compatible string for Rockchip RK1808 SoC. Signed-off-by: Andreas Färber Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210516230551.12469-7-afaerber@suse.de Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml index eaa3b0ef24f6..54fb59820d2b 100644 --- a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml +++ b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml @@ -30,6 +30,7 @@ properties: - items: - enum: - rockchip,px30-dw-mshc + - rockchip,rk1808-dw-mshc - rockchip,rk3036-dw-mshc - rockchip,rk3228-dw-mshc - rockchip,rk3308-dw-mshc -- cgit v1.3.1 From 1e9daaf616a2f053eb80e20a84b47ebf2d5e20d3 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 19 May 2021 10:37:12 -0500 Subject: dt-bindings: mmc: Clean-up examples to match documented bindings The "sdhci" compatible is not documented though used as a fallback in a few cases. It is also not supported by a Linux driver. Just remove the example as part of ridding examples of undocumented bindings. The "brcm,bcm43xx-fmac" compatible is also not documented. Update the example to use one of the correct ones, "brcm,bcm4329-fmac", instead and use a device class based nodename. Cc: Ulf Hansson Cc: linux-mmc@vger.kernel.org Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20210519153712.3146025-1-robh@kernel.org Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/mmc-controller.yaml | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/mmc-controller.yaml b/Documentation/devicetree/bindings/mmc/mmc-controller.yaml index ac80d09df3a9..25ac8e200970 100644 --- a/Documentation/devicetree/bindings/mmc/mmc-controller.yaml +++ b/Documentation/devicetree/bindings/mmc/mmc-controller.yaml @@ -362,22 +362,6 @@ dependencies: additionalProperties: true examples: - - | - mmc@ab000000 { - compatible = "sdhci"; - reg = <0xab000000 0x200>; - interrupts = <23>; - bus-width = <4>; - cd-gpios = <&gpio 69 0>; - cd-inverted; - wp-gpios = <&gpio 70 0>; - max-frequency = <50000000>; - keep-power-in-suspend; - wakeup-source; - mmc-pwrseq = <&sdhci0_pwrseq>; - clk-phase-sd-hs = <63>, <72>; - }; - - | mmc3: mmc@1c12000 { #address-cells = <1>; @@ -390,9 +374,9 @@ examples: non-removable; mmc-pwrseq = <&sdhci0_pwrseq>; - brcmf: bcrmf@1 { + brcmf: wifi@1 { reg = <1>; - compatible = "brcm,bcm43xx-fmac"; + compatible = "brcm,bcm4329-fmac"; interrupt-parent = <&pio>; interrupts = <10 8>; interrupt-names = "host-wake"; -- cgit v1.3.1 From 3160e025361fad1085e527a898c5dcfedf7e796d Mon Sep 17 00:00:00 2001 From: "周琰杰 (Zhou Yanjie)" Date: Thu, 10 Jun 2021 20:58:49 +0800 Subject: dt-bindings: mmc: JZ4740: Add bindings for JZ4775 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a compatible to the mmc DT bindings for the JZ4775 SoC from Ingenic. Signed-off-by: 周琰杰 (Zhou Yanjie) Acked-by: Paul Cercueil Link: https://lore.kernel.org/r/1623329930-14387-2-git-send-email-zhouyanjie@wanyeetech.com Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/ingenic,mmc.yaml | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/ingenic,mmc.yaml b/Documentation/devicetree/bindings/mmc/ingenic,mmc.yaml index 04ba8b7fc054..546480f41141 100644 --- a/Documentation/devicetree/bindings/mmc/ingenic,mmc.yaml +++ b/Documentation/devicetree/bindings/mmc/ingenic,mmc.yaml @@ -19,6 +19,7 @@ properties: - ingenic,jz4740-mmc - ingenic,jz4725b-mmc - ingenic,jz4760-mmc + - ingenic,jz4775-mmc - ingenic,jz4780-mmc - ingenic,x1000-mmc - items: -- cgit v1.3.1 From d7c176e9b5329b4a490b3d8ea49564fc9ff11071 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Wed, 9 Jun 2021 19:50:58 +0000 Subject: docs: printk-formats: update size-casting examples Since commit 72deb455b5ec ("block: remove CONFIG_LBDAF") sector_t and blkcnt_t types are no longer variable in size, making them unsuitable examples for casting to the largest possible type. This patch replaces such examples with cycles_t and blk_status_t types, whose sizes depend on architecture and config options respectively. Signed-off-by: Carlos Llamas Link: https://lore.kernel.org/r/20210609195058.3518943-1-cmllamas@google.com Signed-off-by: Jonathan Corbet --- Documentation/core-api/printk-formats.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst index f063a384c7c8..385c0cc52f1f 100644 --- a/Documentation/core-api/printk-formats.rst +++ b/Documentation/core-api/printk-formats.rst @@ -37,14 +37,13 @@ Integer types u64 %llu or %llx -If is dependent on a config option for its size (e.g., sector_t, -blkcnt_t) or is architecture-dependent for its size (e.g., tcflag_t), use a -format specifier of its largest possible type and explicitly cast to it. +If is architecture-dependent for its size (e.g., cycles_t, tcflag_t) or +is dependent on a config option for its size (e.g., blk_status_t), use a format +specifier of its largest possible type and explicitly cast to it. Example:: - printk("test: sector number/total blocks: %llu/%llu\n", - (unsigned long long)sector, (unsigned long long)blockcount); + printk("test: latency: %llu cycles\n", (unsigned long long)time); Reminder: sizeof() returns type size_t. -- cgit v1.3.1 From b1f4c363666c31f289b26bfc7c38378f0db79b55 Mon Sep 17 00:00:00 2001 From: Baoquan He Date: Wed, 9 Jun 2021 16:32:18 +0800 Subject: Documentation: kdump: update kdump guide Some parts of the guide are aged, hence need be updated. 1) The backup area of the 1st 640K on X86_64 has been removed by below commits, update the description accordingly. commit 7c321eb2b843 ("x86/kdump: Remove the backup region handling") commit 6f599d84231f ("x86/kdump: Always reserve the low 1M when the crashkernel option is specified") 2) Sort out the descripiton of "crashkernel syntax" part. 3) And some other minor cleanups. Signed-off-by: Baoquan He Acked-by: Dave Young Link: https://lore.kernel.org/r/20210609083218.GB591017@MiWiFi-R3L-srv [jc: added blank line to fix added build warning] Signed-off-by: Jonathan Corbet --- Documentation/admin-guide/kdump/kdump.rst | 170 +++++++++++++++++++----------- 1 file changed, 109 insertions(+), 61 deletions(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/kdump/kdump.rst b/Documentation/admin-guide/kdump/kdump.rst index 75a9dd98e76e..cb30ca3df27c 100644 --- a/Documentation/admin-guide/kdump/kdump.rst +++ b/Documentation/admin-guide/kdump/kdump.rst @@ -2,7 +2,7 @@ Documentation for Kdump - The kexec-based Crash Dumping Solution ================================================================ -This document includes overview, setup and installation, and analysis +This document includes overview, setup, installation, and analysis information. Overview @@ -13,9 +13,9 @@ dump of the system kernel's memory needs to be taken (for example, when the system panics). The system kernel's memory image is preserved across the reboot and is accessible to the dump-capture kernel. -You can use common commands, such as cp and scp, to copy the -memory image to a dump file on the local disk, or across the network to -a remote system. +You can use common commands, such as cp, scp or makedumpfile to copy +the memory image to a dump file on the local disk, or across the network +to a remote system. Kdump and kexec are currently supported on the x86, x86_64, ppc64, ia64, s390x, arm and arm64 architectures. @@ -26,13 +26,15 @@ the dump-capture kernel. This ensures that ongoing Direct Memory Access The kexec -p command loads the dump-capture kernel into this reserved memory. -On x86 machines, the first 640 KB of physical memory is needed to boot, -regardless of where the kernel loads. Therefore, kexec backs up this -region just before rebooting into the dump-capture kernel. +On x86 machines, the first 640 KB of physical memory is needed for boot, +regardless of where the kernel loads. For simpler handling, the whole +low 1M is reserved to avoid any later kernel or device driver writing +data into this area. Like this, the low 1M can be reused as system RAM +by kdump kernel without extra handling. -Similarly on PPC64 machines first 32KB of physical memory is needed for -booting regardless of where the kernel is loaded and to support 64K page -size kexec backs up the first 64KB memory. +On PPC64 machines first 32KB of physical memory is needed for booting +regardless of where the kernel is loaded and to support 64K page size +kexec backs up the first 64KB memory. For s390x, when kdump is triggered, the crashkernel region is exchanged with the region [0, crashkernel region size] and then the kdump kernel @@ -46,14 +48,14 @@ passed to the dump-capture kernel through the elfcorehdr= boot parameter. Optionally the size of the ELF header can also be passed when using the elfcorehdr=[size[KMG]@]offset[KMG] syntax. - With the dump-capture kernel, you can access the memory image through /proc/vmcore. This exports the dump as an ELF-format file that you can -write out using file copy commands such as cp or scp. Further, you can -use analysis tools such as the GNU Debugger (GDB) and the Crash tool to -debug the dump file. This method ensures that the dump pages are correctly -ordered. - +write out using file copy commands such as cp or scp. You can also use +makedumpfile utility to analyze and write out filtered contents with +options, e.g with '-d 31' it will only write out kernel data. Further, +you can use analysis tools such as the GNU Debugger (GDB) and the Crash +tool to debug the dump file. This method ensures that the dump pages are +correctly ordered. Setup and Installation ====================== @@ -125,9 +127,18 @@ dump-capture kernels for enabling kdump support. System kernel config options ---------------------------- -1) Enable "kexec system call" in "Processor type and features.":: +1) Enable "kexec system call" or "kexec file based system call" in + "Processor type and features.":: + + CONFIG_KEXEC=y or CONFIG_KEXEC_FILE=y + + And both of them will select KEXEC_CORE:: - CONFIG_KEXEC=y + CONFIG_KEXEC_CORE=y + + Subsequently, CRASH_CORE is selected by KEXEC_CORE:: + + CONFIG_CRASH_CORE=y 2) Enable "sysfs file system support" in "Filesystem" -> "Pseudo filesystems." This is usually enabled by default:: @@ -175,17 +186,19 @@ Dump-capture kernel config options (Arch Dependent, i386 and x86_64) CONFIG_HIGHMEM4G -2) On i386 and x86_64, disable symmetric multi-processing support - under "Processor type and features":: +2) With CONFIG_SMP=y, usually nr_cpus=1 need specified on the kernel + command line when loading the dump-capture kernel because one + CPU is enough for kdump kernel to dump vmcore on most of systems. - CONFIG_SMP=n + However, you can also specify nr_cpus=X to enable multiple processors + in kdump kernel. In this case, "disable_cpu_apicid=" is needed to + tell kdump kernel which cpu is 1st kernel's BSP. Please refer to + admin-guide/kernel-parameters.txt for more details. - (If CONFIG_SMP=y, then specify maxcpus=1 on the kernel command line - when loading the dump-capture kernel, see section "Load the Dump-capture - Kernel".) + With CONFIG_SMP=n, the above things are not related. -3) If one wants to build and use a relocatable kernel, - Enable "Build a relocatable kernel" support under "Processor type and +3) A relocatable kernel is suggested to be built by default. If not yet, + enable "Build a relocatable kernel" support under "Processor type and features":: CONFIG_RELOCATABLE=y @@ -232,7 +245,7 @@ Dump-capture kernel config options (Arch Dependent, ia64) as a dump-capture kernel if desired. The crashkernel region can be automatically placed by the system - kernel at run time. This is done by specifying the base address as 0, + kernel at runtime. This is done by specifying the base address as 0, or omitting it all together:: crashkernel=256M@0 @@ -241,10 +254,6 @@ Dump-capture kernel config options (Arch Dependent, ia64) crashkernel=256M - If the start address is specified, note that the start address of the - kernel will be aligned to 64Mb, so if the start address is not then - any space below the alignment point will be wasted. - Dump-capture kernel config options (Arch Dependent, arm) ---------------------------------------------------------- @@ -260,46 +269,82 @@ Dump-capture kernel config options (Arch Dependent, arm64) on non-VHE systems even if it is configured. This is because the CPU will not be reset to EL2 on panic. -Extended crashkernel syntax +crashkernel syntax =========================== +1) crashkernel=size@offset -While the "crashkernel=size[@offset]" syntax is sufficient for most -configurations, sometimes it's handy to have the reserved memory dependent -on the value of System RAM -- that's mostly for distributors that pre-setup -the kernel command line to avoid a unbootable system after some memory has -been removed from the machine. + Here 'size' specifies how much memory to reserve for the dump-capture kernel + and 'offset' specifies the beginning of this reserved memory. For example, + "crashkernel=64M@16M" tells the system kernel to reserve 64 MB of memory + starting at physical address 0x01000000 (16MB) for the dump-capture kernel. -The syntax is:: + The crashkernel region can be automatically placed by the system + kernel at run time. This is done by specifying the base address as 0, + or omitting it all together:: - crashkernel=:[,:,...][@offset] - range=start-[end] + crashkernel=256M@0 -For example:: + or:: - crashkernel=512M-2G:64M,2G-:128M + crashkernel=256M -This would mean: + If the start address is specified, note that the start address of the + kernel will be aligned to a value (which is Arch dependent), so if the + start address is not then any space below the alignment point will be + wasted. - 1) if the RAM is smaller than 512M, then don't reserve anything - (this is the "rescue" case) - 2) if the RAM size is between 512M and 2G (exclusive), then reserve 64M - 3) if the RAM size is larger than 2G, then reserve 128M +2) range1:size1[,range2:size2,...][@offset] + While the "crashkernel=size[@offset]" syntax is sufficient for most + configurations, sometimes it's handy to have the reserved memory dependent + on the value of System RAM -- that's mostly for distributors that pre-setup + the kernel command line to avoid a unbootable system after some memory has + been removed from the machine. + The syntax is:: -Boot into System Kernel -======================= + crashkernel=:[,:,...][@offset] + range=start-[end] + + For example:: + + crashkernel=512M-2G:64M,2G-:128M + This would mean: + + 1) if the RAM is smaller than 512M, then don't reserve anything + (this is the "rescue" case) + 2) if the RAM size is between 512M and 2G (exclusive), then reserve 64M + 3) if the RAM size is larger than 2G, then reserve 128M + +3) crashkernel=size,high and crashkernel=size,low + + If memory above 4G is preferred, crashkernel=size,high can be used to + fulfill that. With it, physical memory is allowed to be allocated from top, + so could be above 4G if system has more than 4G RAM installed. Otherwise, + memory region will be allocated below 4G if available. + + When crashkernel=X,high is passed, kernel could allocate physical memory + region above 4G, low memory under 4G is needed in this case. There are + three ways to get low memory: + + 1) Kernel will allocate at least 256M memory below 4G automatically + if crashkernel=Y,low is not specified. + 2) Let user specify low memory size instead. + 3) Specified value 0 will disable low memory allocation:: + + crashkernel=0,low + +Boot into System Kernel +----------------------- 1) Update the boot loader (such as grub, yaboot, or lilo) configuration files as necessary. -2) Boot the system kernel with the boot parameter "crashkernel=Y@X", - where Y specifies how much memory to reserve for the dump-capture kernel - and X specifies the beginning of this reserved memory. For example, - "crashkernel=64M@16M" tells the system kernel to reserve 64 MB of memory - starting at physical address 0x01000000 (16MB) for the dump-capture kernel. +2) Boot the system kernel with the boot parameter "crashkernel=Y@X". - On x86 and x86_64, use "crashkernel=64M@16M". + On x86 and x86_64, use "crashkernel=Y[@X]". Most of the time, the + start address 'X' is not necessary, kernel will search a suitable + area. Unless an explicit start address is expected. On ppc64, use "crashkernel=128M@32M". @@ -331,8 +376,8 @@ of dump-capture kernel. Following is the summary. For i386 and x86_64: - - Use vmlinux if kernel is not relocatable. - Use bzImage/vmlinuz if kernel is relocatable. + - Use vmlinux if kernel is not relocatable. For ppc64: @@ -392,7 +437,7 @@ loading dump-capture kernel. For i386, x86_64 and ia64: - "1 irqpoll maxcpus=1 reset_devices" + "1 irqpoll nr_cpus=1 reset_devices" For ppc64: @@ -400,7 +445,7 @@ For ppc64: For s390x: - "1 maxcpus=1 cgroup_disable=memory" + "1 nr_cpus=1 cgroup_disable=memory" For arm: @@ -408,7 +453,7 @@ For arm: For arm64: - "1 maxcpus=1 reset_devices" + "1 nr_cpus=1 reset_devices" Notes on loading the dump-capture kernel: @@ -488,6 +533,10 @@ the following command:: cp /proc/vmcore +You can also use makedumpfile utility to write out the dump file +with specified options to filter out unwanted contents, e.g:: + + makedumpfile -l --message-level 1 -d 31 /proc/vmcore Analysis ======== @@ -535,8 +584,7 @@ This will cause a kdump to occur at the add_taint()->panic() call. Contact ======= -- Vivek Goyal (vgoyal@redhat.com) -- Maneesh Soni (maneesh@in.ibm.com) +- kexec@lists.infradead.org GDB macros ========== -- cgit v1.3.1 From 91a1265cacdd96229304adddf18dcf64a4b8c040 Mon Sep 17 00:00:00 2001 From: Dwaipayan Ray Date: Mon, 14 Jun 2021 19:41:32 +0530 Subject: docs: checkpatch: Document and segregate more checkpatch message types Add and document more checkpatch message types. About 50% of all message types are documented now. In addition to this: - Create a new subsection 'Indentation and Line Breaks'. - Rename subsection 'Comment style' to simply 'Comments'. - Refactor some of the existing types to appropriate subsections. Reviewed-by: Lukas Bulwahn Tested-by: Lukas Bulwahn Signed-off-by: Dwaipayan Ray Link: https://lore.kernel.org/r/20210614141132.6881-1-dwaipayanray1@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/dev-tools/checkpatch.rst | 399 +++++++++++++++++++++++++++------ 1 file changed, 328 insertions(+), 71 deletions(-) (limited to 'Documentation') diff --git a/Documentation/dev-tools/checkpatch.rst b/Documentation/dev-tools/checkpatch.rst index 87b859f321de..f0956e9ea2d8 100644 --- a/Documentation/dev-tools/checkpatch.rst +++ b/Documentation/dev-tools/checkpatch.rst @@ -298,10 +298,148 @@ API usage See: https://www.kernel.org/doc/html/latest/process/deprecated.html#simple-strtol-simple-strtoll-simple-strtoul-simple-strtoull + **CONSTANT_CONVERSION** + Use of __constant_ form is discouraged for the following functions:: + + __constant_cpu_to_be[x] + __constant_cpu_to_le[x] + __constant_be[x]_to_cpu + __constant_le[x]_to_cpu + __constant_htons + __constant_ntohs + + Using any of these outside of include/uapi/ is not preferred as using the + function without __constant_ is identical when the argument is a + constant. + + In big endian systems, the macros like __constant_cpu_to_be32(x) and + cpu_to_be32(x) expand to the same expression:: + + #define __constant_cpu_to_be32(x) ((__force __be32)(__u32)(x)) + #define __cpu_to_be32(x) ((__force __be32)(__u32)(x)) + + In little endian systems, the macros __constant_cpu_to_be32(x) and + cpu_to_be32(x) expand to __constant_swab32 and __swab32. __swab32 + has a __builtin_constant_p check:: + + #define __swab32(x) \ + (__builtin_constant_p((__u32)(x)) ? \ + ___constant_swab32(x) : \ + __fswab32(x)) + + So ultimately they have a special case for constants. + Similar is the case with all of the macros in the list. Thus + using the __constant_... forms are unnecessarily verbose and + not preferred outside of include/uapi. + + See: https://lore.kernel.org/lkml/1400106425.12666.6.camel@joe-AO725/ + + **DEPRECATED_API** + Usage of a deprecated RCU API is detected. It is recommended to replace + old flavourful RCU APIs by their new vanilla-RCU counterparts. + + The full list of available RCU APIs can be viewed from the kernel docs. + + See: https://www.kernel.org/doc/html/latest/RCU/whatisRCU.html#full-list-of-rcu-apis + + **DEPRECATED_VARIABLE** + EXTRA_{A,C,CPP,LD}FLAGS are deprecated and should be replaced by the new + flags added via commit f77bf01425b1 ("kbuild: introduce ccflags-y, + asflags-y and ldflags-y"). + + The following conversion scheme maybe used:: + + EXTRA_AFLAGS -> asflags-y + EXTRA_CFLAGS -> ccflags-y + EXTRA_CPPFLAGS -> cppflags-y + EXTRA_LDFLAGS -> ldflags-y + + See: + + 1. https://lore.kernel.org/lkml/20070930191054.GA15876@uranus.ravnborg.org/ + 2. https://lore.kernel.org/lkml/1313384834-24433-12-git-send-email-lacombar@gmail.com/ + 3. https://www.kernel.org/doc/html/latest/kbuild/makefiles.html#compilation-flags + + **DEVICE_ATTR_FUNCTIONS** + The function names used in DEVICE_ATTR is unusual. + Typically, the store and show functions are used with _store and + _show, where is a named attribute variable of the device. + + Consider the following examples:: + + static DEVICE_ATTR(type, 0444, type_show, NULL); + static DEVICE_ATTR(power, 0644, power_show, power_store); + + The function names should preferably follow the above pattern. + + See: https://www.kernel.org/doc/html/latest/driver-api/driver-model/device.html#attributes + + **DEVICE_ATTR_RO** + The DEVICE_ATTR_RO(name) helper macro can be used instead of + DEVICE_ATTR(name, 0444, name_show, NULL); + + Note that the macro automatically appends _show to the named + attribute variable of the device for the show method. + + See: https://www.kernel.org/doc/html/latest/driver-api/driver-model/device.html#attributes + + **DEVICE_ATTR_RW** + The DEVICE_ATTR_RW(name) helper macro can be used instead of + DEVICE_ATTR(name, 0644, name_show, name_store); + + Note that the macro automatically appends _show and _store to the + named attribute variable of the device for the show and store methods. + + See: https://www.kernel.org/doc/html/latest/driver-api/driver-model/device.html#attributes + + **DEVICE_ATTR_WO** + The DEVICE_AATR_WO(name) helper macro can be used instead of + DEVICE_ATTR(name, 0200, NULL, name_store); + + Note that the macro automatically appends _store to the + named attribute variable of the device for the store method. + + See: https://www.kernel.org/doc/html/latest/driver-api/driver-model/device.html#attributes + + **DUPLICATED_SYSCTL_CONST** + Commit d91bff3011cf ("proc/sysctl: add shared variables for range + check") added some shared const variables to be used instead of a local + copy in each source file. + + Consider replacing the sysctl range checking value with the shared + one in include/linux/sysctl.h. The following conversion scheme may + be used:: + + &zero -> SYSCTL_ZERO + &one -> SYSCTL_ONE + &int_max -> SYSCTL_INT_MAX + + See: + + 1. https://lore.kernel.org/lkml/20190430180111.10688-1-mcroce@redhat.com/ + 2. https://lore.kernel.org/lkml/20190531131422.14970-1-mcroce@redhat.com/ + + **ENOSYS** + ENOSYS means that a nonexistent system call was called. + Earlier, it was wrongly used for things like invalid operations on + otherwise valid syscalls. This should be avoided in new code. + + See: https://lore.kernel.org/lkml/5eb299021dec23c1a48fa7d9f2c8b794e967766d.1408730669.git.luto@amacapital.net/ + + **ENOTSUPP** + ENOTSUPP is not a standard error code and should be avoided in new patches. + EOPNOTSUPP should be used instead. + + See: https://lore.kernel.org/netdev/20200510182252.GA411829@lunn.ch/ + + **EXPORT_SYMBOL** + EXPORT_SYMBOL should immediately follow the symbol to be exported. + **IN_ATOMIC** in_atomic() is not for driver use so any such use is reported as an ERROR. - Also in_atomic() is often used to determine if we may sleep, but it is not - reliable in this use model therefore its use is strongly discouraged. + Also in_atomic() is often used to determine if sleeping is permitted, + but it is not reliable in this use model. Therefore its use is + strongly discouraged. However, in_atomic() is ok for core kernel use. @@ -335,8 +473,8 @@ API usage See: https://www.kernel.org/doc/html/latest/timers/timers-howto.html#delays-information-on-the-various-kernel-delay-sleep-mechanisms -Comment style -------------- +Comments +-------- **BLOCK_COMMENT_STYLE** The comment style is incorrect. The preferred style for multi- @@ -362,6 +500,21 @@ Comment style See: https://www.kernel.org/doc/html/latest/process/coding-style.html#commenting + **DATA_RACE** + Applications of data_race() should have a comment so as to document the + reasoning behind why it was deemed safe. + + See: https://lore.kernel.org/lkml/20200401101714.44781-1-elver@google.com/ + + **FSF_MAILING_ADDRESS** + Kernel maintainers reject new instances of the GPL boilerplate paragraph + directing people to write to the FSF for a copy of the GPL, since the + FSF has moved in the past and may do so again. + So do not write paragraphs about writing to the Free Software Foundation's + mailing address. + + See: https://lore.kernel.org/lkml/20131006222342.GT19510@leaf/ + Commit message -------------- @@ -394,6 +547,13 @@ Commit message See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#describe-your-changes + **EMAIL_SUBJECT** + Naming the tool that found the issue is not very useful in the + subject line. A good subject line summarizes the change that + the patch brings. + + See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#describe-your-changes + **FROM_SIGN_OFF_MISMATCH** The author's email does not match with that in the Signed-off-by: line(s). This can be sometimes caused due to an improperly configured @@ -482,6 +642,87 @@ Comparison style side of the test should be avoided. +Indentation and Line Breaks +--------------------------- + + **CODE_INDENT** + Code indent should use tabs instead of spaces. + Outside of comments, documentation and Kconfig, + spaces are never used for indentation. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#indentation + + **DEEP_INDENTATION** + Indentation with 6 or more tabs usually indicate overly indented + code. + + It is suggested to refactor excessive indentation of + if/else/for/do/while/switch statements. + + See: https://lore.kernel.org/lkml/1328311239.21255.24.camel@joe2Laptop/ + + **SWITCH_CASE_INDENT_LEVEL** + switch should be at the same indent as case. + Example:: + + switch (suffix) { + case 'G': + case 'g': + mem <<= 30; + break; + case 'M': + case 'm': + mem <<= 20; + break; + case 'K': + case 'k': + mem <<= 10; + fallthrough; + default: + break; + } + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#indentation + + **LONG_LINE** + The line has exceeded the specified maximum length. + To use a different maximum line length, the --max-line-length=n option + may be added while invoking checkpatch. + + Earlier, the default line length was 80 columns. Commit bdc48fa11e46 + ("checkpatch/coding-style: deprecate 80-column warning") increased the + limit to 100 columns. This is not a hard limit either and it's + preferable to stay within 80 columns whenever possible. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings + + **LONG_LINE_STRING** + A string starts before but extends beyond the maximum line length. + To use a different maximum line length, the --max-line-length=n option + may be added while invoking checkpatch. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings + + **LONG_LINE_COMMENT** + A comment starts before but extends beyond the maximum line length. + To use a different maximum line length, the --max-line-length=n option + may be added while invoking checkpatch. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings + + **TRAILING_STATEMENTS** + Trailing statements (for example after any conditional) should be + on the next line. + Statements, such as:: + + if (x == y) break; + + should be:: + + if (x == y) + break; + + Macros, Attributes and Symbols ------------------------------ @@ -546,6 +787,9 @@ Macros, Attributes and Symbols See: https://lore.kernel.org/lkml/CA+55aFycQ9XJvEOsiM3txHL5bjUc8CeKWJNR_H+MiicaddB42Q@mail.gmail.com/ + **DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON** + do {} while(0) macros should not have a trailing semicolon. + **INIT_ATTRIBUTE** Const init definitions should use __initconst instead of __initdata. @@ -614,6 +858,48 @@ Functions and Variables See: https://www.kernel.org/doc/html/latest/process/coding-style.html#naming + **CONST_CONST** + Using `const const *` is generally meant to be + written `const * const`. + + **CONST_STRUCT** + Using const is generally a good idea. Checkpatch reads + a list of frequently used structs that are always or + almost always constant. + + The existing structs list can be viewed from + `scripts/const_structs.checkpatch`. + + See: https://lore.kernel.org/lkml/alpine.DEB.2.10.1608281509480.3321@hadrien/ + + **EMBEDDED_FUNCTION_NAME** + Embedded function names are less appropriate to use as + refactoring can cause function renaming. Prefer the use of + "%s", __func__ to embedded function names. + + Note that this does not work with -f (--file) checkpatch option + as it depends on patch context providing the function name. + + **FUNCTION_ARGUMENTS** + This warning is emitted due to any of the following reasons: + + 1. Arguments for the function declaration do not follow + the identifier name. Example:: + + void foo + (int bar, int baz) + + This should be corrected to:: + + void foo(int bar, int baz) + + 2. Some arguments for the function definition do not + have an identifier name. Example:: + + void foo(int) + + All arguments should have identifier names. + **FUNCTION_WITHOUT_ARGS** Function declarations without arguments like:: @@ -647,6 +933,13 @@ Functions and Variables Permissions ----------- + **DEVICE_ATTR_PERMS** + The permissions used in DEVICE_ATTR are unusual. + Typically only three permissions are used - 0644 (RW), 0444 (RO) + and 0200 (WO). + + See: https://www.kernel.org/doc/html/latest/filesystems/sysfs.html#attributes + **EXECUTE_PERMISSIONS** There is no reason for source files to be executable. The executable bit can be removed safely. @@ -708,13 +1001,6 @@ Spacing and Brackets = { [0...10] = 5 } - **CODE_INDENT** - Code indent should use tabs instead of spaces. - Outside of comments, documentation and Kconfig, - spaces are never used for indentation. - - See: https://www.kernel.org/doc/html/latest/process/coding-style.html#indentation - **CONCATENATED_STRING** Concatenated elements should have a space in between. Example:: @@ -760,29 +1046,6 @@ Spacing and Brackets See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces - **SWITCH_CASE_INDENT_LEVEL** - switch should be at the same indent as case. - Example:: - - switch (suffix) { - case 'G': - case 'g': - mem <<= 30; - break; - case 'M': - case 'm': - mem <<= 20; - break; - case 'K': - case 'k': - mem <<= 10; - /* fall through */ - default: - break; - } - - See: https://www.kernel.org/doc/html/latest/process/coding-style.html#indentation - **TRAILING_WHITESPACE** Trailing whitespace should always be removed. Some editors highlight the trailing whitespace and cause visual @@ -791,7 +1054,7 @@ Spacing and Brackets See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces **UNNECESSARY_PARENTHESES** - Parentheses are not required in the following cases:: + Parentheses are not required in the following cases: 1. Function pointer uses:: @@ -842,40 +1105,46 @@ Others The patch seems to be corrupted or lines are wrapped. Please regenerate the patch file before sending it to the maintainer. + **CVS_KEYWORD** + Since linux moved to git, the CVS markers are no longer used. + So, CVS style keywords ($Id$, $Revision$, $Log$) should not be + added. + + **DEFAULT_NO_BREAK** + switch default case is sometimes written as "default:;". This can + cause new cases added below default to be defective. + + A "break;" should be added after empty default statement to avoid + unwanted fallthrough. + **DOS_LINE_ENDINGS** For DOS-formatted patches, there are extra ^M symbols at the end of the line. These should be removed. - **FSF_MAILING_ADDRESS** - Kernel maintainers reject new instances of the GPL boilerplate paragraph - directing people to write to the FSF for a copy of the GPL, since the - FSF has moved in the past and may do so again. - So do not write paragraphs about writing to the Free Software Foundation's - mailing address. + **DT_SCHEMA_BINDING_PATCH** + DT bindings moved to a json-schema based format instead of + freeform text. - See: https://lore.kernel.org/lkml/20131006222342.GT19510@leaf/ + See: https://www.kernel.org/doc/html/latest/devicetree/bindings/writing-schema.html - **LONG_LINE** - The line has exceeded the specified maximum length. Consider refactoring - it. - To use a different maximum line length, the --max-line-length=n option - may be added while invoking checkpatch. + **DT_SPLIT_BINDING_PATCH** + Devicetree bindings should be their own patch. This is because + bindings are logically independent from a driver implementation, + they have a different maintainer (even though they often + are applied via the same tree), and it makes for a cleaner history in the + DT only tree created with git-filter-branch. - See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings + See: https://www.kernel.org/doc/html/latest/devicetree/bindings/submitting-patches.html#i-for-patch-submitters - **LONG_LINE_STRING** - A string starts before but extends beyond the maximum line length. - To use a different maximum line length, the --max-line-length=n option - may be added while invoking checkpatch. + **EMBEDDED_FILENAME** + Embedding the complete filename path inside the file isn't particularly + useful as often the path is moved around and becomes incorrect. - See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings + **FILE_PATH_CHANGES** + Whenever files are added, moved, or deleted, the MAINTAINERS file + patterns can be out of sync or outdated. - **LONG_LINE_COMMENT** - A comment starts before but extends beyond the maximum line length. - To use a different maximum line length, the --max-line-length=n option - may be added while invoking checkpatch. - - See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings + So MAINTAINERS might need updating in these cases. **MEMSET** The memset use appears to be incorrect. This may be caused due to @@ -895,17 +1164,5 @@ Others See: https://www.kernel.org/doc/html/latest/process/license-rules.html - **TRAILING_STATEMENTS** - Trailing statements (for example after any conditional) should be - on the next line. - Like:: - - if (x == y) break; - - should be:: - - if (x == y) - break; - **TYPO_SPELLING** Some words may have been misspelled. Consider reviewing them. -- cgit v1.3.1 From 005747526d4f3c2ec995891e95cb7625161022f9 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 3 Jun 2021 14:58:41 +0200 Subject: docs: fault-injection: fix non-working usage of negative values Fault injection uses debugfs in a way that the provided values via sysfs are interpreted as u64. Providing negative numbers results in an error: /sys/kernel/debug/fail_function# echo -1 > times sh: write error: Invalid argument Update the docs and examples to use "printf %#x " in these cases. For "retval", reword the paragraph a little and fix a typo. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20210603125841.27436-1-wsa+renesas@sang-engineering.com Signed-off-by: Jonathan Corbet --- Documentation/fault-injection/fault-injection.rst | 24 +++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/fault-injection/fault-injection.rst b/Documentation/fault-injection/fault-injection.rst index 31ecfe44e5b4..f47d05ed0d94 100644 --- a/Documentation/fault-injection/fault-injection.rst +++ b/Documentation/fault-injection/fault-injection.rst @@ -78,8 +78,10 @@ configuration of fault-injection capabilities. - /sys/kernel/debug/fail*/times: - specifies how many times failures may happen at most. - A value of -1 means "no limit". + specifies how many times failures may happen at most. A value of -1 + means "no limit". Note, though, that this file only accepts unsigned + values. So, if you want to specify -1, you better use 'printf' instead + of 'echo', e.g.: $ printf %#x -1 > times - /sys/kernel/debug/fail*/space: @@ -167,11 +169,13 @@ configuration of fault-injection capabilities. - ERRNO: retval must be -1 to -MAX_ERRNO (-4096). - ERR_NULL: retval must be 0 or -1 to -MAX_ERRNO (-4096). -- /sys/kernel/debug/fail_function//retval: +- /sys/kernel/debug/fail_function//retval: - specifies the "error" return value to inject to the given - function for given function. This will be created when - user specifies new injection entry. + specifies the "error" return value to inject to the given function. + This will be created when the user specifies a new injection entry. + Note that this file only accepts unsigned values. So, if you want to + use a negative errno, you better use 'printf' instead of 'echo', e.g.: + $ printf %#x -12 > retval Boot option ^^^^^^^^^^^ @@ -255,7 +259,7 @@ Application Examples echo Y > /sys/kernel/debug/$FAILTYPE/task-filter echo 10 > /sys/kernel/debug/$FAILTYPE/probability echo 100 > /sys/kernel/debug/$FAILTYPE/interval - echo -1 > /sys/kernel/debug/$FAILTYPE/times + printf %#x -1 > /sys/kernel/debug/$FAILTYPE/times echo 0 > /sys/kernel/debug/$FAILTYPE/space echo 2 > /sys/kernel/debug/$FAILTYPE/verbose echo 1 > /sys/kernel/debug/$FAILTYPE/ignore-gfp-wait @@ -309,7 +313,7 @@ Application Examples echo N > /sys/kernel/debug/$FAILTYPE/task-filter echo 10 > /sys/kernel/debug/$FAILTYPE/probability echo 100 > /sys/kernel/debug/$FAILTYPE/interval - echo -1 > /sys/kernel/debug/$FAILTYPE/times + printf %#x -1 > /sys/kernel/debug/$FAILTYPE/times echo 0 > /sys/kernel/debug/$FAILTYPE/space echo 2 > /sys/kernel/debug/$FAILTYPE/verbose echo 1 > /sys/kernel/debug/$FAILTYPE/ignore-gfp-wait @@ -336,11 +340,11 @@ Application Examples FAILTYPE=fail_function FAILFUNC=open_ctree echo $FAILFUNC > /sys/kernel/debug/$FAILTYPE/inject - echo -12 > /sys/kernel/debug/$FAILTYPE/$FAILFUNC/retval + printf %#x -12 > /sys/kernel/debug/$FAILTYPE/$FAILFUNC/retval echo N > /sys/kernel/debug/$FAILTYPE/task-filter echo 100 > /sys/kernel/debug/$FAILTYPE/probability echo 0 > /sys/kernel/debug/$FAILTYPE/interval - echo -1 > /sys/kernel/debug/$FAILTYPE/times + printf %#x -1 > /sys/kernel/debug/$FAILTYPE/times echo 0 > /sys/kernel/debug/$FAILTYPE/space echo 1 > /sys/kernel/debug/$FAILTYPE/verbose -- cgit v1.3.1 From 05a463ec1bd4fd564312d6dbc0ea1e3a4701e4a4 Mon Sep 17 00:00:00 2001 From: Tian Tao Date: Fri, 11 Jun 2021 17:22:49 +1200 Subject: docs: cputopology: move the sysfs ABI description to right place Documentation/admin-guide/cputopology.rst is the wrong place to describe sysfs ABI. So move the cputopology ABI things to Documentation/ABI/stable/sysfs-devices-system-cpu and add a reference to ABI doc in Documentation/admin-guide/cputopology.rst. Link: https://lkml.kernel.org/r/20210319041618.14316-1-song.bao.hua@hisilicon.com Cc: Greg Kroah-Hartman Signed-off-by: Tian Tao Signed-off-by: Barry Song Link: https://lore.kernel.org/r/20210611052249.25776-1-song.bao.hua@hisilicon.com Signed-off-by: Jonathan Corbet --- Documentation/ABI/stable/sysfs-devices-system-cpu | 83 ++++++++++++++++++++++ Documentation/admin-guide/cputopology.rst | 85 ++--------------------- 2 files changed, 87 insertions(+), 81 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/stable/sysfs-devices-system-cpu b/Documentation/ABI/stable/sysfs-devices-system-cpu index 33c133e2a631..516dafea03eb 100644 --- a/Documentation/ABI/stable/sysfs-devices-system-cpu +++ b/Documentation/ABI/stable/sysfs-devices-system-cpu @@ -23,3 +23,86 @@ Description: Default value for the Data Stream Control Register (DSCR) on here). If set by a process it will be inherited by child processes. Values: 64 bit unsigned integer (bit field) + +What: /sys/devices/system/cpu/cpuX/topology/physical_package_id +Description: physical package id of cpuX. Typically corresponds to a physical + socket number, but the actual value is architecture and platform + dependent. +Values: integer + +What: /sys/devices/system/cpu/cpuX/topology/die_id +Description: the CPU die ID of cpuX. Typically it is the hardware platform's + identifier (rather than the kernel's). The actual value is + architecture and platform dependent. +Values: integer + +What: /sys/devices/system/cpu/cpuX/topology/core_id +Description: the CPU core ID of cpuX. Typically it is the hardware platform's + identifier (rather than the kernel's). The actual value is + architecture and platform dependent. +Values: integer + +What: /sys/devices/system/cpu/cpuX/topology/book_id +Description: the book ID of cpuX. Typically it is the hardware platform's + identifier (rather than the kernel's). The actual value is + architecture and platform dependent. it's only used on s390. +Values: integer + +What: /sys/devices/system/cpu/cpuX/topology/drawer_id +Description: the drawer ID of cpuX. Typically it is the hardware platform's + identifier (rather than the kernel's). The actual value is + architecture and platform dependent. it's only used on s390. +Values: integer + +What: /sys/devices/system/cpu/cpuX/topology/core_cpus +Description: internal kernel map of CPUs within the same core. + (deprecated name: "thread_siblings") +Values: hexadecimal bitmask. + +What: /sys/devices/system/cpu/cpuX/topology/core_cpus_list +Description: human-readable list of CPUs within the same core. + The format is like 0-3, 8-11, 14,17. + (deprecated name: "thread_siblings_list"). +Values: decimal list. + +What: /sys/devices/system/cpu/cpuX/topology/package_cpus +Description: internal kernel map of the CPUs sharing the same physical_package_id. + (deprecated name: "core_siblings"). +Values: hexadecimal bitmask. + +What: /sys/devices/system/cpu/cpuX/topology/package_cpus_list +Description: human-readable list of CPUs sharing the same physical_package_id. + The format is like 0-3, 8-11, 14,17. + (deprecated name: "core_siblings_list") +Values: decimal list. + +What: /sys/devices/system/cpu/cpuX/topology/die_cpus +Description: internal kernel map of CPUs within the same die. +Values: hexadecimal bitmask. + +What: /sys/devices/system/cpu/cpuX/topology/die_cpus_list +Description: human-readable list of CPUs within the same die. + The format is like 0-3, 8-11, 14,17. +Values: decimal list. + +What: /sys/devices/system/cpu/cpuX/topology/book_siblings +Description: internal kernel map of cpuX's hardware threads within the same + book_id. it's only used on s390. +Values: hexadecimal bitmask. + +What: /sys/devices/system/cpu/cpuX/topology/book_siblings_list +Description: human-readable list of cpuX's hardware threads within the same + book_id. + The format is like 0-3, 8-11, 14,17. it's only used on s390. +Values: decimal list. + +What: /sys/devices/system/cpu/cpuX/topology/drawer_siblings +Description: internal kernel map of cpuX's hardware threads within the same + drawer_id. it's only used on s390. +Values: hexadecimal bitmask. + +What: /sys/devices/system/cpu/cpuX/topology/drawer_siblings_list +Description: human-readable list of cpuX's hardware threads within the same + drawer_id. + The format is like 0-3, 8-11, 14,17. it's only used on s390. +Values: decimal list. diff --git a/Documentation/admin-guide/cputopology.rst b/Documentation/admin-guide/cputopology.rst index b90dafcc8237..8632a1db36e4 100644 --- a/Documentation/admin-guide/cputopology.rst +++ b/Documentation/admin-guide/cputopology.rst @@ -2,87 +2,10 @@ How CPU topology info is exported via sysfs =========================================== -Export CPU topology info via sysfs. Items (attributes) are similar -to /proc/cpuinfo output of some architectures. They reside in -/sys/devices/system/cpu/cpuX/topology/: - -physical_package_id: - - physical package id of cpuX. Typically corresponds to a physical - socket number, but the actual value is architecture and platform - dependent. - -die_id: - - the CPU die ID of cpuX. Typically it is the hardware platform's - identifier (rather than the kernel's). The actual value is - architecture and platform dependent. - -core_id: - - the CPU core ID of cpuX. Typically it is the hardware platform's - identifier (rather than the kernel's). The actual value is - architecture and platform dependent. - -book_id: - - the book ID of cpuX. Typically it is the hardware platform's - identifier (rather than the kernel's). The actual value is - architecture and platform dependent. - -drawer_id: - - the drawer ID of cpuX. Typically it is the hardware platform's - identifier (rather than the kernel's). The actual value is - architecture and platform dependent. - -core_cpus: - - internal kernel map of CPUs within the same core. - (deprecated name: "thread_siblings") - -core_cpus_list: - - human-readable list of CPUs within the same core. - (deprecated name: "thread_siblings_list"); - -package_cpus: - - internal kernel map of the CPUs sharing the same physical_package_id. - (deprecated name: "core_siblings") - -package_cpus_list: - - human-readable list of CPUs sharing the same physical_package_id. - (deprecated name: "core_siblings_list") - -die_cpus: - - internal kernel map of CPUs within the same die. - -die_cpus_list: - - human-readable list of CPUs within the same die. - -book_siblings: - - internal kernel map of cpuX's hardware threads within the same - book_id. - -book_siblings_list: - - human-readable list of cpuX's hardware threads within the same - book_id. - -drawer_siblings: - - internal kernel map of cpuX's hardware threads within the same - drawer_id. - -drawer_siblings_list: - - human-readable list of cpuX's hardware threads within the same - drawer_id. +CPU topology info is exported via sysfs. Items (attributes) are similar +to /proc/cpuinfo output of some architectures. They reside in +/sys/devices/system/cpu/cpuX/topology/. Please refer to the ABI file: +Documentation/ABI/stable/sysfs-devices-system-cpu. Architecture-neutral, drivers/base/topology.c, exports these attributes. However, the book and drawer related sysfs files will only be created if -- cgit v1.3.1 From 09a8ec9a2d03efa2813d9d306424eb6802146b57 Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Wed, 2 Jun 2021 15:27:57 -0400 Subject: dt-bindings: mmc: sdhci-iproc: Add brcm,bcm7211a0-sdhci Add new compatible string for the legacy sdhci controller on the BCM7211 family of SoC's. Signed-off-by: Al Cooper Link: https://lore.kernel.org/r/20210602192758.38735-1-alcooperx@gmail.com Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml index 6f569fbfa134..2f63f2cdeb71 100644 --- a/Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml @@ -21,6 +21,7 @@ properties: - brcm,bcm2711-emmc2 - brcm,sdhci-iproc-cygnus - brcm,sdhci-iproc + - brcm,bcm7211a0-sdhci reg: minItems: 1 -- cgit v1.3.1 From 703ac06a88f07f1fdde795d00c0296750e2b8e4c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Jun 2021 14:00:54 +0200 Subject: media: docs: */media/index.rst: don't use ReST doc:`foo` The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab --- Documentation/admin-guide/media/index.rst | 12 +++++++----- Documentation/driver-api/media/index.rst | 10 ++++++---- Documentation/userspace-api/media/index.rst | 12 +++++++----- 3 files changed, 20 insertions(+), 14 deletions(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/media/index.rst b/Documentation/admin-guide/media/index.rst index 6e0d2bae7154..c676af665111 100644 --- a/Documentation/admin-guide/media/index.rst +++ b/Documentation/admin-guide/media/index.rst @@ -11,12 +11,14 @@ its supported drivers. Please see: -- :doc:`/userspace-api/media/index` - for the userspace APIs used on media devices. +Documentation/userspace-api/media/index.rst -- :doc:`/driver-api/media/index` - for driver development information and Kernel APIs used by - media devices; + - for the userspace APIs used on media devices. + +Documentation/driver-api/media/index.rst + + - for driver development information and Kernel APIs used by + media devices; The media subsystem =================== diff --git a/Documentation/driver-api/media/index.rst b/Documentation/driver-api/media/index.rst index 2ad71dfa8828..813d7db59da7 100644 --- a/Documentation/driver-api/media/index.rst +++ b/Documentation/driver-api/media/index.rst @@ -11,11 +11,13 @@ its supported drivers. Please see: -- :doc:`/admin-guide/media/index` - for usage information about media subsystem and supported drivers; +Documentation/admin-guide/media/index.rst -- :doc:`/userspace-api/media/index` - for the userspace APIs used on media devices. + - for usage information about media subsystem and supported drivers; + +Documentation/userspace-api/media/index.rst + + - for the userspace APIs used on media devices. .. only:: html diff --git a/Documentation/userspace-api/media/index.rst b/Documentation/userspace-api/media/index.rst index 7f42f83b9f59..d839904be085 100644 --- a/Documentation/userspace-api/media/index.rst +++ b/Documentation/userspace-api/media/index.rst @@ -11,12 +11,14 @@ used by media devices. Please see: -- :doc:`/admin-guide/media/index` - for usage information about media subsystem and supported drivers; +Documentation/admin-guide/media/index.rst -- :doc:`/driver-api/media/index` - for driver development information and Kernel APIs used by - media devices; + - for usage information about media subsystem and supported drivers; + +Documentation/driver-api/media/index.rst + + - for driver development information and Kernel APIs used by + media devices; .. only:: html -- cgit v1.3.1 From d759cd46b9f15180321b6f246a6e0964d4510aef Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Jun 2021 14:40:12 +0200 Subject: media: userspace-api: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/glossary.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/media/glossary.rst b/Documentation/userspace-api/media/glossary.rst index cb165d7176b7..96a360edbf3b 100644 --- a/Documentation/userspace-api/media/glossary.rst +++ b/Documentation/userspace-api/media/glossary.rst @@ -116,7 +116,7 @@ Glossary - :term:`RC API`; and - :term:`V4L2 API`. - See :doc:`index`. + See Documentation/userspace-api/media/index.rst. MC API **Media Controller API** -- cgit v1.3.1 From a169c44e58190bbdaf9c8d345cd445eec2c2b010 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Jun 2021 14:40:12 +0200 Subject: media: driver-api: drivers: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/drivers/bttv-devel.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/driver-api/media/drivers/bttv-devel.rst b/Documentation/driver-api/media/drivers/bttv-devel.rst index c9aa8b95a5e5..0885a04563a9 100644 --- a/Documentation/driver-api/media/drivers/bttv-devel.rst +++ b/Documentation/driver-api/media/drivers/bttv-devel.rst @@ -21,7 +21,7 @@ log, telling which card type is used. Like this one:: You should verify this is correct. If it isn't, you have to pass the correct board type as insmod argument, ``insmod bttv card=2`` for -example. The file :doc:`/admin-guide/media/bttv-cardlist` has a list +example. The file Documentation/admin-guide/media/bttv-cardlist.rst has a list of valid arguments for card. If your card isn't listed there, you might check the source code for -- cgit v1.3.1 From 6ef43d273e8562366035d8086008e4000a270fd8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Jun 2021 14:40:12 +0200 Subject: media: admin-guide: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab --- Documentation/admin-guide/media/bt8xx.rst | 15 ++++++++------- Documentation/admin-guide/media/bttv.rst | 21 +++++++++++---------- Documentation/admin-guide/media/saa7134.rst | 3 ++- 3 files changed, 21 insertions(+), 18 deletions(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/media/bt8xx.rst b/Documentation/admin-guide/media/bt8xx.rst index 1382ada1e38e..3589f6ab7e46 100644 --- a/Documentation/admin-guide/media/bt8xx.rst +++ b/Documentation/admin-guide/media/bt8xx.rst @@ -15,11 +15,12 @@ Authors: General information ------------------- -This class of cards has a bt878a as the PCI interface, and require the bttv driver -for accessing the i2c bus and the gpio pins of the bt8xx chipset. +This class of cards has a bt878a as the PCI interface, and require the bttv +driver for accessing the i2c bus and the gpio pins of the bt8xx chipset. -Please see :doc:`bttv-cardlist` for a complete list of Cards based on the -Conexant Bt8xx PCI bridge supported by the Linux Kernel. +Please see Documentation/admin-guide/media/bttv-cardlist.rst for a complete +list of Cards based on the Conexant Bt8xx PCI bridge supported by the +Linux Kernel. In order to be able to compile the kernel, some config options should be enabled:: @@ -80,7 +81,7 @@ for dvb-bt8xx drivers by passing modprobe parameters may be necessary. Running TwinHan and Clones ~~~~~~~~~~~~~~~~~~~~~~~~~~ -As shown at :doc:`bttv-cardlist`, TwinHan and +As shown at Documentation/admin-guide/media/bttv-cardlist.rst, TwinHan and clones use ``card=113`` modprobe parameter. So, in order to properly detect it for devices without EEPROM, you should use:: @@ -105,12 +106,12 @@ The autodetected values are determined by the cards' "response string". In your logs see f. ex.: dst_get_device_id: Recognize [DSTMCI]. For bug reports please send in a complete log with verbose=4 activated. -Please also see :doc:`ci`. +Please also see Documentation/admin-guide/media/ci.rst. Running multiple cards ~~~~~~~~~~~~~~~~~~~~~~ -See :doc:`bttv-cardlist` for a complete list of +See Documentation/admin-guide/media/bttv-cardlist.rst for a complete list of Card ID. Some examples: =========================== === diff --git a/Documentation/admin-guide/media/bttv.rst b/Documentation/admin-guide/media/bttv.rst index 0ef1f203104d..125f6f47123d 100644 --- a/Documentation/admin-guide/media/bttv.rst +++ b/Documentation/admin-guide/media/bttv.rst @@ -24,7 +24,8 @@ If your board has digital TV, you'll also need:: ./scripts/config -m DVB_BT8XX -In this case, please see :doc:`bt8xx` for additional notes. +In this case, please see Documentation/admin-guide/media/bt8xx.rst +for additional notes. Make bttv work with your card ----------------------------- @@ -39,7 +40,7 @@ If it doesn't bttv likely could not autodetect your card and needs some insmod options. The most important insmod option for bttv is "card=n" to select the correct card type. If you get video but no sound you've very likely specified the wrong (or no) card type. A list of supported -cards is in :doc:`bttv-cardlist`. +cards is in Documentation/admin-guide/media/bttv-cardlist.rst. If bttv takes very long to load (happens sometimes with the cheap cards which have no tuner), try adding this to your modules configuration @@ -57,8 +58,8 @@ directory should be enough for it to be autoload during the driver's probing mode (e. g. when the Kernel boots or when the driver is manually loaded via ``modprobe`` command). -If your card isn't listed in :doc:`bttv-cardlist` or if you have -trouble making audio work, please read :ref:`still_doesnt_work`. +If your card isn't listed in Documentation/admin-guide/media/bttv-cardlist.rst +or if you have trouble making audio work, please read :ref:`still_doesnt_work`. Autodetecting cards @@ -77,8 +78,8 @@ the Subsystem ID in the second line, looks like this: only bt878-based cards can have a subsystem ID (which does not mean that every card really has one). bt848 cards can't have a Subsystem ID and therefore can't be autodetected. There is a list with the ID's -at :doc:`bttv-cardlist` (in case you are interested or want to mail -patches with updates). +at Documentation/admin-guide/media/bttv-cardlist.rst +(in case you are interested or want to mail patches with updates). .. _still_doesnt_work: @@ -259,15 +260,15 @@ bug. It is very helpful if you can tell where exactly it broke With a hard freeze you probably doesn't find anything in the logfiles. The only way to capture any kernel messages is to hook up a serial console and let some terminal application log the messages. /me uses -screen. See :doc:`/admin-guide/serial-console` for details on setting -up a serial console. +screen. See Documentation/admin-guide/serial-console.rst for details on +setting up a serial console. -Read :doc:`/admin-guide/bug-hunting` to learn how to get any useful +Read Documentation/admin-guide/bug-hunting.rst to learn how to get any useful information out of a register+stack dump printed by the kernel on protection faults (so-called "kernel oops"). If you run into some kind of deadlock, you can try to dump a call trace -for each process using sysrq-t (see :doc:`/admin-guide/sysrq`). +for each process using sysrq-t (see Documentation/admin-guide/sysrq.rst). This way it is possible to figure where *exactly* some process in "D" state is stuck. diff --git a/Documentation/admin-guide/media/saa7134.rst b/Documentation/admin-guide/media/saa7134.rst index 7ab9c70b9abe..51eae7eb5ab7 100644 --- a/Documentation/admin-guide/media/saa7134.rst +++ b/Documentation/admin-guide/media/saa7134.rst @@ -50,7 +50,8 @@ To build and install, you should run:: Once the new Kernel is booted, saa7134 driver should be loaded automatically. Depending on the card you might have to pass ``card=`` as insmod option. -If so, please check :doc:`saa7134-cardlist` for valid choices. +If so, please check Documentation/admin-guide/media/saa7134-cardlist.rst +for valid choices. Once you have your card type number, you can pass a modules configuration via a file (usually, it is either ``/etc/modules.conf`` or some file at -- cgit v1.3.1 From b7fb14d3ac63117e0e8beabe75f4ea52051fbe3a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 16 Jun 2021 15:46:58 +0200 Subject: ide: remove the legacy ide driver The legay ide driver has been replace with libata starting in 2003 and has been scheduled for removal for a while. Finally kill it off so that we can start cleaning up various bits of cruft it forced on the block layer. Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe --- Documentation/userspace-api/ioctl/hdio.rst | 845 +---------- MAINTAINERS | 16 - drivers/Kconfig | 2 - drivers/Makefile | 1 - drivers/ide/Kconfig | 827 ----------- drivers/ide/Makefile | 109 -- drivers/ide/aec62xx.c | 331 ----- drivers/ide/ali14xx.c | 250 ---- drivers/ide/alim15x3.c | 602 -------- drivers/ide/amd74xx.c | 343 ----- drivers/ide/atiixp.c | 212 --- drivers/ide/buddha.c | 238 ---- drivers/ide/cmd640.c | 848 ----------- drivers/ide/cmd64x.c | 452 ------ drivers/ide/cs5520.c | 168 --- drivers/ide/cs5530.c | 295 ---- drivers/ide/cs5535.c | 216 --- drivers/ide/cs5536.c | 294 ---- drivers/ide/cy82c693.c | 234 ---- drivers/ide/delkin_cb.c | 181 --- drivers/ide/dtc2278.c | 155 --- drivers/ide/falconide.c | 226 --- drivers/ide/gayle.c | 188 --- drivers/ide/hpt366.c | 1545 --------------------- drivers/ide/ht6560b.c | 383 ----- drivers/ide/icside.c | 692 --------- drivers/ide/ide-4drives.c | 65 - drivers/ide/ide-acpi.c | 622 --------- drivers/ide/ide-atapi.c | 756 ---------- drivers/ide/ide-cd.c | 1858 ------------------------- drivers/ide/ide-cd.h | 123 -- drivers/ide/ide-cd_ioctl.c | 468 ------- drivers/ide/ide-cd_verbose.c | 362 ----- drivers/ide/ide-cs.c | 364 ----- drivers/ide/ide-devsets.c | 192 --- drivers/ide/ide-disk.c | 795 ----------- drivers/ide/ide-disk.h | 30 - drivers/ide/ide-disk_ioctl.c | 33 - drivers/ide/ide-disk_proc.c | 125 -- drivers/ide/ide-dma-sff.c | 336 ----- drivers/ide/ide-dma.c | 551 -------- drivers/ide/ide-eh.c | 443 ------ drivers/ide/ide-floppy.c | 551 -------- drivers/ide/ide-floppy.h | 42 - drivers/ide/ide-floppy_ioctl.c | 339 ----- drivers/ide/ide-floppy_proc.c | 34 - drivers/ide/ide-gd.c | 432 ------ drivers/ide/ide-gd.h | 43 - drivers/ide/ide-generic.c | 139 -- drivers/ide/ide-io-std.c | 262 ---- drivers/ide/ide-io.c | 904 ------------ drivers/ide/ide-ioctls.c | 306 ---- drivers/ide/ide-iops.c | 536 ------- drivers/ide/ide-legacy.c | 59 - drivers/ide/ide-lib.c | 146 -- drivers/ide/ide-park.c | 155 --- drivers/ide/ide-pci-generic.c | 203 --- drivers/ide/ide-pio-blacklist.c | 96 -- drivers/ide/ide-pm.c | 261 ---- drivers/ide/ide-pnp.c | 92 -- drivers/ide/ide-probe.c | 1623 ---------------------- drivers/ide/ide-proc.c | 633 --------- drivers/ide/ide-scan-pci.c | 113 -- drivers/ide/ide-sysfs.c | 143 -- drivers/ide/ide-tape.c | 2083 ---------------------------- drivers/ide/ide-taskfile.c | 668 --------- drivers/ide/ide-timings.c | 198 --- drivers/ide/ide-xfer-mode.c | 267 ---- drivers/ide/ide.c | 415 ------ drivers/ide/ide_platform.c | 133 -- drivers/ide/it8172.c | 165 --- drivers/ide/it8213.c | 217 --- drivers/ide/it821x.c | 715 ---------- drivers/ide/jmicron.c | 176 --- drivers/ide/ns87415.c | 350 ----- drivers/ide/opti621.c | 179 --- drivers/ide/palm_bk3710.c | 387 ------ drivers/ide/pdc202xx_new.c | 557 -------- drivers/ide/pdc202xx_old.c | 362 ----- drivers/ide/piix.c | 476 ------- drivers/ide/pmac.c | 1703 ----------------------- drivers/ide/qd65xx.c | 446 ------ drivers/ide/qd65xx.h | 145 -- drivers/ide/rapide.c | 106 -- drivers/ide/rz1000.c | 100 -- drivers/ide/sc1200.c | 355 ----- drivers/ide/serverworks.c | 456 ------ drivers/ide/setup-pci.c | 682 --------- drivers/ide/siimage.c | 843 ----------- drivers/ide/sis5513.c | 637 --------- drivers/ide/sl82c105.c | 367 ----- drivers/ide/slc90e66.c | 182 --- drivers/ide/tc86c001.c | 270 ---- drivers/ide/triflex.c | 143 -- drivers/ide/trm290.c | 374 ----- drivers/ide/tx4938ide.c | 209 --- drivers/ide/tx4939ide.c | 628 --------- drivers/ide/umc8672.c | 184 --- drivers/ide/via82cxxx.c | 532 ------- include/linux/ide.h | 1623 ---------------------- 100 files changed, 25 insertions(+), 41196 deletions(-) delete mode 100644 drivers/ide/Kconfig delete mode 100644 drivers/ide/Makefile delete mode 100644 drivers/ide/aec62xx.c delete mode 100644 drivers/ide/ali14xx.c delete mode 100644 drivers/ide/alim15x3.c delete mode 100644 drivers/ide/amd74xx.c delete mode 100644 drivers/ide/atiixp.c delete mode 100644 drivers/ide/buddha.c delete mode 100644 drivers/ide/cmd640.c delete mode 100644 drivers/ide/cmd64x.c delete mode 100644 drivers/ide/cs5520.c delete mode 100644 drivers/ide/cs5530.c delete mode 100644 drivers/ide/cs5535.c delete mode 100644 drivers/ide/cs5536.c delete mode 100644 drivers/ide/cy82c693.c delete mode 100644 drivers/ide/delkin_cb.c delete mode 100644 drivers/ide/dtc2278.c delete mode 100644 drivers/ide/falconide.c delete mode 100644 drivers/ide/gayle.c delete mode 100644 drivers/ide/hpt366.c delete mode 100644 drivers/ide/ht6560b.c delete mode 100644 drivers/ide/icside.c delete mode 100644 drivers/ide/ide-4drives.c delete mode 100644 drivers/ide/ide-acpi.c delete mode 100644 drivers/ide/ide-atapi.c delete mode 100644 drivers/ide/ide-cd.c delete mode 100644 drivers/ide/ide-cd.h delete mode 100644 drivers/ide/ide-cd_ioctl.c delete mode 100644 drivers/ide/ide-cd_verbose.c delete mode 100644 drivers/ide/ide-cs.c delete mode 100644 drivers/ide/ide-devsets.c delete mode 100644 drivers/ide/ide-disk.c delete mode 100644 drivers/ide/ide-disk.h delete mode 100644 drivers/ide/ide-disk_ioctl.c delete mode 100644 drivers/ide/ide-disk_proc.c delete mode 100644 drivers/ide/ide-dma-sff.c delete mode 100644 drivers/ide/ide-dma.c delete mode 100644 drivers/ide/ide-eh.c delete mode 100644 drivers/ide/ide-floppy.c delete mode 100644 drivers/ide/ide-floppy.h delete mode 100644 drivers/ide/ide-floppy_ioctl.c delete mode 100644 drivers/ide/ide-floppy_proc.c delete mode 100644 drivers/ide/ide-gd.c delete mode 100644 drivers/ide/ide-gd.h delete mode 100644 drivers/ide/ide-generic.c delete mode 100644 drivers/ide/ide-io-std.c delete mode 100644 drivers/ide/ide-io.c delete mode 100644 drivers/ide/ide-ioctls.c delete mode 100644 drivers/ide/ide-iops.c delete mode 100644 drivers/ide/ide-legacy.c delete mode 100644 drivers/ide/ide-lib.c delete mode 100644 drivers/ide/ide-park.c delete mode 100644 drivers/ide/ide-pci-generic.c delete mode 100644 drivers/ide/ide-pio-blacklist.c delete mode 100644 drivers/ide/ide-pm.c delete mode 100644 drivers/ide/ide-pnp.c delete mode 100644 drivers/ide/ide-probe.c delete mode 100644 drivers/ide/ide-proc.c delete mode 100644 drivers/ide/ide-scan-pci.c delete mode 100644 drivers/ide/ide-sysfs.c delete mode 100644 drivers/ide/ide-tape.c delete mode 100644 drivers/ide/ide-taskfile.c delete mode 100644 drivers/ide/ide-timings.c delete mode 100644 drivers/ide/ide-xfer-mode.c delete mode 100644 drivers/ide/ide.c delete mode 100644 drivers/ide/ide_platform.c delete mode 100644 drivers/ide/it8172.c delete mode 100644 drivers/ide/it8213.c delete mode 100644 drivers/ide/it821x.c delete mode 100644 drivers/ide/jmicron.c delete mode 100644 drivers/ide/ns87415.c delete mode 100644 drivers/ide/opti621.c delete mode 100644 drivers/ide/palm_bk3710.c delete mode 100644 drivers/ide/pdc202xx_new.c delete mode 100644 drivers/ide/pdc202xx_old.c delete mode 100644 drivers/ide/piix.c delete mode 100644 drivers/ide/pmac.c delete mode 100644 drivers/ide/qd65xx.c delete mode 100644 drivers/ide/qd65xx.h delete mode 100644 drivers/ide/rapide.c delete mode 100644 drivers/ide/rz1000.c delete mode 100644 drivers/ide/sc1200.c delete mode 100644 drivers/ide/serverworks.c delete mode 100644 drivers/ide/setup-pci.c delete mode 100644 drivers/ide/siimage.c delete mode 100644 drivers/ide/sis5513.c delete mode 100644 drivers/ide/sl82c105.c delete mode 100644 drivers/ide/slc90e66.c delete mode 100644 drivers/ide/tc86c001.c delete mode 100644 drivers/ide/triflex.c delete mode 100644 drivers/ide/trm290.c delete mode 100644 drivers/ide/tx4938ide.c delete mode 100644 drivers/ide/tx4939ide.c delete mode 100644 drivers/ide/umc8672.c delete mode 100644 drivers/ide/via82cxxx.c delete mode 100644 include/linux/ide.h (limited to 'Documentation') diff --git a/Documentation/userspace-api/ioctl/hdio.rst b/Documentation/userspace-api/ioctl/hdio.rst index 817371bf94e9..6ee8fc88699f 100644 --- a/Documentation/userspace-api/ioctl/hdio.rst +++ b/Documentation/userspace-api/ioctl/hdio.rst @@ -7,8 +7,8 @@ Summary of `HDIO_` ioctl calls November, 2004 This document attempts to describe the ioctl(2) calls supported by -the HD/IDE layer. These are by-and-large implemented (as of Linux 2.6) -in drivers/ide/ide.c and drivers/block/scsi_ioctl.c +the HD/IDE layer. These are by-and-large implemented (as of Linux 5.11) +drivers/ata/libata-scsi.c. ioctl values are listed in . As of this writing, they are as follows: @@ -17,50 +17,17 @@ are as follows: ======================= ======================================= HDIO_GETGEO get device geometry - HDIO_GET_UNMASKINTR get current unmask setting - HDIO_GET_MULTCOUNT get current IDE blockmode setting - HDIO_GET_QDMA get use-qdma flag - HDIO_SET_XFER set transfer rate via proc - HDIO_OBSOLETE_IDENTITY OBSOLETE, DO NOT USE - HDIO_GET_KEEPSETTINGS get keep-settings-on-reset flag HDIO_GET_32BIT get current io_32bit setting - HDIO_GET_NOWERR get ignore-write-error flag - HDIO_GET_DMA get use-dma flag - HDIO_GET_NICE get nice flags HDIO_GET_IDENTITY get IDE identification info - HDIO_GET_WCACHE get write cache mode on|off - HDIO_GET_ACOUSTIC get acoustic value - HDIO_GET_ADDRESS get sector addressing mode - HDIO_GET_BUSSTATE get the bus state of the hwif - HDIO_TRISTATE_HWIF execute a channel tristate - HDIO_DRIVE_RESET execute a device reset HDIO_DRIVE_TASKFILE execute raw taskfile HDIO_DRIVE_TASK execute task and special drive command HDIO_DRIVE_CMD execute a special drive command - HDIO_DRIVE_CMD_AEB HDIO_DRIVE_TASK ======================= ======================================= ioctls that pass non-pointer values: ======================= ======================================= - HDIO_SET_MULTCOUNT change IDE blockmode - HDIO_SET_UNMASKINTR permit other irqs during I/O - HDIO_SET_KEEPSETTINGS keep ioctl settings on reset HDIO_SET_32BIT change io_32bit flags - HDIO_SET_NOWERR change ignore-write-error flag - HDIO_SET_DMA change use-dma flag - HDIO_SET_PIO_MODE reconfig interface to new speed - HDIO_SCAN_HWIF register and (re)scan interface - HDIO_SET_NICE set nice flags - HDIO_UNREGISTER_HWIF unregister interface - HDIO_SET_WCACHE change write cache enable-disable - HDIO_SET_ACOUSTIC change acoustic behavior - HDIO_SET_BUSSTATE set the bus state of the hwif - HDIO_SET_QDMA change use-qdma flag - HDIO_SET_ADDRESS change lba addressing modes - - HDIO_SET_IDE_SCSI Set scsi emulation mode on/off - HDIO_SET_SCSI_IDE not implemented yet ======================= ======================================= @@ -137,512 +104,49 @@ HDIO_GETGEO - -HDIO_GET_UNMASKINTR - get current unmask setting - - - usage:: - - long val; - - ioctl(fd, HDIO_GET_UNMASKINTR, &val); - - inputs: - none - - - - outputs: - The value of the drive's current unmask setting - - - - - -HDIO_SET_UNMASKINTR - permit other irqs during I/O - - - usage:: - - unsigned long val; - - ioctl(fd, HDIO_SET_UNMASKINTR, val); - - inputs: - New value for unmask flag - - - - outputs: - none - - - - error return: - - EINVAL Called on a partition instead of the whole disk device - - EACCES Access denied: requires CAP_SYS_ADMIN - - EINVAL value out of range [0 1] - - EBUSY Controller busy - - - - -HDIO_GET_MULTCOUNT - get current IDE blockmode setting - - - usage:: - - long val; - - ioctl(fd, HDIO_GET_MULTCOUNT, &val); - - inputs: - none - - - - outputs: - The value of the current IDE block mode setting. This - controls how many sectors the drive will transfer per - interrupt. - - - -HDIO_SET_MULTCOUNT - change IDE blockmode - - - usage:: - - int val; - - ioctl(fd, HDIO_SET_MULTCOUNT, val); - - inputs: - New value for IDE block mode setting. This controls how many - sectors the drive will transfer per interrupt. - - outputs: - none - - - - error return: - - EINVAL Called on a partition instead of the whole disk device - - EACCES Access denied: requires CAP_SYS_ADMIN - - EINVAL value out of range supported by disk. - - EBUSY Controller busy or blockmode already set. - - EIO Drive did not accept new block mode. - - notes: - Source code comments read:: - - This is tightly woven into the driver->do_special cannot - touch. DON'T do it again until a total personality rewrite - is committed. - - If blockmode has already been set, this ioctl will fail with - -EBUSY - - - -HDIO_GET_QDMA - get use-qdma flag - - - Not implemented, as of 2.6.8.1 - - - -HDIO_SET_XFER - set transfer rate via proc - - - Not implemented, as of 2.6.8.1 - - - -HDIO_OBSOLETE_IDENTITY - OBSOLETE, DO NOT USE - - - Same as HDIO_GET_IDENTITY (see below), except that it only - returns the first 142 bytes of drive identity information. - - - -HDIO_GET_IDENTITY - get IDE identification info - - - usage:: - - unsigned char identity[512]; - - ioctl(fd, HDIO_GET_IDENTITY, identity); - - inputs: - none - - - - outputs: - ATA drive identity information. For full description, see - the IDENTIFY DEVICE and IDENTIFY PACKET DEVICE commands in - the ATA specification. - - error returns: - - EINVAL Called on a partition instead of the whole disk device - - ENOMSG IDENTIFY DEVICE information not available - - notes: - Returns information that was obtained when the drive was - probed. Some of this information is subject to change, and - this ioctl does not re-probe the drive to update the - information. - - This information is also available from /proc/ide/hdX/identify - - - -HDIO_GET_KEEPSETTINGS - get keep-settings-on-reset flag - - - usage:: - - long val; - - ioctl(fd, HDIO_GET_KEEPSETTINGS, &val); - - inputs: - none - - - - outputs: - The value of the current "keep settings" flag - - - - notes: - When set, indicates that kernel should restore settings - after a drive reset. - - - -HDIO_SET_KEEPSETTINGS - keep ioctl settings on reset - - - usage:: - - long val; - - ioctl(fd, HDIO_SET_KEEPSETTINGS, val); - - inputs: - New value for keep_settings flag - - - - outputs: - none - - - - error return: - - EINVAL Called on a partition instead of the whole disk device - - EACCES Access denied: requires CAP_SYS_ADMIN - - EINVAL value out of range [0 1] - - EBUSY Controller busy - - - -HDIO_GET_32BIT - get current io_32bit setting - - - usage:: - - long val; - - ioctl(fd, HDIO_GET_32BIT, &val); - - inputs: - none - - - - outputs: - The value of the current io_32bit setting - - - - notes: - 0=16-bit, 1=32-bit, 2,3 = 32bit+sync - - - - - -HDIO_GET_NOWERR - get ignore-write-error flag - - - usage:: - - long val; - - ioctl(fd, HDIO_GET_NOWERR, &val); - - inputs: - none - - - - outputs: - The value of the current ignore-write-error flag - - - - - -HDIO_GET_DMA - get use-dma flag - - - usage:: - - long val; - - ioctl(fd, HDIO_GET_DMA, &val); - - inputs: - none - - - - outputs: - The value of the current use-dma flag - - - - - -HDIO_GET_NICE - get nice flags - - - usage:: - - long nice; - - ioctl(fd, HDIO_GET_NICE, &nice); - - inputs: - none - - - - outputs: - The drive's "nice" values. - - - - notes: - Per-drive flags which determine when the system will give more - bandwidth to other devices sharing the same IDE bus. - - See , near symbol IDE_NICE_DSC_OVERLAP. - - - - -HDIO_SET_NICE - set nice flags - - - usage:: - - unsigned long nice; - - ... - ioctl(fd, HDIO_SET_NICE, nice); - - inputs: - bitmask of nice flags. - - - - outputs: - none - - - - error returns: - - EACCES Access denied: requires CAP_SYS_ADMIN - - EPERM Flags other than DSC_OVERLAP and NICE_1 set. - - EPERM DSC_OVERLAP specified but not supported by drive - - notes: - This ioctl sets the DSC_OVERLAP and NICE_1 flags from values - provided by the user. - - Nice flags are listed in , starting with - IDE_NICE_DSC_OVERLAP. These values represent shifts. - - - - - -HDIO_GET_WCACHE - get write cache mode on|off - - - usage:: - - long val; - - ioctl(fd, HDIO_GET_WCACHE, &val); - - inputs: - none - - - - outputs: - The value of the current write cache mode - - - - - -HDIO_GET_ACOUSTIC - get acoustic value - - - usage:: - - long val; - - ioctl(fd, HDIO_GET_ACOUSTIC, &val); - - inputs: - none - - - - outputs: - The value of the current acoustic settings - - - - notes: - See HDIO_SET_ACOUSTIC - - - - - -HDIO_GET_ADDRESS - usage:: - - - long val; - - ioctl(fd, HDIO_GET_ADDRESS, &val); - - inputs: - none - - - - outputs: - The value of the current addressing mode: - - = =================== - 0 28-bit - 1 48-bit - 2 48-bit doing 28-bit - 3 64-bit - = =================== - - - -HDIO_GET_BUSSTATE - get the bus state of the hwif - - - usage:: - - long state; - - ioctl(fd, HDIO_SCAN_HWIF, &state); - - inputs: - none - - - - outputs: - Current power state of the IDE bus. One of BUSSTATE_OFF, - BUSSTATE_ON, or BUSSTATE_TRISTATE - - error returns: - - EACCES Access denied: requires CAP_SYS_ADMIN - - - - -HDIO_SET_BUSSTATE - set the bus state of the hwif +HDIO_GET_IDENTITY + get IDE identification info usage:: - int state; + unsigned char identity[512]; - ... - ioctl(fd, HDIO_SCAN_HWIF, state); + ioctl(fd, HDIO_GET_IDENTITY, identity); inputs: - Desired IDE power state. One of BUSSTATE_OFF, BUSSTATE_ON, - or BUSSTATE_TRISTATE - - outputs: none - error returns: - - EACCES Access denied: requires CAP_SYS_RAWIO - - EOPNOTSUPP Hardware interface does not support bus power control - - - + outputs: + ATA drive identity information. For full description, see + the IDENTIFY DEVICE and IDENTIFY PACKET DEVICE commands in + the ATA specification. -HDIO_TRISTATE_HWIF - execute a channel tristate + error returns: + - EINVAL Called on a partition instead of the whole disk device + - ENOMSG IDENTIFY DEVICE information not available + notes: + Returns information that was obtained when the drive was + probed. Some of this information is subject to change, and + this ioctl does not re-probe the drive to update the + information. - Not implemented, as of 2.6.8.1. See HDIO_SET_BUSSTATE + This information is also available from /proc/ide/hdX/identify -HDIO_DRIVE_RESET - execute a device reset +HDIO_GET_32BIT + get current io_32bit setting usage:: - int args[3] + long val; - ... - ioctl(fd, HDIO_DRIVE_RESET, args); + ioctl(fd, HDIO_GET_32BIT, &val); inputs: none @@ -650,22 +154,12 @@ HDIO_DRIVE_RESET outputs: - none - + The value of the current io_32bit setting - error returns: - - EACCES Access denied: requires CAP_SYS_ADMIN - - ENXIO No such device: phy dead or ctl_addr == 0 - - EIO I/O error: reset timed out or hardware error notes: - - - Execute a reset on the device as soon as the current IO - operation has completed. - - - Executes an ATAPI soft reset if applicable, otherwise - executes an ATA soft reset on the controller. + 0=16-bit, 1=32-bit, 2,3 = 32bit+sync @@ -1026,14 +520,6 @@ HDIO_DRIVE_TASK -HDIO_DRIVE_CMD_AEB - HDIO_DRIVE_TASK - - - Not implemented, as of 2.6.8.1 - - - HDIO_SET_32BIT change io_32bit flags @@ -1059,284 +545,3 @@ HDIO_SET_32BIT - EACCES Access denied: requires CAP_SYS_ADMIN - EINVAL value out of range [0 3] - EBUSY Controller busy - - - - -HDIO_SET_NOWERR - change ignore-write-error flag - - - usage:: - - int val; - - ioctl(fd, HDIO_SET_NOWERR, val); - - inputs: - New value for ignore-write-error flag. Used for ignoring - - - WRERR_STAT - - outputs: - none - - - - error return: - - EINVAL Called on a partition instead of the whole disk device - - EACCES Access denied: requires CAP_SYS_ADMIN - - EINVAL value out of range [0 1] - - EBUSY Controller busy - - - -HDIO_SET_DMA - change use-dma flag - - - usage:: - - long val; - - ioctl(fd, HDIO_SET_DMA, val); - - inputs: - New value for use-dma flag - - - - outputs: - none - - - - error return: - - EINVAL Called on a partition instead of the whole disk device - - EACCES Access denied: requires CAP_SYS_ADMIN - - EINVAL value out of range [0 1] - - EBUSY Controller busy - - - -HDIO_SET_PIO_MODE - reconfig interface to new speed - - - usage:: - - long val; - - ioctl(fd, HDIO_SET_PIO_MODE, val); - - inputs: - New interface speed. - - - - outputs: - none - - - - error return: - - EINVAL Called on a partition instead of the whole disk device - - EACCES Access denied: requires CAP_SYS_ADMIN - - EINVAL value out of range [0 255] - - EBUSY Controller busy - - - -HDIO_SCAN_HWIF - register and (re)scan interface - - - usage:: - - int args[3] - - ... - ioctl(fd, HDIO_SCAN_HWIF, args); - - inputs: - - ======= ========================= - args[0] io address to probe - - - args[1] control address to probe - args[2] irq number - ======= ========================= - - outputs: - none - - - - error returns: - - EACCES Access denied: requires CAP_SYS_RAWIO - - EIO Probe failed. - - notes: - This ioctl initializes the addresses and irq for a disk - controller, probes for drives, and creates /proc/ide - interfaces as appropriate. - - - -HDIO_UNREGISTER_HWIF - unregister interface - - - usage:: - - int index; - - ioctl(fd, HDIO_UNREGISTER_HWIF, index); - - inputs: - index index of hardware interface to unregister - - - - outputs: - none - - - - error returns: - - EACCES Access denied: requires CAP_SYS_RAWIO - - notes: - This ioctl removes a hardware interface from the kernel. - - Currently (2.6.8) this ioctl silently fails if any drive on - the interface is busy. - - - -HDIO_SET_WCACHE - change write cache enable-disable - - - usage:: - - int val; - - ioctl(fd, HDIO_SET_WCACHE, val); - - inputs: - New value for write cache enable - - - - outputs: - none - - - - error return: - - EINVAL Called on a partition instead of the whole disk device - - EACCES Access denied: requires CAP_SYS_ADMIN - - EINVAL value out of range [0 1] - - EBUSY Controller busy - - - -HDIO_SET_ACOUSTIC - change acoustic behavior - - - usage:: - - int val; - - ioctl(fd, HDIO_SET_ACOUSTIC, val); - - inputs: - New value for drive acoustic settings - - - - outputs: - none - - - - error return: - - EINVAL Called on a partition instead of the whole disk device - - EACCES Access denied: requires CAP_SYS_ADMIN - - EINVAL value out of range [0 254] - - EBUSY Controller busy - - - -HDIO_SET_QDMA - change use-qdma flag - - - Not implemented, as of 2.6.8.1 - - - -HDIO_SET_ADDRESS - change lba addressing modes - - - usage:: - - int val; - - ioctl(fd, HDIO_SET_ADDRESS, val); - - inputs: - New value for addressing mode - - = =================== - 0 28-bit - 1 48-bit - 2 48-bit doing 28-bit - = =================== - - outputs: - none - - - - error return: - - EINVAL Called on a partition instead of the whole disk device - - EACCES Access denied: requires CAP_SYS_ADMIN - - EINVAL value out of range [0 2] - - EBUSY Controller busy - - EIO Drive does not support lba48 mode. - - -HDIO_SET_IDE_SCSI - usage:: - - - long val; - - ioctl(fd, HDIO_SET_IDE_SCSI, val); - - inputs: - New value for scsi emulation mode (?) - - - - outputs: - none - - - - error return: - - EINVAL Called on a partition instead of the whole disk device - - EACCES Access denied: requires CAP_SYS_ADMIN - - EINVAL value out of range [0 1] - - EBUSY Controller busy - - - -HDIO_SET_SCSI_IDE - Not implemented, as of 2.6.8.1 diff --git a/MAINTAINERS b/MAINTAINERS index 008fcad7ac00..4f3a7e3ce93f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8763,22 +8763,6 @@ L: linux-i2c@vger.kernel.org S: Maintained F: drivers/i2c/busses/i2c-icy.c -IDE SUBSYSTEM -M: "David S. Miller" -L: linux-ide@vger.kernel.org -S: Maintained -Q: http://patchwork.ozlabs.org/project/linux-ide/list/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide.git -F: Documentation/ide/ -F: drivers/ide/ -F: include/linux/ide.h - -IDE/ATAPI DRIVERS -L: linux-ide@vger.kernel.org -S: Orphan -F: Documentation/cdrom/ide-cd.rst -F: drivers/ide/ide-cd* - IDEAPAD LAPTOP EXTRAS DRIVER M: Ike Panhc L: platform-driver-x86@vger.kernel.org diff --git a/drivers/Kconfig b/drivers/Kconfig index 47980c6b1945..8bad63417a50 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -33,8 +33,6 @@ source "drivers/nvme/Kconfig" source "drivers/misc/Kconfig" -source "drivers/ide/Kconfig" - source "drivers/scsi/Kconfig" source "drivers/ata/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 5a6d613e868d..f85185f9139e 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -78,7 +78,6 @@ obj-$(CONFIG_CXL_BUS) += cxl/ obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/ obj-$(CONFIG_NUBUS) += nubus/ obj-y += macintosh/ -obj-$(CONFIG_IDE) += ide/ obj-y += scsi/ obj-y += nvme/ obj-$(CONFIG_ATA) += ata/ diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig deleted file mode 100644 index 8af1ac69e5f8..000000000000 --- a/drivers/ide/Kconfig +++ /dev/null @@ -1,827 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# IDE ATA ATAPI Block device driver configuration -# - -# Select HAVE_IDE if IDE is supported -config HAVE_IDE - bool - -menuconfig IDE - tristate "ATA/ATAPI/MFM/RLL support (DEPRECATED)" - depends on HAVE_IDE - depends on BLOCK - select BLK_SCSI_REQUEST - help - If you say Y here, your kernel will be able to manage ATA/(E)IDE and - ATAPI units. The most common cases are IDE hard drives and ATAPI - CD-ROM drives. - - This subsystem is currently in maintenance mode with only bug fix - changes applied. Users of ATA hardware are encouraged to migrate to - the newer ATA subsystem ("Serial ATA (prod) and Parallel ATA - (experimental) drivers") which is more actively maintained. - - To compile this driver as a module, choose M here: the - module will be called ide-core. - - For further information, please read . - - If unsure, say N. - -if IDE - -comment "Please see Documentation/ide/ide.rst for help/info on IDE drives" - -config IDE_XFER_MODE - bool - -config IDE_TIMINGS - bool - select IDE_XFER_MODE - -config IDE_ATAPI - bool - -config IDE_LEGACY - bool - -config BLK_DEV_IDE_SATA - bool "Support for SATA (deprecated; conflicts with libata SATA driver)" - default n - help - There are two drivers for Serial ATA controllers. - - The main driver, "libata", uses the SCSI subsystem - and supports most modern SATA controllers. In order to use it - you may take a look at "Serial ATA (prod) and Parallel ATA - (experimental) drivers". - - The IDE driver (which you are currently configuring) supports - a few first-generation SATA controllers. - - In order to eliminate conflicts between the two subsystems, - this config option enables the IDE driver's SATA support. - Normally this is disabled, as it is preferred that libata - supports SATA controllers, and this (IDE) driver supports - PATA controllers. - - If unsure, say N. - -config IDE_GD - tristate "generic ATA/ATAPI disk support" - default y - help - Support for ATA/ATAPI disks (including ATAPI floppy drives). - - To compile this driver as a module, choose M here. - The module will be called ide-gd_mod. - - If unsure, say Y. - -config IDE_GD_ATA - bool "ATA disk support" - depends on IDE_GD - default y - help - This will include support for ATA hard disks. - - If unsure, say Y. - -config IDE_GD_ATAPI - bool "ATAPI floppy support" - depends on IDE_GD - select IDE_ATAPI - help - This will include support for ATAPI floppy drives - (i.e. Iomega ZIP or MKE LS-120). - - For information about jumper settings and the question - of when a ZIP drive uses a partition table, see - . - - If unsure, say N. - -config BLK_DEV_IDECS - tristate "PCMCIA IDE support" - depends on PCMCIA - help - Support for Compact Flash cards, outboard IDE disks, tape drives, - and CD-ROM drives connected through a PCMCIA card. - -config BLK_DEV_DELKIN - tristate "Cardbus IDE support (Delkin/ASKA/Workbit)" - depends on CARDBUS && PCI - help - Support for Delkin, ASKA, and Workbit Cardbus CompactFlash - Adapters. This may also work for similar SD and XD adapters. - -config BLK_DEV_IDECD - tristate "Include IDE/ATAPI CDROM support" - depends on BLK_DEV - select IDE_ATAPI - select CDROM - help - If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is - a newer protocol used by IDE CD-ROM and TAPE drives, similar to the - SCSI protocol. Most new CD-ROM drives use ATAPI, including the - NEC-260, Mitsumi FX400, Sony 55E, and just about all non-SCSI - double(2X) or better speed drives. - - If you say Y here, the CD-ROM drive will be identified at boot time - along with other IDE devices, as "hdb" or "hdc", or something - similar (check the boot messages with dmesg). If this is your only - CD-ROM drive, you can say N to all other CD-ROM options, but be sure - to say Y or M to "ISO 9660 CD-ROM file system support". - - To compile this driver as a module, choose M here: the - module will be called ide-cd. - -config BLK_DEV_IDECD_VERBOSE_ERRORS - bool "Verbose error logging for IDE/ATAPI CDROM driver" if EXPERT - depends on BLK_DEV_IDECD - default y - help - Turn this on to have the driver print out the meanings of the - ATAPI error codes. This will use up additional 8kB of kernel-space - memory, though. - -config BLK_DEV_IDETAPE - tristate "Include IDE/ATAPI TAPE support" - select IDE_ATAPI - help - If you have an IDE tape drive using the ATAPI protocol, say Y. - ATAPI is a newer protocol used by IDE tape and CD-ROM drives, - similar to the SCSI protocol. If you have an SCSI tape drive - however, you can say N here. - - You should also say Y if you have an OnStream DI-30 tape drive; this - will not work with the SCSI protocol, until there is support for the - SC-30 and SC-50 versions. - - If you say Y here, the tape drive will be identified at boot time - along with other IDE devices, as "hdb" or "hdc", or something - similar, and will be mapped to a character device such as "ht0" - (check the boot messages with dmesg). Be sure to consult the - and - files for usage information. - - To compile this driver as a module, choose M here: the - module will be called ide-tape. - -config BLK_DEV_IDEACPI - bool "IDE ACPI support" - depends on ACPI - help - Implement ACPI support for generic IDE devices. On modern - machines ACPI support is required to properly handle ACPI S3 states. - -config IDE_TASK_IOCTL - bool "IDE Taskfile Access" - help - This is a direct raw access to the media. It is a complex but - elegant solution to test and validate the domain of the hardware and - perform below the driver data recovery if needed. This is the most - basic form of media-forensics. - - If you are unsure, say N here. - -config IDE_PROC_FS - bool "legacy /proc/ide/ support" - depends on IDE && PROC_FS - default y - help - This option enables support for the various files in - /proc/ide. In Linux 2.6 this has been superseded by - files in sysfs but many legacy applications rely on this. - - If unsure say Y. - -comment "IDE chipset support/bugfixes" - -config IDE_GENERIC - tristate "generic/default IDE chipset support" - depends on ALPHA || X86 || IA64 || MIPS || ARCH_RPC - default ARM && ARCH_RPC - help - This is the generic IDE driver. This driver attaches to the - fixed legacy ports (e.g. on PCs 0x1f0/0x170, 0x1e8/0x168 and - so on). Please note that if this driver is built into the - kernel or loaded before other ATA (IDE or libata) drivers - and the controller is located at legacy ports, this driver - may grab those ports and thus can prevent the controller - specific driver from attaching. - - Also, currently, IDE generic doesn't allow IRQ sharing - meaning that the IRQs it grabs won't be available to other - controllers sharing those IRQs which usually makes drivers - for those controllers fail. Generally, it's not a good idea - to load IDE generic driver on modern systems. - - If unsure, say N. - -config BLK_DEV_PLATFORM - tristate "Platform driver for IDE interfaces" - help - This is the platform IDE driver, used mostly for Memory Mapped - IDE devices, like Compact Flashes running in True IDE mode. - - If unsure, say N. - -config BLK_DEV_CMD640 - tristate "CMD640 chipset bugfix/support" - depends on X86 - select IDE_TIMINGS - help - The CMD-Technologies CMD640 IDE chip is used on many common 486 and - Pentium motherboards, usually in combination with a "Neptune" or - "SiS" chipset. Unfortunately, it has a number of rather nasty - design flaws that can cause severe data corruption under many common - conditions. Say Y here to include code which tries to automatically - detect and correct the problems under Linux. This option also - enables access to the secondary IDE ports in some CMD640 based - systems. - - This driver will work automatically in PCI based systems (most new - systems have PCI slots). But if your system uses VESA local bus - (VLB) instead of PCI, you must also supply a kernel boot parameter - to enable the CMD640 bugfix/support: "cmd640.probe_vlb". (Try "man - bootparam" or see the documentation of your boot loader about how to - pass options to the kernel.) - - The CMD640 chip is also used on add-in cards by Acculogic, and on - the "CSA-6400E PCI to IDE controller" that some people have. For - details, read . - -config BLK_DEV_CMD640_ENHANCED - bool "CMD640 enhanced support" - depends on BLK_DEV_CMD640 - help - This option includes support for setting/autotuning PIO modes and - prefetch on CMD640 IDE interfaces. For details, read - . If you have a CMD640 IDE interface - and your BIOS does not already do this for you, then say Y here. - Otherwise say N. - -config BLK_DEV_IDEPNP - tristate "PNP EIDE support" - depends on PNP - help - If you have a PnP (Plug and Play) compatible EIDE card and - would like the kernel to automatically detect and activate - it, say Y here. - -config BLK_DEV_IDEDMA_SFF - bool - -if PCI - -comment "PCI IDE chipsets support" - -config BLK_DEV_IDEPCI - bool - -config IDEPCI_PCIBUS_ORDER - bool "Probe IDE PCI devices in the PCI bus order (DEPRECATED)" - depends on IDE=y && BLK_DEV_IDEPCI - default y - help - Probe IDE PCI devices in the order in which they appear on the - PCI bus (i.e. 00:1f.1 PCI device before 02:01.0 PCI device) - instead of the order in which IDE PCI host drivers are loaded. - - Please note that this method of assuring stable naming of - IDE devices is unreliable and use other means for achieving - it (i.e. udev). - - If in doubt, say N. - -# TODO: split it on per host driver config options (or module parameters) -config BLK_DEV_OFFBOARD - bool "Boot off-board chipsets first support (DEPRECATED)" - depends on BLK_DEV_IDEPCI && (BLK_DEV_AEC62XX || BLK_DEV_GENERIC || BLK_DEV_HPT366 || BLK_DEV_PDC202XX_NEW || BLK_DEV_PDC202XX_OLD || BLK_DEV_TC86C001) - help - Normally, IDE controllers built into the motherboard (on-board - controllers) are assigned to ide0 and ide1 while those on add-in PCI - cards (off-board controllers) are relegated to ide2 and ide3. - Answering Y here will allow you to reverse the situation, with - off-board controllers on ide0/1 and on-board controllers on ide2/3. - This can improve the usability of some boot managers such as lilo - when booting from a drive on an off-board controller. - - Note that, if you do this, the order of the hd* devices will be - rearranged which may require modification of fstab and other files. - - Please also note that this method of assuring stable naming of - IDE devices is unreliable and use other means for achieving it - (i.e. udev). - - If in doubt, say N. - -config BLK_DEV_GENERIC - tristate "Generic PCI IDE Chipset Support" - select BLK_DEV_IDEPCI - help - This option provides generic support for various PCI IDE Chipsets - which otherwise might not be supported. - -config BLK_DEV_OPTI621 - tristate "OPTi 82C621 chipset enhanced support" - select BLK_DEV_IDEPCI - help - This is a driver for the OPTi 82C621 EIDE controller. - Please read the comments at the top of . - -config BLK_DEV_RZ1000 - tristate "RZ1000 chipset bugfix/support" - depends on X86 - select BLK_DEV_IDEPCI - help - The PC-Technologies RZ1000 IDE chip is used on many common 486 and - Pentium motherboards, usually along with the "Neptune" chipset. - Unfortunately, it has a rather nasty design flaw that can cause - severe data corruption under many conditions. Say Y here to include - code which automatically detects and corrects the problem under - Linux. This may slow disk throughput by a few percent, but at least - things will operate 100% reliably. - -config BLK_DEV_IDEDMA_PCI - bool - select BLK_DEV_IDEPCI - select BLK_DEV_IDEDMA_SFF - -config BLK_DEV_AEC62XX - tristate "AEC62XX chipset support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds explicit support for Acard AEC62xx (Artop ATP8xx) - IDE controllers. This allows the kernel to change PIO, DMA and UDMA - speeds and to configure the chip to optimum performance. - -config BLK_DEV_ALI15X3 - tristate "ALI M15x3 chipset support" - select IDE_TIMINGS - select BLK_DEV_IDEDMA_PCI - help - This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C - onboard chipsets. It also tests for Simplex mode and enables - normal dual channel support. - - Please read the comments at the top of - . - - If unsure, say N. - -config BLK_DEV_AMD74XX - tristate "AMD and nVidia IDE support" - depends on !ARM - select IDE_TIMINGS - select BLK_DEV_IDEDMA_PCI - help - This driver adds explicit support for AMD-7xx and AMD-8111 chips - and also for the nVidia nForce chip. This allows the kernel to - change PIO, DMA and UDMA speeds and to configure the chip to - optimum performance. - -config BLK_DEV_ATIIXP - tristate "ATI IXP chipset IDE support" - depends on X86 - select BLK_DEV_IDEDMA_PCI - help - This driver adds explicit support for ATI IXP chipset. - This allows the kernel to change PIO, DMA and UDMA speeds - and to configure the chip to optimum performance. - - Say Y here if you have an ATI IXP chipset IDE controller. - -config BLK_DEV_CMD64X - tristate "CMD64{3|6|8|9} chipset support" - select IDE_TIMINGS - select BLK_DEV_IDEDMA_PCI - help - Say Y here if you have an IDE controller which uses any of these - chipsets: CMD643, CMD646, or CMD648. - -config BLK_DEV_TRIFLEX - tristate "Compaq Triflex IDE support" - select BLK_DEV_IDEDMA_PCI - help - Say Y here if you have a Compaq Triflex IDE controller, such - as those commonly found on Compaq Pentium-Pro systems - -config BLK_DEV_CY82C693 - tristate "CY82C693 chipset support" - depends on ALPHA - select IDE_TIMINGS - select BLK_DEV_IDEDMA_PCI - help - This driver adds detection and support for the CY82C693 chipset - used on Digital's PC-Alpha 164SX boards. - -config BLK_DEV_CS5520 - tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)" - depends on X86_32 || COMPILE_TEST - select BLK_DEV_IDEDMA_PCI - help - Include support for PIO tuning and virtual DMA on the Cyrix MediaGX - 5510/5520 chipset. This will automatically be detected and - configured if found. - - It is safe to say Y to this question. - -config BLK_DEV_CS5530 - tristate "Cyrix/National Semiconductor CS5530 MediaGX chipset support" - depends on X86_32 || COMPILE_TEST - select BLK_DEV_IDEDMA_PCI - help - Include support for UDMA on the Cyrix MediaGX 5530 chipset. This - will automatically be detected and configured if found. - - It is safe to say Y to this question. - -config BLK_DEV_CS5535 - tristate "AMD CS5535 chipset support" - depends on X86_32 - select BLK_DEV_IDEDMA_PCI - help - Include support for UDMA on the NSC/AMD CS5535 companion chipset. - This will automatically be detected and configured if found. - - It is safe to say Y to this question. - -config BLK_DEV_CS5536 - tristate "CS5536 chipset support" - depends on X86_32 - select BLK_DEV_IDEDMA_PCI - help - This option enables support for the AMD CS5536 - companion chip used with the Geode LX processor family. - - If unsure, say N. - -config BLK_DEV_HPT366 - tristate "HPT36X/37X chipset support" - select BLK_DEV_IDEDMA_PCI - help - HPT366 is an Ultra DMA chipset for ATA-66. - HPT368 is an Ultra DMA chipset for ATA-66 RAID Based. - HPT370 is an Ultra DMA chipset for ATA-100. - HPT372 is an Ultra DMA chipset for ATA-100. - HPT374 is an Ultra DMA chipset for ATA-100. - - This driver adds up to 4 more EIDE devices sharing a single - interrupt. - - The HPT366 chipset in its current form is bootable. One solution - for this problem are special LILO commands for redirecting the - reference to device 0x80. The other solution is to say Y to "Boot - off-board chipsets first support" (CONFIG_BLK_DEV_OFFBOARD) unless - your mother board has the chipset natively mounted. Regardless one - should use the fore mentioned option and call at LILO. - - This driver requires dynamic tuning of the chipset during the - ide-probe at boot. It is reported to support DVD II drives, by the - manufacturer. - -config BLK_DEV_JMICRON - tristate "JMicron JMB36x support" - select BLK_DEV_IDEDMA_PCI - help - Basic support for the JMicron ATA controllers. For full support - use the libata drivers. - -config BLK_DEV_SC1200 - tristate "National SCx200 chipset support" - depends on X86_32 || COMPILE_TEST - select BLK_DEV_IDEDMA_PCI - help - This driver adds support for the on-board IDE controller on the - National SCx200 series of embedded x86 "Geode" systems. - -config BLK_DEV_PIIX - tristate "Intel PIIX/ICH chipsets support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds explicit support for Intel PIIX and ICH chips. - This allows the kernel to change PIO, DMA and UDMA speeds and to - configure the chip to optimum performance. - -config BLK_DEV_IT8172 - tristate "IT8172 IDE support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds support for the IDE controller on the - IT8172 System Controller. - -config BLK_DEV_IT8213 - tristate "IT8213 IDE support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds support for the ITE 8213 IDE controller. - -config BLK_DEV_IT821X - tristate "IT821X IDE support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds support for the ITE 8211 IDE controller and the - IT 8212 IDE RAID controller in both RAID and pass-through mode. - -config BLK_DEV_NS87415 - tristate "NS87415 chipset support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds detection and support for the NS87415 chip - (used mainly on SPARC64 and PA-RISC machines). - - Please read the comments at the top of . - -config BLK_DEV_PDC202XX_OLD - tristate "PROMISE PDC202{46|62|65|67} support" - select BLK_DEV_IDEDMA_PCI - help - Promise Ultra33 or PDC20246 - Promise Ultra66 or PDC20262 - Promise Ultra100 or PDC20265/PDC20267/PDC20268 - - This driver adds up to 4 more EIDE devices sharing a single - interrupt. This add-on card is a bootable PCI UDMA controller. Since - multiple cards can be installed and there are BIOS ROM problems that - happen if the BIOS revisions of all installed cards (three-max) do - not match, the driver attempts to do dynamic tuning of the chipset - at boot-time for max-speed. Ultra33 BIOS 1.25 or newer is required - for more than one card. - - Please read the comments at the top of - . - - If unsure, say N. - -config BLK_DEV_PDC202XX_NEW - tristate "PROMISE PDC202{68|69|70|71|75|76|77} support" - select BLK_DEV_IDEDMA_PCI - -config BLK_DEV_SVWKS - tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5 - chipsets. - -config BLK_DEV_SIIMAGE - tristate "Silicon Image chipset support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds PIO/(U)DMA support for the SI CMD680 and SII - 3112 (Serial ATA) chips. - -config BLK_DEV_SIS5513 - tristate "SiS5513 chipset support" - depends on X86 - select BLK_DEV_IDEDMA_PCI - help - This driver ensures (U)DMA support for SIS5513 chipset family based - mainboards. - - The following chipsets are supported: - ATA16: SiS5511, SiS5513 - ATA33: SiS5591, SiS5597, SiS5598, SiS5600 - ATA66: SiS530, SiS540, SiS620, SiS630, SiS640 - ATA100: SiS635, SiS645, SiS650, SiS730, SiS735, SiS740, - SiS745, SiS750 - - Please read the comments at the top of . - -config BLK_DEV_SL82C105 - tristate "Winbond SL82c105 support" - depends on (PPC || ARM) - select IDE_TIMINGS - select BLK_DEV_IDEDMA_PCI - help - If you have a Winbond SL82c105 IDE controller, say Y here to enable - special configuration for this chip. This is common on various CHRP - motherboards, but could be used elsewhere. If in doubt, say Y. - -config BLK_DEV_SLC90E66 - tristate "SLC90E66 chipset support" - select BLK_DEV_IDEDMA_PCI - help - This driver ensures (U)DMA support for Victory66 SouthBridges for - SMsC with Intel NorthBridges. This is an Ultra66 based chipset. - The nice thing about it is that you can mix Ultra/DMA/PIO devices - and it will handle timing cycles. Since this is an improved - look-a-like to the PIIX4 it should be a nice addition. - - Please read the comments at the top of - . - -config BLK_DEV_TRM290 - tristate "Tekram TRM290 chipset support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds support for bus master DMA transfers - using the Tekram TRM290 PCI IDE chip. Volunteers are - needed for further tweaking and development. - Please read the comments at the top of . - -config BLK_DEV_VIA82CXXX - tristate "VIA82CXXX chipset support" - select IDE_TIMINGS - select BLK_DEV_IDEDMA_PCI - help - This driver adds explicit support for VIA BusMastering IDE chips. - This allows the kernel to change PIO, DMA and UDMA speeds and to - configure the chip to optimum performance. - -config BLK_DEV_TC86C001 - tristate "Toshiba TC86C001 support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds support for Toshiba TC86C001 GOKU-S chip. - -endif - -# TODO: BLK_DEV_IDEDMA_PCI -> BLK_DEV_IDEDMA_SFF -config BLK_DEV_IDE_PMAC - tristate "PowerMac on-board IDE support" - depends on PPC_PMAC - select IDE_TIMINGS - select BLK_DEV_IDEDMA_PCI - help - This driver provides support for the on-board IDE controller on - most of the recent Apple Power Macintoshes and PowerBooks. - If unsure, say Y. - -config BLK_DEV_IDE_PMAC_ATA100FIRST - bool "Probe on-board ATA/100 (Kauai) first" - depends on BLK_DEV_IDE_PMAC - help - This option will cause the ATA/100 controller found in UniNorth2 - based machines (Windtunnel PowerMac, Aluminium PowerBooks, ...) - to be probed before the ATA/66 and ATA/33 controllers. Without - these, those machine used to have the hard disk on hdc and the - CD-ROM on hda. This option changes this to more natural hda for - hard disk and hdc for CD-ROM. - -config BLK_DEV_IDE_TX4938 - tristate "TX4938 internal IDE support" - depends on SOC_TX4938 - select IDE_TIMINGS - -config BLK_DEV_IDE_TX4939 - tristate "TX4939 internal IDE support" - depends on SOC_TX4939 - select BLK_DEV_IDEDMA_SFF - -config BLK_DEV_IDE_ICSIDE - tristate "ICS IDE interface support" - depends on ARM && ARCH_ACORN - help - On Acorn systems, say Y here if you wish to use the ICS IDE - interface card. This is not required for ICS partition support. - If you are unsure, say N to this. - -config BLK_DEV_IDEDMA_ICS - bool "ICS DMA support" - depends on BLK_DEV_IDE_ICSIDE - help - Say Y here if you want to add DMA (Direct Memory Access) support to - the ICS IDE driver. - -config BLK_DEV_IDE_RAPIDE - tristate "RapIDE interface support" - depends on ARM && ARCH_ACORN - help - Say Y here if you want to support the Yellowstone RapIDE controller - manufactured for use with Acorn computers. - -config BLK_DEV_GAYLE - tristate "Amiga Gayle IDE interface support" - depends on AMIGA - help - This is the IDE driver for the Amiga Gayle IDE interface. It supports - both the `A1200 style' and `A4000 style' of the Gayle IDE interface, - This includes on-board IDE interfaces on some Amiga models (A600, - A1200, A4000, and A4000T), and IDE interfaces on the Zorro expansion - bus (M-Tech E-Matrix 530 expansion card). - - It also provides support for the so-called `IDE doublers' (made - by various manufacturers, e.g. Eyetech) that can be connected to - the on-board IDE interface of some Amiga models. Using such an IDE - doubler, you can connect up to four instead of two IDE devices to - the Amiga's on-board IDE interface. The feature is enabled at kernel - runtime using the "gayle.doubler" kernel boot parameter. - - Say Y if you have an Amiga with a Gayle IDE interface and want to use - IDE devices (hard disks, CD-ROM drives, etc.) that are connected to - it. - - Note that you also have to enable Zorro bus support if you want to - use Gayle IDE interfaces on the Zorro expansion bus. - -config BLK_DEV_BUDDHA - tristate "Buddha/Catweasel/X-Surf IDE interface support" - depends on ZORRO - help - This is the IDE driver for the IDE interfaces on the Buddha, Catweasel - and X-Surf expansion boards. It supports up to two interfaces on the - Buddha, three on the Catweasel and two on the X-Surf. - - Say Y if you have a Buddha or Catweasel expansion board and want to - use IDE devices (hard disks, CD-ROM drives, etc.) that are connected - to one of its IDE interfaces. - -config BLK_DEV_FALCON_IDE - tristate "Falcon and Q40/Q60 IDE interface support" - depends on ATARI || Q40 - help - This is the IDE driver for the on-board IDE interface on the Atari - Falcon and Q40/Q60. Say Y if you have such a machine and want to use - IDE devices (hard disks, CD-ROM drives, etc.) that are connected to - the on-board IDE interface. - -config BLK_DEV_PALMCHIP_BK3710 - tristate "Palmchip bk3710 IDE controller support" - depends on ARCH_DAVINCI - select IDE_TIMINGS - select BLK_DEV_IDEDMA_SFF - help - Say Y here if you want to support the onchip IDE controller on the - TI DaVinci SoC - -# no isa -> no vlb -if ISA && (ALPHA || X86 || MIPS) - -comment "Other IDE chipsets support" -comment "Note: most of these also require special kernel boot parameters" - -config BLK_DEV_4DRIVES - tristate "Generic 4 drives/port support" - help - Certain older chipsets, including the Tekram 690CD, use a single set - of I/O ports at 0x1f0 to control up to four drives, instead of the - customary two drives per port. Support for this can be enabled at - runtime using the "ide-4drives.probe" kernel boot parameter if you - say Y here. - -config BLK_DEV_ALI14XX - tristate "ALI M14xx support" - select IDE_TIMINGS - select IDE_LEGACY - help - This driver is enabled at runtime using the "ali14xx.probe" kernel - boot parameter. It enables support for the secondary IDE interface - of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster - I/O speeds to be set as well. - See the files and - for more info. - -config BLK_DEV_DTC2278 - tristate "DTC-2278 support" - select IDE_XFER_MODE - select IDE_LEGACY - help - This driver is enabled at runtime using the "dtc2278.probe" kernel - boot parameter. It enables support for the secondary IDE interface - of the DTC-2278 card, and permits faster I/O speeds to be set as - well. See the and - files for more info. - -config BLK_DEV_HT6560B - tristate "Holtek HT6560B support" - select IDE_TIMINGS - select IDE_LEGACY - help - This driver is enabled at runtime using the "ht6560b.probe" kernel - boot parameter. It enables support for the secondary IDE interface - of the Holtek card, and permits faster I/O speeds to be set as well. - See the and - files for more info. - -config BLK_DEV_QD65XX - tristate "QDI QD65xx support" - select IDE_TIMINGS - select IDE_LEGACY - help - This driver is enabled at runtime using the "qd65xx.probe" kernel - boot parameter. It permits faster I/O speeds to be set. See the - and - for more info. - -config BLK_DEV_UMC8672 - tristate "UMC-8672 support" - select IDE_XFER_MODE - select IDE_LEGACY - help - This driver is enabled at runtime using the "umc8672.probe" kernel - boot parameter. It enables support for the secondary IDE interface - of the UMC-8672, and permits faster I/O speeds to be set as well. - See the files and - for more info. - -endif - -config BLK_DEV_IDEDMA - def_bool BLK_DEV_IDEDMA_SFF || BLK_DEV_IDEDMA_ICS - select IDE_XFER_MODE - -endif # IDE diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile deleted file mode 100644 index 991eb72a786b..000000000000 --- a/drivers/ide/Makefile +++ /dev/null @@ -1,109 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# link order is important here -# - -ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \ - ide-taskfile.o ide-pm.o ide-park.o ide-sysfs.o ide-devsets.o \ - ide-io-std.o ide-eh.o - -# core IDE code -ide-core-$(CONFIG_IDE_XFER_MODE) += ide-pio-blacklist.o ide-xfer-mode.o -ide-core-$(CONFIG_IDE_TIMINGS) += ide-timings.o -ide-core-$(CONFIG_IDE_ATAPI) += ide-atapi.o -ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o -ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o -ide-core-$(CONFIG_BLK_DEV_IDEDMA_SFF) += ide-dma-sff.o -ide-core-$(CONFIG_IDE_PROC_FS) += ide-proc.o -ide-core-$(CONFIG_BLK_DEV_IDEACPI) += ide-acpi.o -ide-core-$(CONFIG_IDE_LEGACY) += ide-legacy.o - -obj-$(CONFIG_IDE) += ide-core.o - -obj-$(CONFIG_BLK_DEV_ALI14XX) += ali14xx.o -obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o -obj-$(CONFIG_BLK_DEV_DTC2278) += dtc2278.o -obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o -obj-$(CONFIG_BLK_DEV_QD65XX) += qd65xx.o -obj-$(CONFIG_BLK_DEV_4DRIVES) += ide-4drives.o - -obj-$(CONFIG_BLK_DEV_GAYLE) += gayle.o -obj-$(CONFIG_BLK_DEV_FALCON_IDE) += falconide.o -obj-$(CONFIG_BLK_DEV_BUDDHA) += buddha.o - -obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o -obj-$(CONFIG_BLK_DEV_ALI15X3) += alim15x3.o -obj-$(CONFIG_BLK_DEV_AMD74XX) += amd74xx.o -obj-$(CONFIG_BLK_DEV_ATIIXP) += atiixp.o -obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o -obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o -obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o -obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o -obj-$(CONFIG_BLK_DEV_CS5536) += cs5536.o -obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o -obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o -obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o -obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o -obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o -obj-$(CONFIG_BLK_DEV_IT8213) += it8213.o -obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o -obj-$(CONFIG_BLK_DEV_JMICRON) += jmicron.o -obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o -obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o -obj-$(CONFIG_BLK_DEV_PDC202XX_OLD) += pdc202xx_old.o -obj-$(CONFIG_BLK_DEV_PDC202XX_NEW) += pdc202xx_new.o -obj-$(CONFIG_BLK_DEV_PIIX) += piix.o -obj-$(CONFIG_BLK_DEV_RZ1000) += rz1000.o -obj-$(CONFIG_BLK_DEV_SVWKS) += serverworks.o -obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimage.o -obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o -obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o -obj-$(CONFIG_BLK_DEV_SLC90E66) += slc90e66.o -obj-$(CONFIG_BLK_DEV_TC86C001) += tc86c001.o -obj-$(CONFIG_BLK_DEV_TRIFLEX) += triflex.o -obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o -obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o - -# Must appear at the end of the block -obj-$(CONFIG_BLK_DEV_GENERIC) += ide-pci-generic.o - -obj-$(CONFIG_IDEPCI_PCIBUS_ORDER) += ide-scan-pci.o - -obj-$(CONFIG_BLK_DEV_CMD640) += cmd640.o - -obj-$(CONFIG_BLK_DEV_IDE_PMAC) += pmac.o - -obj-$(CONFIG_IDE_GENERIC) += ide-generic.o -obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o - -ide-gd_mod-y += ide-gd.o -ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o - -ifeq ($(CONFIG_IDE_GD_ATA), y) - ide-gd_mod-y += ide-disk.o ide-disk_ioctl.o -ifeq ($(CONFIG_IDE_PROC_FS), y) - ide-gd_mod-y += ide-disk_proc.o -endif -endif - -ifeq ($(CONFIG_IDE_GD_ATAPI), y) - ide-gd_mod-y += ide-floppy.o ide-floppy_ioctl.o -ifeq ($(CONFIG_IDE_PROC_FS), y) - ide-gd_mod-y += ide-floppy_proc.o -endif -endif - -obj-$(CONFIG_IDE_GD) += ide-gd_mod.o -obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd_mod.o -obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o - -obj-$(CONFIG_BLK_DEV_IDECS) += ide-cs.o - -obj-$(CONFIG_BLK_DEV_PLATFORM) += ide_platform.o - -obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o -obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o -obj-$(CONFIG_BLK_DEV_PALMCHIP_BK3710) += palm_bk3710.o - -obj-$(CONFIG_BLK_DEV_IDE_TX4938) += tx4938ide.o -obj-$(CONFIG_BLK_DEV_IDE_TX4939) += tx4939ide.o diff --git a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c deleted file mode 100644 index 4c959ce41ba9..000000000000 --- a/drivers/ide/aec62xx.c +++ /dev/null @@ -1,331 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1999-2002 Andre Hedrick - * Copyright (C) 2007 MontaVista Software, Inc. - * - */ - -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "aec62xx" - -struct chipset_bus_clock_list_entry { - u8 xfer_speed; - u8 chipset_settings; - u8 ultra_settings; -}; - -static const struct chipset_bus_clock_list_entry aec6xxx_33_base [] = { - { XFER_UDMA_6, 0x31, 0x07 }, - { XFER_UDMA_5, 0x31, 0x06 }, - { XFER_UDMA_4, 0x31, 0x05 }, - { XFER_UDMA_3, 0x31, 0x04 }, - { XFER_UDMA_2, 0x31, 0x03 }, - { XFER_UDMA_1, 0x31, 0x02 }, - { XFER_UDMA_0, 0x31, 0x01 }, - - { XFER_MW_DMA_2, 0x31, 0x00 }, - { XFER_MW_DMA_1, 0x31, 0x00 }, - { XFER_MW_DMA_0, 0x0a, 0x00 }, - { XFER_PIO_4, 0x31, 0x00 }, - { XFER_PIO_3, 0x33, 0x00 }, - { XFER_PIO_2, 0x08, 0x00 }, - { XFER_PIO_1, 0x0a, 0x00 }, - { XFER_PIO_0, 0x00, 0x00 }, - { 0, 0x00, 0x00 } -}; - -static const struct chipset_bus_clock_list_entry aec6xxx_34_base [] = { - { XFER_UDMA_6, 0x41, 0x06 }, - { XFER_UDMA_5, 0x41, 0x05 }, - { XFER_UDMA_4, 0x41, 0x04 }, - { XFER_UDMA_3, 0x41, 0x03 }, - { XFER_UDMA_2, 0x41, 0x02 }, - { XFER_UDMA_1, 0x41, 0x01 }, - { XFER_UDMA_0, 0x41, 0x01 }, - - { XFER_MW_DMA_2, 0x41, 0x00 }, - { XFER_MW_DMA_1, 0x42, 0x00 }, - { XFER_MW_DMA_0, 0x7a, 0x00 }, - { XFER_PIO_4, 0x41, 0x00 }, - { XFER_PIO_3, 0x43, 0x00 }, - { XFER_PIO_2, 0x78, 0x00 }, - { XFER_PIO_1, 0x7a, 0x00 }, - { XFER_PIO_0, 0x70, 0x00 }, - { 0, 0x00, 0x00 } -}; - -/* - * TO DO: active tuning and correction of cards without a bios. - */ -static u8 pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table) -{ - for ( ; chipset_table->xfer_speed ; chipset_table++) - if (chipset_table->xfer_speed == speed) { - return chipset_table->chipset_settings; - } - return chipset_table->chipset_settings; -} - -static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entry * chipset_table) -{ - for ( ; chipset_table->xfer_speed ; chipset_table++) - if (chipset_table->xfer_speed == speed) { - return chipset_table->ultra_settings; - } - return chipset_table->ultra_settings; -} - -static void aec6210_set_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - struct ide_host *host = pci_get_drvdata(dev); - struct chipset_bus_clock_list_entry *bus_clock = host->host_priv; - u16 d_conf = 0; - u8 ultra = 0, ultra_conf = 0; - u8 tmp0 = 0, tmp1 = 0, tmp2 = 0; - const u8 speed = drive->dma_mode; - unsigned long flags; - - local_irq_save(flags); - /* 0x40|(2*drive->dn): Active, 0x41|(2*drive->dn): Recovery */ - pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf); - tmp0 = pci_bus_clock_list(speed, bus_clock); - d_conf = ((tmp0 & 0xf0) << 4) | (tmp0 & 0xf); - pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf); - - tmp1 = 0x00; - tmp2 = 0x00; - pci_read_config_byte(dev, 0x54, &ultra); - tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn)))); - ultra_conf = pci_bus_clock_list_ultra(speed, bus_clock); - tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn)))); - pci_write_config_byte(dev, 0x54, tmp2); - local_irq_restore(flags); -} - -static void aec6260_set_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - struct ide_host *host = pci_get_drvdata(dev); - struct chipset_bus_clock_list_entry *bus_clock = host->host_priv; - u8 unit = drive->dn & 1; - u8 tmp1 = 0, tmp2 = 0; - u8 ultra = 0, drive_conf = 0, ultra_conf = 0; - const u8 speed = drive->dma_mode; - unsigned long flags; - - local_irq_save(flags); - /* high 4-bits: Active, low 4-bits: Recovery */ - pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf); - drive_conf = pci_bus_clock_list(speed, bus_clock); - pci_write_config_byte(dev, 0x40|drive->dn, drive_conf); - - pci_read_config_byte(dev, (0x44|hwif->channel), &ultra); - tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit)))); - ultra_conf = pci_bus_clock_list_ultra(speed, bus_clock); - tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit)))); - pci_write_config_byte(dev, (0x44|hwif->channel), tmp2); - local_irq_restore(flags); -} - -static void aec_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - drive->dma_mode = drive->pio_mode; - hwif->port_ops->set_dma_mode(hwif, drive); -} - -static int init_chipset_aec62xx(struct pci_dev *dev) -{ - /* These are necessary to get AEC6280 Macintosh cards to work */ - if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) || - (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) { - u8 reg49h = 0, reg4ah = 0; - /* Clear reset and test bits. */ - pci_read_config_byte(dev, 0x49, ®49h); - pci_write_config_byte(dev, 0x49, reg49h & ~0x30); - /* Enable chip interrupt output. */ - pci_read_config_byte(dev, 0x4a, ®4ah); - pci_write_config_byte(dev, 0x4a, reg4ah & ~0x01); - /* Enable burst mode. */ - pci_read_config_byte(dev, 0x4a, ®4ah); - pci_write_config_byte(dev, 0x4a, reg4ah | 0x80); - } - - return 0; -} - -static u8 atp86x_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01; - - pci_read_config_byte(dev, 0x49, &ata66); - - return (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; -} - -static const struct ide_port_ops atp850_port_ops = { - .set_pio_mode = aec_set_pio_mode, - .set_dma_mode = aec6210_set_mode, -}; - -static const struct ide_port_ops atp86x_port_ops = { - .set_pio_mode = aec_set_pio_mode, - .set_dma_mode = aec6260_set_mode, - .cable_detect = atp86x_cable_detect, -}; - -static const struct ide_port_info aec62xx_chipsets[] = { - { /* 0: AEC6210 */ - .name = DRV_NAME, - .init_chipset = init_chipset_aec62xx, - .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, - .port_ops = &atp850_port_ops, - .host_flags = IDE_HFLAG_SERIALIZE | - IDE_HFLAG_NO_ATAPI_DMA | - IDE_HFLAG_NO_DSC | - IDE_HFLAG_OFF_BOARD, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA2, - }, - { /* 1: AEC6260 */ - .name = DRV_NAME, - .init_chipset = init_chipset_aec62xx, - .port_ops = &atp86x_port_ops, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA | - IDE_HFLAG_OFF_BOARD, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA4, - }, - { /* 2: AEC6260R */ - .name = DRV_NAME, - .init_chipset = init_chipset_aec62xx, - .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, - .port_ops = &atp86x_port_ops, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | - IDE_HFLAG_NON_BOOTABLE, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA4, - }, - { /* 3: AEC6280 */ - .name = DRV_NAME, - .init_chipset = init_chipset_aec62xx, - .port_ops = &atp86x_port_ops, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | - IDE_HFLAG_OFF_BOARD, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA5, - }, - { /* 4: AEC6280R */ - .name = DRV_NAME, - .init_chipset = init_chipset_aec62xx, - .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, - .port_ops = &atp86x_port_ops, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | - IDE_HFLAG_OFF_BOARD, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA5, - } -}; - -/** - * aec62xx_init_one - called when a AEC is found - * @dev: the aec62xx device - * @id: the matching pci id - * - * Called when the PCI registration layer (or the IDE initialization) - * finds a device matching our IDE device tables. - * - * NOTE: since we're going to modify the 'name' field for AEC-6[26]80[R] - * chips, pass a local copy of 'struct ide_port_info' down the call chain. - */ - -static int aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - const struct chipset_bus_clock_list_entry *bus_clock; - struct ide_port_info d; - u8 idx = id->driver_data; - int bus_speed = ide_pci_clk ? ide_pci_clk : 33; - int err; - - if (bus_speed <= 33) - bus_clock = aec6xxx_33_base; - else - bus_clock = aec6xxx_34_base; - - err = pci_enable_device(dev); - if (err) - return err; - - d = aec62xx_chipsets[idx]; - - if (idx == 3 || idx == 4) { - unsigned long dma_base = pci_resource_start(dev, 4); - - if (inb(dma_base + 2) & 0x10) { - printk(KERN_INFO DRV_NAME " %s: AEC6880%s card detected" - "\n", pci_name(dev), (idx == 4) ? "R" : ""); - d.udma_mask = ATA_UDMA6; - } - } - - err = ide_pci_init_one(dev, &d, (void *)bus_clock); - if (err) - pci_disable_device(dev); - - return err; -} - -static void aec62xx_remove(struct pci_dev *dev) -{ - ide_pci_remove(dev); - pci_disable_device(dev); -} - -static const struct pci_device_id aec62xx_pci_tbl[] = { - { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF), 0 }, - { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860), 1 }, - { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R), 2 }, - { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865), 3 }, - { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R), 4 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl); - -static struct pci_driver aec62xx_pci_driver = { - .name = "AEC62xx_IDE", - .id_table = aec62xx_pci_tbl, - .probe = aec62xx_init_one, - .remove = aec62xx_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init aec62xx_ide_init(void) -{ - return ide_pci_register_driver(&aec62xx_pci_driver); -} - -static void __exit aec62xx_ide_exit(void) -{ - pci_unregister_driver(&aec62xx_pci_driver); -} - -module_init(aec62xx_ide_init); -module_exit(aec62xx_ide_exit); - -MODULE_AUTHOR("Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for ARTOP AEC62xx IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c deleted file mode 100644 index 3268931c2c7a..000000000000 --- a/drivers/ide/ali14xx.c +++ /dev/null @@ -1,250 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1996 Linus Torvalds & author (see below) - */ - -/* - * ALI M14xx chipset EIDE controller - * - * Works for ALI M1439/1443/1445/1487/1489 chipsets. - * - * Adapted from code developed by derekn@vw.ece.cmu.edu. -ml - * Derek's notes follow: - * - * I think the code should be pretty understandable, - * but I'll be happy to (try to) answer questions. - * - * The critical part is in the setupDrive function. The initRegisters - * function doesn't seem to be necessary, but the DOS driver does it, so - * I threw it in. - * - * I've only tested this on my system, which only has one disk. I posted - * it to comp.sys.linux.hardware, so maybe some other people will try it - * out. - * - * Derek Noonburg (derekn@ece.cmu.edu) - * 95-sep-26 - * - * Update 96-jul-13: - * - * I've since upgraded to two disks and a CD-ROM, with no trouble, and - * I've also heard from several others who have used it successfully. - * This driver appears to work with both the 1443/1445 and the 1487/1489 - * chipsets. I've added support for PIO mode 4 for the 1487. This - * seems to work just fine on the 1443 also, although I'm not sure it's - * advertised as supporting mode 4. (I've been running a WDC AC21200 in - * mode 4 for a while now with no trouble.) -Derek - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "ali14xx" - -/* port addresses for auto-detection */ -#define ALI_NUM_PORTS 4 -static const int ports[ALI_NUM_PORTS] __initconst = - { 0x074, 0x0f4, 0x034, 0x0e4 }; - -/* register initialization data */ -typedef struct { u8 reg, data; } RegInitializer; - -static const RegInitializer initData[] __initconst = { - {0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00}, - {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f}, - {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00}, - {0x29, 0x00}, {0x2a, 0x00}, {0x2f, 0x00}, {0x2b, 0x00}, - {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x30, 0x00}, - {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0xff}, - {0x35, 0x03}, {0x00, 0x00} -}; - -/* timing parameter registers for each drive */ -static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = { - {0x03, 0x26, 0x04, 0x27}, /* drive 0 */ - {0x05, 0x28, 0x06, 0x29}, /* drive 1 */ - {0x2b, 0x30, 0x2c, 0x31}, /* drive 2 */ - {0x2d, 0x32, 0x2e, 0x33}, /* drive 3 */ -}; - -static int basePort; /* base port address */ -static int regPort; /* port for register number */ -static int dataPort; /* port for register data */ -static u8 regOn; /* output to base port to access registers */ -static u8 regOff; /* output to base port to close registers */ - -/*------------------------------------------------------------------------*/ - -/* - * Read a controller register. - */ -static inline u8 inReg(u8 reg) -{ - outb_p(reg, regPort); - return inb(dataPort); -} - -/* - * Write a controller register. - */ -static void outReg(u8 data, u8 reg) -{ - outb_p(reg, regPort); - outb_p(data, dataPort); -} - -static DEFINE_SPINLOCK(ali14xx_lock); - -/* - * Set PIO mode for the specified drive. - * This function computes timing parameters - * and sets controller registers accordingly. - */ -static void ali14xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - int driveNum; - int time1, time2; - u8 param1, param2, param3, param4; - unsigned long flags; - int bus_speed = ide_vlb_clk ? ide_vlb_clk : 50; - const u8 pio = drive->pio_mode - XFER_PIO_0; - struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); - - /* calculate timing, according to PIO mode */ - time1 = ide_pio_cycle_time(drive, pio); - time2 = t->active; - param3 = param1 = (time2 * bus_speed + 999) / 1000; - param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1; - if (pio < 3) { - param3 += 8; - param4 += 8; - } - printk(KERN_DEBUG "%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n", - drive->name, pio, time1, time2, param1, param2, param3, param4); - - /* stuff timing parameters into controller registers */ - driveNum = (drive->hwif->index << 1) + (drive->dn & 1); - spin_lock_irqsave(&ali14xx_lock, flags); - outb_p(regOn, basePort); - outReg(param1, regTab[driveNum].reg1); - outReg(param2, regTab[driveNum].reg2); - outReg(param3, regTab[driveNum].reg3); - outReg(param4, regTab[driveNum].reg4); - outb_p(regOff, basePort); - spin_unlock_irqrestore(&ali14xx_lock, flags); -} - -/* - * Auto-detect the IDE controller port. - */ -static int __init findPort(void) -{ - int i; - u8 t; - unsigned long flags; - - local_irq_save(flags); - for (i = 0; i < ALI_NUM_PORTS; ++i) { - basePort = ports[i]; - regOff = inb(basePort); - for (regOn = 0x30; regOn <= 0x33; ++regOn) { - outb_p(regOn, basePort); - if (inb(basePort) == regOn) { - regPort = basePort + 4; - dataPort = basePort + 8; - t = inReg(0) & 0xf0; - outb_p(regOff, basePort); - local_irq_restore(flags); - if (t != 0x50) - return 0; - return 1; /* success */ - } - } - outb_p(regOff, basePort); - } - local_irq_restore(flags); - return 0; -} - -/* - * Initialize controller registers with default values. - */ -static int __init initRegisters(void) -{ - const RegInitializer *p; - u8 t; - unsigned long flags; - - local_irq_save(flags); - outb_p(regOn, basePort); - for (p = initData; p->reg != 0; ++p) - outReg(p->data, p->reg); - outb_p(0x01, regPort); - t = inb(regPort) & 0x01; - outb_p(regOff, basePort); - local_irq_restore(flags); - return t; -} - -static const struct ide_port_ops ali14xx_port_ops = { - .set_pio_mode = ali14xx_set_pio_mode, -}; - -static const struct ide_port_info ali14xx_port_info = { - .name = DRV_NAME, - .chipset = ide_ali14xx, - .port_ops = &ali14xx_port_ops, - .host_flags = IDE_HFLAG_NO_DMA, - .pio_mask = ATA_PIO4, -}; - -static int __init ali14xx_probe(void) -{ - printk(KERN_DEBUG "ali14xx: base=0x%03x, regOn=0x%02x.\n", - basePort, regOn); - - /* initialize controller registers */ - if (!initRegisters()) { - printk(KERN_ERR "ali14xx: Chip initialization failed.\n"); - return 1; - } - - return ide_legacy_device_add(&ali14xx_port_info, 0); -} - -static bool probe_ali14xx; - -module_param_named(probe, probe_ali14xx, bool, 0); -MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets"); - -static int __init ali14xx_init(void) -{ - if (probe_ali14xx == 0) - goto out; - - /* auto-detect IDE controller port */ - if (findPort()) { - if (ali14xx_probe()) - return -ENODEV; - return 0; - } - printk(KERN_ERR "ali14xx: not found.\n"); -out: - return -ENODEV; -} - -module_init(ali14xx_init); - -MODULE_AUTHOR("see local file"); -MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c deleted file mode 100644 index 3265970aee34..000000000000 --- a/drivers/ide/alim15x3.c +++ /dev/null @@ -1,602 +0,0 @@ -/* - * Copyright (C) 1998-2000 Michel Aubry, Maintainer - * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer - * Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer - * - * Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org) - * May be copied or modified under the terms of the GNU General Public License - * Copyright (C) 2002 Alan Cox - * ALi (now ULi M5228) support by Clear Zhang - * Copyright (C) 2007 MontaVista Software, Inc. - * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz - * - * (U)DMA capable version of ali 1533/1543(C), 1535(D) - * - ********************************************************************** - * 9/7/99 --Parts from the above author are included and need to be - * converted into standard interface, once I finish the thought. - * - * Recent changes - * Don't use LBA48 mode on ALi <= 0xC4 - * Don't poke 0x79 with a non ALi northbridge - * Don't flip undefined bits on newer chipsets (fix Fujitsu laptop hang) - * Allow UDMA6 on revisions > 0xC4 - * - * Documentation - * Chipset documentation available under NDA only - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "alim15x3" - -/* - * ALi devices are not plug in. Otherwise these static values would - * need to go. They ought to go away anyway - */ - -static u8 m5229_revision; -static u8 chip_is_1543c_e; -static struct pci_dev *isa_dev; - -static void ali_fifo_control(ide_hwif_t *hwif, ide_drive_t *drive, int on) -{ - struct pci_dev *pdev = to_pci_dev(hwif->dev); - int pio_fifo = 0x54 + hwif->channel; - u8 fifo; - int shift = 4 * (drive->dn & 1); - - pci_read_config_byte(pdev, pio_fifo, &fifo); - fifo &= ~(0x0F << shift); - fifo |= (on << shift); - pci_write_config_byte(pdev, pio_fifo, fifo); -} - -static void ali_program_timings(ide_hwif_t *hwif, ide_drive_t *drive, - struct ide_timing *t, u8 ultra) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - int port = hwif->channel ? 0x5c : 0x58; - int udmat = 0x56 + hwif->channel; - u8 unit = drive->dn & 1, udma; - int shift = 4 * unit; - - /* Set up the UDMA */ - pci_read_config_byte(dev, udmat, &udma); - udma &= ~(0x0F << shift); - udma |= ultra << shift; - pci_write_config_byte(dev, udmat, udma); - - if (t == NULL) - return; - - t->setup = clamp_val(t->setup, 1, 8) & 7; - t->act8b = clamp_val(t->act8b, 1, 8) & 7; - t->rec8b = clamp_val(t->rec8b, 1, 16) & 15; - t->active = clamp_val(t->active, 1, 8) & 7; - t->recover = clamp_val(t->recover, 1, 16) & 15; - - pci_write_config_byte(dev, port, t->setup); - pci_write_config_byte(dev, port + 1, (t->act8b << 4) | t->rec8b); - pci_write_config_byte(dev, port + unit + 2, - (t->active << 4) | t->recover); -} - -/** - * ali_set_pio_mode - set host controller for PIO mode - * @hwif: port - * @drive: drive - * - * Program the controller for the given PIO mode. - */ - -static void ali_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - ide_drive_t *pair = ide_get_pair_dev(drive); - int bus_speed = ide_pci_clk ? ide_pci_clk : 33; - unsigned long T = 1000000 / bus_speed; /* PCI clock based */ - struct ide_timing t; - - ide_timing_compute(drive, drive->pio_mode, &t, T, 1); - if (pair) { - struct ide_timing p; - - ide_timing_compute(pair, pair->pio_mode, &p, T, 1); - ide_timing_merge(&p, &t, &t, - IDE_TIMING_SETUP | IDE_TIMING_8BIT); - if (pair->dma_mode) { - ide_timing_compute(pair, pair->dma_mode, &p, T, 1); - ide_timing_merge(&p, &t, &t, - IDE_TIMING_SETUP | IDE_TIMING_8BIT); - } - } - - /* - * PIO mode => ATA FIFO on, ATAPI FIFO off - */ - ali_fifo_control(hwif, drive, (drive->media == ide_disk) ? 0x05 : 0x00); - - ali_program_timings(hwif, drive, &t, 0); -} - -/** - * ali_udma_filter - compute UDMA mask - * @drive: IDE device - * - * Return available UDMA modes. - * - * The actual rules for the ALi are: - * No UDMA on revisions <= 0x20 - * Disk only for revisions < 0xC2 - * Not WDC drives on M1543C-E (?) - */ - -static u8 ali_udma_filter(ide_drive_t *drive) -{ - if (m5229_revision > 0x20 && m5229_revision < 0xC2) { - if (drive->media != ide_disk) - return 0; - if (chip_is_1543c_e && - strstr((char *)&drive->id[ATA_ID_PROD], "WDC ")) - return 0; - } - - return drive->hwif->ultra_mask; -} - -/** - * ali_set_dma_mode - set host controller for DMA mode - * @hwif: port - * @drive: drive - * - * Configure the hardware for the desired IDE transfer mode. - */ - -static void ali_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - static u8 udma_timing[7] = { 0xC, 0xB, 0xA, 0x9, 0x8, 0xF, 0xD }; - struct pci_dev *dev = to_pci_dev(hwif->dev); - ide_drive_t *pair = ide_get_pair_dev(drive); - int bus_speed = ide_pci_clk ? ide_pci_clk : 33; - unsigned long T = 1000000 / bus_speed; /* PCI clock based */ - const u8 speed = drive->dma_mode; - u8 tmpbyte = 0x00; - struct ide_timing t; - - if (speed < XFER_UDMA_0) { - ide_timing_compute(drive, drive->dma_mode, &t, T, 1); - if (pair) { - struct ide_timing p; - - ide_timing_compute(pair, pair->pio_mode, &p, T, 1); - ide_timing_merge(&p, &t, &t, - IDE_TIMING_SETUP | IDE_TIMING_8BIT); - if (pair->dma_mode) { - ide_timing_compute(pair, pair->dma_mode, - &p, T, 1); - ide_timing_merge(&p, &t, &t, - IDE_TIMING_SETUP | IDE_TIMING_8BIT); - } - } - ali_program_timings(hwif, drive, &t, 0); - } else { - ali_program_timings(hwif, drive, NULL, - udma_timing[speed - XFER_UDMA_0]); - if (speed >= XFER_UDMA_3) { - pci_read_config_byte(dev, 0x4b, &tmpbyte); - tmpbyte |= 1; - pci_write_config_byte(dev, 0x4b, tmpbyte); - } - } -} - -/** - * ali_dma_check - DMA check - * @drive: target device - * @cmd: command - * - * Returns 1 if the DMA cannot be performed, zero on success. - */ - -static int ali_dma_check(ide_drive_t *drive, struct ide_cmd *cmd) -{ - if (m5229_revision < 0xC2 && drive->media != ide_disk) { - if (cmd->tf_flags & IDE_TFLAG_WRITE) - return 1; /* try PIO instead of DMA */ - } - return 0; -} - -/** - * init_chipset_ali15x3 - Initialise an ALi IDE controller - * @dev: PCI device - * - * This function initializes the ALI IDE controller and where - * appropriate also sets up the 1533 southbridge. - */ - -static int init_chipset_ali15x3(struct pci_dev *dev) -{ - unsigned long flags; - u8 tmpbyte; - struct pci_dev *north = pci_get_slot(dev->bus, PCI_DEVFN(0,0)); - - m5229_revision = dev->revision; - - isa_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); - - local_irq_save(flags); - - if (m5229_revision < 0xC2) { - /* - * revision 0x20 (1543-E, 1543-F) - * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E) - * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7 - */ - pci_read_config_byte(dev, 0x4b, &tmpbyte); - /* - * clear bit 7 - */ - pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F); - /* - * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010 - */ - if (m5229_revision >= 0x20 && isa_dev) { - pci_read_config_byte(isa_dev, 0x5e, &tmpbyte); - chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0; - } - goto out; - } - - /* - * 1543C-B?, 1535, 1535D, 1553 - * Note 1: not all "motherboard" support this detection - * Note 2: if no udma 66 device, the detection may "error". - * but in this case, we will not set the device to - * ultra 66, the detection result is not important - */ - - /* - * enable "Cable Detection", m5229, 0x4b, bit3 - */ - pci_read_config_byte(dev, 0x4b, &tmpbyte); - pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08); - - /* - * We should only tune the 1533 enable if we are using an ALi - * North bridge. We might have no north found on some zany - * box without a device at 0:0.0. The ALi bridge will be at - * 0:0.0 so if we didn't find one we know what is cooking. - */ - if (north && north->vendor != PCI_VENDOR_ID_AL) - goto out; - - if (m5229_revision < 0xC5 && isa_dev) - { - /* - * set south-bridge's enable bit, m1533, 0x79 - */ - - pci_read_config_byte(isa_dev, 0x79, &tmpbyte); - if (m5229_revision == 0xC2) { - /* - * 1543C-B0 (m1533, 0x79, bit 2) - */ - pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04); - } else if (m5229_revision >= 0xC3) { - /* - * 1553/1535 (m1533, 0x79, bit 1) - */ - pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02); - } - } - -out: - /* - * CD_ROM DMA on (m5229, 0x53, bit0) - * Enable this bit even if we want to use PIO. - * PIO FIFO off (m5229, 0x53, bit1) - * The hardware will use 0x54h and 0x55h to control PIO FIFO. - * (Not on later devices it seems) - * - * 0x53 changes meaning on later revs - we must no touch - * bit 1 on them. Need to check if 0x20 is the right break. - */ - if (m5229_revision >= 0x20) { - pci_read_config_byte(dev, 0x53, &tmpbyte); - - if (m5229_revision <= 0x20) - tmpbyte = (tmpbyte & (~0x02)) | 0x01; - else if (m5229_revision == 0xc7 || m5229_revision == 0xc8) - tmpbyte |= 0x03; - else - tmpbyte |= 0x01; - - pci_write_config_byte(dev, 0x53, tmpbyte); - } - local_irq_restore(flags); - pci_dev_put(north); - pci_dev_put(isa_dev); - return 0; -} - -/* - * Cable special cases - */ - -static const struct dmi_system_id cable_dmi_table[] = { - { - .ident = "HP Pavilion N5430", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"), - }, - }, - { - .ident = "Toshiba Satellite S1800-814", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_NAME, "S1800-814"), - }, - }, - { } -}; - -static int ali_cable_override(struct pci_dev *pdev) -{ - /* Fujitsu P2000 */ - if (pdev->subsystem_vendor == 0x10CF && - pdev->subsystem_device == 0x10AF) - return 1; - - /* Mitac 8317 (Winbook-A) and relatives */ - if (pdev->subsystem_vendor == 0x1071 && - pdev->subsystem_device == 0x8317) - return 1; - - /* Systems by DMI */ - if (dmi_check_system(cable_dmi_table)) - return 1; - - return 0; -} - -/** - * ali_cable_detect - cable detection - * @hwif: IDE interface - * - * This checks if the controller and the cable are capable - * of UDMA66 transfers. It doesn't check the drives. - */ - -static u8 ali_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 cbl = ATA_CBL_PATA40, tmpbyte; - - if (m5229_revision >= 0xC2) { - /* - * m5229 80-pin cable detection (from Host View) - * - * 0x4a bit0 is 0 => primary channel has 80-pin - * 0x4a bit1 is 0 => secondary channel has 80-pin - * - * Certain laptops use short but suitable cables - * and don't implement the detect logic. - */ - if (ali_cable_override(dev)) - cbl = ATA_CBL_PATA40_SHORT; - else { - pci_read_config_byte(dev, 0x4a, &tmpbyte); - if ((tmpbyte & (1 << hwif->channel)) == 0) - cbl = ATA_CBL_PATA80; - } - } - - return cbl; -} - -#ifndef CONFIG_SPARC64 -/** - * init_hwif_ali15x3 - Initialize the ALI IDE x86 stuff - * @hwif: interface to configure - * - * Obtain the IRQ tables for an ALi based IDE solution on the PC - * class platforms. This part of the code isn't applicable to the - * Sparc systems. - */ - -static void init_hwif_ali15x3(ide_hwif_t *hwif) -{ - u8 ideic, inmir; - s8 irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6, - 1, 11, 0, 12, 0, 14, 0, 15 }; - int irq = -1; - - if (isa_dev) { - /* - * read IDE interface control - */ - pci_read_config_byte(isa_dev, 0x58, &ideic); - - /* bit0, bit1 */ - ideic = ideic & 0x03; - - /* get IRQ for IDE Controller */ - if ((hwif->channel && ideic == 0x03) || - (!hwif->channel && !ideic)) { - /* - * get SIRQ1 routing table - */ - pci_read_config_byte(isa_dev, 0x44, &inmir); - inmir = inmir & 0x0f; - irq = irq_routing_table[inmir]; - } else if (hwif->channel && !(ideic & 0x01)) { - /* - * get SIRQ2 routing table - */ - pci_read_config_byte(isa_dev, 0x75, &inmir); - inmir = inmir & 0x0f; - irq = irq_routing_table[inmir]; - } - if(irq >= 0) - hwif->irq = irq; - } -} -#else -#define init_hwif_ali15x3 NULL -#endif /* CONFIG_SPARC64 */ - -/** - * init_dma_ali15x3 - set up DMA on ALi15x3 - * @hwif: IDE interface - * @d: IDE port info - * - * Set up the DMA functionality on the ALi 15x3. - */ - -static int init_dma_ali15x3(ide_hwif_t *hwif, const struct ide_port_info *d) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long base = ide_pci_dma_base(hwif, d); - - if (base == 0) - return -1; - - hwif->dma_base = base; - - if (ide_pci_check_simplex(hwif, d) < 0) - return -1; - - if (ide_pci_set_master(dev, d->name) < 0) - return -1; - - if (!hwif->channel) - outb(inb(base + 2) & 0x60, base + 2); - - printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n", - hwif->name, base, base + 7); - - if (ide_allocate_dma_engine(hwif)) - return -1; - - return 0; -} - -static const struct ide_port_ops ali_port_ops = { - .set_pio_mode = ali_set_pio_mode, - .set_dma_mode = ali_set_dma_mode, - .udma_filter = ali_udma_filter, - .cable_detect = ali_cable_detect, -}; - -static const struct ide_dma_ops ali_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = ide_dma_start, - .dma_end = ide_dma_end, - .dma_test_irq = ide_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_check = ali_dma_check, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = ide_dma_sff_read_status, -}; - -static const struct ide_port_info ali15x3_chipset = { - .name = DRV_NAME, - .init_chipset = init_chipset_ali15x3, - .init_hwif = init_hwif_ali15x3, - .init_dma = init_dma_ali15x3, - .port_ops = &ali_port_ops, - .dma_ops = &sff_dma_ops, - .pio_mask = ATA_PIO5, - .swdma_mask = ATA_SWDMA2, - .mwdma_mask = ATA_MWDMA2, -}; - -/** - * alim15x3_init_one - set up an ALi15x3 IDE controller - * @dev: PCI device to set up - * - * Perform the actual set up for an ALi15x3 that has been found by the - * hot plug layer. - */ - -static int alim15x3_init_one(struct pci_dev *dev, - const struct pci_device_id *id) -{ - struct ide_port_info d = ali15x3_chipset; - u8 rev = dev->revision, idx = id->driver_data; - - /* don't use LBA48 DMA on ALi devices before rev 0xC5 */ - if (rev <= 0xC4) - d.host_flags |= IDE_HFLAG_NO_LBA48_DMA; - - if (rev >= 0x20) { - if (rev == 0x20) - d.host_flags |= IDE_HFLAG_NO_ATAPI_DMA; - - if (rev < 0xC2) - d.udma_mask = ATA_UDMA2; - else if (rev == 0xC2 || rev == 0xC3) - d.udma_mask = ATA_UDMA4; - else if (rev == 0xC4) - d.udma_mask = ATA_UDMA5; - else - d.udma_mask = ATA_UDMA6; - - d.dma_ops = &ali_dma_ops; - } else { - d.host_flags |= IDE_HFLAG_NO_DMA; - - d.mwdma_mask = d.swdma_mask = 0; - } - - if (idx == 0) - d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX; - - return ide_pci_init_one(dev, &d, NULL); -} - - -static const struct pci_device_id alim15x3_pci_tbl[] = { - { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), 0 }, - { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), 1 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl); - -static struct pci_driver alim15x3_pci_driver = { - .name = "ALI15x3_IDE", - .id_table = alim15x3_pci_tbl, - .probe = alim15x3_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init ali15x3_ide_init(void) -{ - return ide_pci_register_driver(&alim15x3_pci_driver); -} - -static void __exit ali15x3_ide_exit(void) -{ - pci_unregister_driver(&alim15x3_pci_driver); -} - -module_init(ali15x3_ide_init); -module_exit(ali15x3_ide_exit); - -MODULE_AUTHOR("Michael Aubry, Andrzej Krzysztofowicz, CJ, Andre Hedrick, Alan Cox, Bartlomiej Zolnierkiewicz"); -MODULE_DESCRIPTION("PCI driver module for ALi 15x3 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c deleted file mode 100644 index 7340597a373e..000000000000 --- a/drivers/ide/amd74xx.c +++ /dev/null @@ -1,343 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04 - * IDE driver for Linux. - * - * Copyright (c) 2000-2002 Vojtech Pavlik - * Copyright (c) 2007-2010 Bartlomiej Zolnierkiewicz - * - * Based on the work of: - * Andre Hedrick - */ - - -#include -#include -#include -#include -#include - -#define DRV_NAME "amd74xx" - -enum { - AMD_IDE_CONFIG = 0x41, - AMD_CABLE_DETECT = 0x42, - AMD_DRIVE_TIMING = 0x48, - AMD_8BIT_TIMING = 0x4e, - AMD_ADDRESS_SETUP = 0x4c, - AMD_UDMA_TIMING = 0x50, -}; - -static unsigned int amd_80w; -static unsigned int amd_clock; - -static char *amd_dma[] = { "16", "25", "33", "44", "66", "100", "133" }; -static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7 }; - -static inline u8 amd_offset(struct pci_dev *dev) -{ - return (dev->vendor == PCI_VENDOR_ID_NVIDIA) ? 0x10 : 0; -} - -/* - * amd_set_speed() writes timing values to the chipset registers - */ - -static void amd_set_speed(struct pci_dev *dev, u8 dn, u8 udma_mask, - struct ide_timing *timing) -{ - u8 t = 0, offset = amd_offset(dev); - - pci_read_config_byte(dev, AMD_ADDRESS_SETUP + offset, &t); - t = (t & ~(3 << ((3 - dn) << 1))) | ((clamp_val(timing->setup, 1, 4) - 1) << ((3 - dn) << 1)); - pci_write_config_byte(dev, AMD_ADDRESS_SETUP + offset, t); - - pci_write_config_byte(dev, AMD_8BIT_TIMING + offset + (1 - (dn >> 1)), - ((clamp_val(timing->act8b, 1, 16) - 1) << 4) | (clamp_val(timing->rec8b, 1, 16) - 1)); - - pci_write_config_byte(dev, AMD_DRIVE_TIMING + offset + (3 - dn), - ((clamp_val(timing->active, 1, 16) - 1) << 4) | (clamp_val(timing->recover, 1, 16) - 1)); - - switch (udma_mask) { - case ATA_UDMA2: t = timing->udma ? (0xc0 | (clamp_val(timing->udma, 2, 5) - 2)) : 0x03; break; - case ATA_UDMA4: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 2, 10)]) : 0x03; break; - case ATA_UDMA5: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 1, 10)]) : 0x03; break; - case ATA_UDMA6: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 1, 15)]) : 0x03; break; - default: return; - } - - if (timing->udma) - pci_write_config_byte(dev, AMD_UDMA_TIMING + offset + 3 - dn, t); -} - -/* - * amd_set_drive() computes timing values and configures the chipset - * to a desired transfer mode. It also can be called by upper layers. - */ - -static void amd_set_drive(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - ide_drive_t *peer = ide_get_pair_dev(drive); - struct ide_timing t, p; - int T, UT; - u8 udma_mask = hwif->ultra_mask; - const u8 speed = drive->dma_mode; - - T = 1000000000 / amd_clock; - UT = (udma_mask == ATA_UDMA2) ? T : (T / 2); - - ide_timing_compute(drive, speed, &t, T, UT); - - if (peer) { - ide_timing_compute(peer, peer->pio_mode, &p, T, UT); - ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT); - } - - if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1; - if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15; - - amd_set_speed(dev, drive->dn, udma_mask, &t); -} - -/* - * amd_set_pio_mode() is a callback from upper layers for PIO-only tuning. - */ - -static void amd_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - drive->dma_mode = drive->pio_mode; - amd_set_drive(hwif, drive); -} - -static void amd7409_cable_detect(struct pci_dev *dev) -{ - /* no host side cable detection */ - amd_80w = 0x03; -} - -static void amd7411_cable_detect(struct pci_dev *dev) -{ - int i; - u32 u = 0; - u8 t = 0, offset = amd_offset(dev); - - pci_read_config_byte(dev, AMD_CABLE_DETECT + offset, &t); - pci_read_config_dword(dev, AMD_UDMA_TIMING + offset, &u); - amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0); - for (i = 24; i >= 0; i -= 8) - if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) { - printk(KERN_WARNING DRV_NAME " %s: BIOS didn't set " - "cable bits correctly. Enabling workaround.\n", - pci_name(dev)); - amd_80w |= (1 << (1 - (i >> 4))); - } -} - -/* - * The initialization callback. Initialize drive independent registers. - */ - -static int init_chipset_amd74xx(struct pci_dev *dev) -{ - u8 t = 0, offset = amd_offset(dev); - -/* - * Check 80-wire cable presence. - */ - - if (dev->vendor == PCI_VENDOR_ID_AMD && - dev->device == PCI_DEVICE_ID_AMD_COBRA_7401) - ; /* no UDMA > 2 */ - else if (dev->vendor == PCI_VENDOR_ID_AMD && - dev->device == PCI_DEVICE_ID_AMD_VIPER_7409) - amd7409_cable_detect(dev); - else - amd7411_cable_detect(dev); - -/* - * Take care of prefetch & postwrite. - */ - - pci_read_config_byte(dev, AMD_IDE_CONFIG + offset, &t); - /* - * Check for broken FIFO support. - */ - if (dev->vendor == PCI_VENDOR_ID_AMD && - dev->device == PCI_DEVICE_ID_AMD_VIPER_7411) - t &= 0x0f; - else - t |= 0xf0; - pci_write_config_byte(dev, AMD_IDE_CONFIG + offset, t); - - return 0; -} - -static u8 amd_cable_detect(ide_hwif_t *hwif) -{ - if ((amd_80w >> hwif->channel) & 1) - return ATA_CBL_PATA80; - else - return ATA_CBL_PATA40; -} - -static const struct ide_port_ops amd_port_ops = { - .set_pio_mode = amd_set_pio_mode, - .set_dma_mode = amd_set_drive, - .cable_detect = amd_cable_detect, -}; - -#define IDE_HFLAGS_AMD \ - (IDE_HFLAG_PIO_NO_BLACKLIST | \ - IDE_HFLAG_POST_SET_MODE | \ - IDE_HFLAG_IO_32BIT | \ - IDE_HFLAG_UNMASK_IRQS) - -#define DECLARE_AMD_DEV(swdma, udma) \ - { \ - .name = DRV_NAME, \ - .init_chipset = init_chipset_amd74xx, \ - .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \ - .port_ops = &amd_port_ops, \ - .host_flags = IDE_HFLAGS_AMD, \ - .pio_mask = ATA_PIO5, \ - .swdma_mask = swdma, \ - .mwdma_mask = ATA_MWDMA2, \ - .udma_mask = udma, \ - } - -#define DECLARE_NV_DEV(udma) \ - { \ - .name = DRV_NAME, \ - .init_chipset = init_chipset_amd74xx, \ - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \ - .port_ops = &amd_port_ops, \ - .host_flags = IDE_HFLAGS_AMD, \ - .pio_mask = ATA_PIO5, \ - .swdma_mask = ATA_SWDMA2, \ - .mwdma_mask = ATA_MWDMA2, \ - .udma_mask = udma, \ - } - -static const struct ide_port_info amd74xx_chipsets[] = { - /* 0: AMD7401 */ DECLARE_AMD_DEV(0x00, ATA_UDMA2), - /* 1: AMD7409 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA4), - /* 2: AMD7411/7441 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA5), - /* 3: AMD8111 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA6), - - /* 4: NFORCE */ DECLARE_NV_DEV(ATA_UDMA5), - /* 5: >= NFORCE2 */ DECLARE_NV_DEV(ATA_UDMA6), - - /* 6: AMD5536 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA5), -}; - -static int amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct ide_port_info d; - u8 idx = id->driver_data; - - d = amd74xx_chipsets[idx]; - - /* - * Check for bad SWDMA and incorrectly wired Serenade mainboards. - */ - if (idx == 1) { - if (dev->revision <= 7) - d.swdma_mask = 0; - d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX; - } else if (idx == 3) { - if (dev->subsystem_vendor == PCI_VENDOR_ID_AMD && - dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE) - d.udma_mask = ATA_UDMA5; - } - - /* - * It seems that on some nVidia controllers using AltStatus - * register can be unreliable so default to Status register - * if the device is in Compatibility Mode. - */ - if (dev->vendor == PCI_VENDOR_ID_NVIDIA && - ide_pci_is_in_compatibility_mode(dev)) - d.host_flags |= IDE_HFLAG_BROKEN_ALTSTATUS; - - printk(KERN_INFO "%s %s: UDMA%s controller\n", - d.name, pci_name(dev), amd_dma[fls(d.udma_mask) - 1]); - - /* - * Determine the system bus clock. - */ - amd_clock = (ide_pci_clk ? ide_pci_clk : 33) * 1000; - - switch (amd_clock) { - case 33000: amd_clock = 33333; break; - case 37000: amd_clock = 37500; break; - case 41000: amd_clock = 41666; break; - } - - if (amd_clock < 20000 || amd_clock > 50000) { - printk(KERN_WARNING "%s: User given PCI clock speed impossible" - " (%d), using 33 MHz instead.\n", - d.name, amd_clock); - amd_clock = 33333; - } - - return ide_pci_init_one(dev, &d, NULL); -} - -static const struct pci_device_id amd74xx_pci_tbl[] = { - { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_COBRA_7401), 0 }, - { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7409), 1 }, - { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7411), 2 }, - { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_OPUS_7441), 2 }, - { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_8111_IDE), 3 }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE), 4 }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE), 5 }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE), 5 }, -#ifdef CONFIG_BLK_DEV_IDE_SATA - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA), 5 }, -#endif - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE), 5 }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE), 5 }, -#ifdef CONFIG_BLK_DEV_IDE_SATA - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA), 5 }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2), 5 }, -#endif - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE), 5 }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE), 5 }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE), 5 }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE), 5 }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE), 5 }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE), 5 }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE), 5 }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE), 5 }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE), 5 }, - { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), 6 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); - -static struct pci_driver amd74xx_pci_driver = { - .name = "AMD_IDE", - .id_table = amd74xx_pci_tbl, - .probe = amd74xx_probe, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init amd74xx_ide_init(void) -{ - return ide_pci_register_driver(&amd74xx_pci_driver); -} - -static void __exit amd74xx_ide_exit(void) -{ - pci_unregister_driver(&amd74xx_pci_driver); -} - -module_init(amd74xx_ide_init); -module_exit(amd74xx_ide_exit); - -MODULE_AUTHOR("Vojtech Pavlik, Bartlomiej Zolnierkiewicz"); -MODULE_DESCRIPTION("AMD PCI IDE driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/atiixp.c b/drivers/ide/atiixp.c deleted file mode 100644 index e08b0aac08b9..000000000000 --- a/drivers/ide/atiixp.c +++ /dev/null @@ -1,212 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2003 ATI Inc. - * Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz - */ - -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "atiixp" - -#define ATIIXP_IDE_PIO_TIMING 0x40 -#define ATIIXP_IDE_MDMA_TIMING 0x44 -#define ATIIXP_IDE_PIO_CONTROL 0x48 -#define ATIIXP_IDE_PIO_MODE 0x4a -#define ATIIXP_IDE_UDMA_CONTROL 0x54 -#define ATIIXP_IDE_UDMA_MODE 0x56 - -struct atiixp_ide_timing { - u8 command_width; - u8 recover_width; -}; - -static struct atiixp_ide_timing pio_timing[] = { - { 0x05, 0x0d }, - { 0x04, 0x07 }, - { 0x03, 0x04 }, - { 0x02, 0x02 }, - { 0x02, 0x00 }, -}; - -static struct atiixp_ide_timing mdma_timing[] = { - { 0x07, 0x07 }, - { 0x02, 0x01 }, - { 0x02, 0x00 }, -}; - -static DEFINE_SPINLOCK(atiixp_lock); - -/** - * atiixp_set_pio_mode - set host controller for PIO mode - * @hwif: port - * @drive: drive - * - * Set the interface PIO mode. - */ - -static void atiixp_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long flags; - int timing_shift = (drive->dn ^ 1) * 8; - u32 pio_timing_data; - u16 pio_mode_data; - const u8 pio = drive->pio_mode - XFER_PIO_0; - - spin_lock_irqsave(&atiixp_lock, flags); - - pci_read_config_word(dev, ATIIXP_IDE_PIO_MODE, &pio_mode_data); - pio_mode_data &= ~(0x07 << (drive->dn * 4)); - pio_mode_data |= (pio << (drive->dn * 4)); - pci_write_config_word(dev, ATIIXP_IDE_PIO_MODE, pio_mode_data); - - pci_read_config_dword(dev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data); - pio_timing_data &= ~(0xff << timing_shift); - pio_timing_data |= (pio_timing[pio].recover_width << timing_shift) | - (pio_timing[pio].command_width << (timing_shift + 4)); - pci_write_config_dword(dev, ATIIXP_IDE_PIO_TIMING, pio_timing_data); - - spin_unlock_irqrestore(&atiixp_lock, flags); -} - -/** - * atiixp_set_dma_mode - set host controller for DMA mode - * @hwif: port - * @drive: drive - * - * Set a ATIIXP host controller to the desired DMA mode. This involves - * programming the right timing data into the PCI configuration space. - */ - -static void atiixp_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long flags; - int timing_shift = (drive->dn ^ 1) * 8; - u32 tmp32; - u16 tmp16; - u16 udma_ctl = 0; - const u8 speed = drive->dma_mode; - - spin_lock_irqsave(&atiixp_lock, flags); - - pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &udma_ctl); - - if (speed >= XFER_UDMA_0) { - pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &tmp16); - tmp16 &= ~(0x07 << (drive->dn * 4)); - tmp16 |= ((speed & 0x07) << (drive->dn * 4)); - pci_write_config_word(dev, ATIIXP_IDE_UDMA_MODE, tmp16); - - udma_ctl |= (1 << drive->dn); - } else if (speed >= XFER_MW_DMA_0) { - u8 i = speed & 0x03; - - pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32); - tmp32 &= ~(0xff << timing_shift); - tmp32 |= (mdma_timing[i].recover_width << timing_shift) | - (mdma_timing[i].command_width << (timing_shift + 4)); - pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32); - - udma_ctl &= ~(1 << drive->dn); - } - - pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, udma_ctl); - - spin_unlock_irqrestore(&atiixp_lock, flags); -} - -static u8 atiixp_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *pdev = to_pci_dev(hwif->dev); - u8 udma_mode = 0, ch = hwif->channel; - - pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ch, &udma_mode); - - if ((udma_mode & 0x07) >= 0x04 || (udma_mode & 0x70) >= 0x40) - return ATA_CBL_PATA80; - else - return ATA_CBL_PATA40; -} - -static const struct ide_port_ops atiixp_port_ops = { - .set_pio_mode = atiixp_set_pio_mode, - .set_dma_mode = atiixp_set_dma_mode, - .cable_detect = atiixp_cable_detect, -}; - -static const struct ide_port_info atiixp_pci_info[] = { - { /* 0: IXP200/300/400/700 */ - .name = DRV_NAME, - .enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}}, - .port_ops = &atiixp_port_ops, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA5, - }, - { /* 1: IXP600 */ - .name = DRV_NAME, - .enablebits = {{0x48,0x01,0x00}, {0x00,0x00,0x00}}, - .port_ops = &atiixp_port_ops, - .host_flags = IDE_HFLAG_SINGLE, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA5, - }, -}; - -/** - * atiixp_init_one - called when a ATIIXP is found - * @dev: the atiixp device - * @id: the matching pci id - * - * Called when the PCI registration layer (or the IDE initialization) - * finds a device matching our IDE device tables. - */ - -static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_pci_init_one(dev, &atiixp_pci_info[id->driver_data], NULL); -} - -static const struct pci_device_id atiixp_pci_tbl[] = { - { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), 0 }, - { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), 0 }, - { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), 0 }, - { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), 1 }, - { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), 0 }, - { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_HUDSON2_IDE), 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl); - -static struct pci_driver atiixp_pci_driver = { - .name = "ATIIXP_IDE", - .id_table = atiixp_pci_tbl, - .probe = atiixp_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init atiixp_ide_init(void) -{ - return ide_pci_register_driver(&atiixp_pci_driver); -} - -static void __exit atiixp_ide_exit(void) -{ - pci_unregister_driver(&atiixp_pci_driver); -} - -module_init(atiixp_ide_init); -module_exit(atiixp_ide_exit); - -MODULE_AUTHOR("HUI YU"); -MODULE_DESCRIPTION("PCI driver module for ATI IXP IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/buddha.c b/drivers/ide/buddha.c deleted file mode 100644 index 46eaf58d881b..000000000000 --- a/drivers/ide/buddha.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Amiga Buddha, Catweasel and X-Surf IDE Driver - * - * Copyright (C) 1997, 2001 by Geert Uytterhoeven and others - * - * This driver was written based on the specifications in README.buddha and - * the X-Surf info from Inside_XSurf.txt available at - * http://www.jschoenfeld.com - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * - * TODO: - * - test it :-) - * - tune the timings using the speed-register - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - - /* - * The Buddha has 2 IDE interfaces, the Catweasel has 3, X-Surf has 2 - */ - -#define BUDDHA_NUM_HWIFS 2 -#define CATWEASEL_NUM_HWIFS 3 -#define XSURF_NUM_HWIFS 2 - -#define MAX_NUM_HWIFS 3 - - /* - * Bases of the IDE interfaces (relative to the board address) - */ - -#define BUDDHA_BASE1 0x800 -#define BUDDHA_BASE2 0xa00 -#define BUDDHA_BASE3 0xc00 - -#define XSURF_BASE1 0xb000 /* 2.5" Interface */ -#define XSURF_BASE2 0xd000 /* 3.5" Interface */ - -static u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = { - BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3 -}; - -static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = { - XSURF_BASE1, XSURF_BASE2 -}; - - /* - * Offsets from one of the above bases - */ - -#define BUDDHA_CONTROL 0x11a - - /* - * Other registers - */ - -#define BUDDHA_IRQ1 0xf00 /* MSB = 1, Harddisk is source of */ -#define BUDDHA_IRQ2 0xf40 /* interrupt */ -#define BUDDHA_IRQ3 0xf80 - -#define XSURF_IRQ1 0x7e -#define XSURF_IRQ2 0x7e - -static int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = { - BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3 -}; - -static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = { - XSURF_IRQ1, XSURF_IRQ2 -}; - -#define BUDDHA_IRQ_MR 0xfc0 /* master interrupt enable */ - - - /* - * Board information - */ - -typedef enum BuddhaType_Enum { - BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF -} BuddhaType; - -static const char *buddha_board_name[] = { "Buddha", "Catweasel", "X-Surf" }; - - /* - * Check and acknowledge the interrupt status - */ - -static int buddha_test_irq(ide_hwif_t *hwif) -{ - unsigned char ch; - - ch = z_readb(hwif->io_ports.irq_addr); - if (!(ch & 0x80)) - return 0; - return 1; -} - -static void xsurf_clear_irq(ide_drive_t *drive) -{ - /* - * X-Surf needs 0 written to IRQ register to ensure ISA bit A11 stays at 0 - */ - z_writeb(0, drive->hwif->io_ports.irq_addr); -} - -static void __init buddha_setup_ports(struct ide_hw *hw, unsigned long base, - unsigned long ctl, unsigned long irq_port) -{ - int i; - - memset(hw, 0, sizeof(*hw)); - - hw->io_ports.data_addr = base; - - for (i = 1; i < 8; i++) - hw->io_ports_array[i] = base + 2 + i * 4; - - hw->io_ports.ctl_addr = ctl; - hw->io_ports.irq_addr = irq_port; - - hw->irq = IRQ_AMIGA_PORTS; -} - -static const struct ide_port_ops buddha_port_ops = { - .test_irq = buddha_test_irq, -}; - -static const struct ide_port_ops xsurf_port_ops = { - .clear_irq = xsurf_clear_irq, - .test_irq = buddha_test_irq, -}; - -static const struct ide_port_info buddha_port_info = { - .port_ops = &buddha_port_ops, - .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, - .irq_flags = IRQF_SHARED, - .chipset = ide_generic, -}; - - /* - * Probe for a Buddha or Catweasel IDE interface - */ - -static int __init buddha_init(void) -{ - struct zorro_dev *z = NULL; - u_long buddha_board = 0; - BuddhaType type; - int buddha_num_hwifs, i; - - while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { - unsigned long board; - struct ide_hw hw[MAX_NUM_HWIFS], *hws[MAX_NUM_HWIFS]; - struct ide_port_info d = buddha_port_info; - - if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) { - buddha_num_hwifs = BUDDHA_NUM_HWIFS; - type=BOARD_BUDDHA; - } else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) { - buddha_num_hwifs = CATWEASEL_NUM_HWIFS; - type=BOARD_CATWEASEL; - } else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) { - buddha_num_hwifs = XSURF_NUM_HWIFS; - type=BOARD_XSURF; - d.port_ops = &xsurf_port_ops; - } else - continue; - - board = z->resource.start; - - if(type != BOARD_XSURF) { - if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE")) - continue; - } else { - if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE")) - continue; - if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE")) - goto fail_base2; - if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) { - release_mem_region(board+XSURF_BASE2, 0x1000); -fail_base2: - release_mem_region(board+XSURF_BASE1, 0x1000); - continue; - } - } - buddha_board = (unsigned long)ZTWO_VADDR(board); - - /* write to BUDDHA_IRQ_MR to enable the board IRQ */ - /* X-Surf doesn't have this. IRQs are always on */ - if (type != BOARD_XSURF) - z_writeb(0, buddha_board+BUDDHA_IRQ_MR); - - printk(KERN_INFO "ide: %s IDE controller\n", - buddha_board_name[type]); - - for (i = 0; i < buddha_num_hwifs; i++) { - unsigned long base, ctl, irq_port; - - if (type != BOARD_XSURF) { - base = buddha_board + buddha_bases[i]; - ctl = base + BUDDHA_CONTROL; - irq_port = buddha_board + buddha_irqports[i]; - } else { - base = buddha_board + xsurf_bases[i]; - /* X-Surf has no CS1* (Control/AltStat) */ - ctl = 0; - irq_port = buddha_board + xsurf_irqports[i]; - } - - buddha_setup_ports(&hw[i], base, ctl, irq_port); - - hws[i] = &hw[i]; - } - - ide_host_add(&d, hws, i, NULL); - } - - return 0; -} - -module_init(buddha_init); - -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c deleted file mode 100644 index f48decb9fac4..000000000000 --- a/drivers/ide/cmd640.c +++ /dev/null @@ -1,848 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1995-1996 Linus Torvalds & authors (see below) - */ - -/* - * Original authors: abramov@cecmow.enet.dec.com (Igor Abramov) - * mlord@pobox.com (Mark Lord) - * - * See linux/MAINTAINERS for address of current maintainer. - * - * This file provides support for the advanced features and bugs - * of IDE interfaces using the CMD Technologies 0640 IDE interface chip. - * - * These chips are basically fucked by design, and getting this driver - * to work on every motherboard design that uses this screwed chip seems - * bloody well impossible. However, we're still trying. - * - * Version 0.97 worked for everybody. - * - * User feedback is essential. Many thanks to the beta test team: - * - * A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com, - * bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz, - * chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de, - * derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de, - * flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net, - * j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net, - * kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu, - * peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com, - * s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net, - * steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com - * liug@mama.indstate.edu, and others. - * - * Version 0.01 Initial version, hacked out of ide.c, - * and #include'd rather than compiled separately. - * This will get cleaned up in a subsequent release. - * - * Version 0.02 Fixes for vlb initialization code, enable prefetch - * for versions 'B' and 'C' of chip by default, - * some code cleanup. - * - * Version 0.03 Added reset of secondary interface, - * and black list for devices which are not compatible - * with prefetch mode. Separate function for setting - * prefetch is added, possibly it will be called some - * day from ioctl processing code. - * - * Version 0.04 Now configs/compiles separate from ide.c - * - * Version 0.05 Major rewrite of interface timing code. - * Added new function cmd640_set_mode to set PIO mode - * from ioctl call. New drives added to black list. - * - * Version 0.06 More code cleanup. Prefetch is enabled only for - * detected hard drives, not included in prefetch - * black list. - * - * Version 0.07 Changed to more conservative drive tuning policy. - * Unknown drives, which report PIO < 4 are set to - * (reported_PIO - 1) if it is supported, or to PIO0. - * List of known drives extended by info provided by - * CMD at their ftp site. - * - * Version 0.08 Added autotune/noautotune support. - * - * Version 0.09 Try to be smarter about 2nd port enabling. - * Version 0.10 Be nice and don't reset 2nd port. - * Version 0.11 Try to handle more weird situations. - * - * Version 0.12 Lots of bug fixes from Laszlo Peter - * irq unmasking disabled for reliability. - * try to be even smarter about the second port. - * tidy up source code formatting. - * Version 0.13 permit irq unmasking again. - * Version 0.90 massive code cleanup, some bugs fixed. - * defaults all drives to PIO mode0, prefetch off. - * autotune is OFF by default, with compile time flag. - * prefetch can be turned OFF/ON using "hdparm -p8/-p9" - * (requires hdparm-3.1 or newer) - * Version 0.91 first release to linux-kernel list. - * Version 0.92 move initial reg dump to separate callable function - * change "readahead" to "prefetch" to avoid confusion - * Version 0.95 respect original BIOS timings unless autotuning. - * tons of code cleanup and rearrangement. - * added CONFIG_BLK_DEV_CMD640_ENHANCED option - * prevent use of unmask when prefetch is on - * Version 0.96 prevent use of io_32bit when prefetch is off - * Version 0.97 fix VLB secondary interface for sjd@slip.net - * other minor tune-ups: 0.96 was very good. - * Version 0.98 ignore PCI version when disabled by BIOS - * Version 0.99 display setup/active/recovery clocks with PIO mode - * Version 1.00 Mmm.. cannot depend on PCMD_ENA in all systems - * Version 1.01 slow/fast devsel can be selected with "hdparm -p6/-p7" - * ("fast" is necessary for 32bit I/O in some systems) - * Version 1.02 fix bug that resulted in slow "setup times" - * (patch courtesy of Zoltan Hidvegi) - */ - -#define CMD640_PREFETCH_MASKS 1 - -/*#define CMD640_DUMP_REGS */ - -#include -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "cmd640" - -static bool cmd640_vlb; - -/* - * CMD640 specific registers definition. - */ - -#define VID 0x00 -#define DID 0x02 -#define PCMD 0x04 -#define PCMD_ENA 0x01 -#define PSTTS 0x06 -#define REVID 0x08 -#define PROGIF 0x09 -#define SUBCL 0x0a -#define BASCL 0x0b -#define BaseA0 0x10 -#define BaseA1 0x14 -#define BaseA2 0x18 -#define BaseA3 0x1c -#define INTLINE 0x3c -#define INPINE 0x3d - -#define CFR 0x50 -#define CFR_DEVREV 0x03 -#define CFR_IDE01INTR 0x04 -#define CFR_DEVID 0x18 -#define CFR_AT_VESA_078h 0x20 -#define CFR_DSA1 0x40 -#define CFR_DSA0 0x80 - -#define CNTRL 0x51 -#define CNTRL_DIS_RA0 0x40 -#define CNTRL_DIS_RA1 0x80 -#define CNTRL_ENA_2ND 0x08 - -#define CMDTIM 0x52 -#define ARTTIM0 0x53 -#define DRWTIM0 0x54 -#define ARTTIM1 0x55 -#define DRWTIM1 0x56 -#define ARTTIM23 0x57 -#define ARTTIM23_DIS_RA2 0x04 -#define ARTTIM23_DIS_RA3 0x08 -#define ARTTIM23_IDE23INTR 0x10 -#define DRWTIM23 0x58 -#define BRST 0x59 - -/* - * Registers and masks for easy access by drive index: - */ -static u8 prefetch_regs[4] = {CNTRL, CNTRL, ARTTIM23, ARTTIM23}; -static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3}; - -#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED - -static u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23}; -static u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23}; - -/* - * Current cmd640 timing values for each drive. - * The defaults for each are the slowest possible timings. - */ -static u8 setup_counts[4] = {4, 4, 4, 4}; /* Address setup count (in clocks) */ -static u8 active_counts[4] = {16, 16, 16, 16}; /* Active count (encoded) */ -static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */ - -#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ - -static DEFINE_SPINLOCK(cmd640_lock); - -/* - * Interface to access cmd640x registers - */ -static unsigned int cmd640_key; -static void (*__put_cmd640_reg)(u16 reg, u8 val); -static u8 (*__get_cmd640_reg)(u16 reg); - -/* - * This is read from the CFR reg, and is used in several places. - */ -static unsigned int cmd640_chip_version; - -/* - * The CMD640x chip does not support DWORD config write cycles, but some - * of the BIOSes use them to implement the config services. - * Therefore, we must use direct IO instead. - */ - -/* PCI method 1 access */ - -static void put_cmd640_reg_pci1(u16 reg, u8 val) -{ - outl_p((reg & 0xfc) | cmd640_key, 0xcf8); - outb_p(val, (reg & 3) | 0xcfc); -} - -static u8 get_cmd640_reg_pci1(u16 reg) -{ - outl_p((reg & 0xfc) | cmd640_key, 0xcf8); - return inb_p((reg & 3) | 0xcfc); -} - -/* PCI method 2 access (from CMD datasheet) */ - -static void put_cmd640_reg_pci2(u16 reg, u8 val) -{ - outb_p(0x10, 0xcf8); - outb_p(val, cmd640_key + reg); - outb_p(0, 0xcf8); -} - -static u8 get_cmd640_reg_pci2(u16 reg) -{ - u8 b; - - outb_p(0x10, 0xcf8); - b = inb_p(cmd640_key + reg); - outb_p(0, 0xcf8); - return b; -} - -/* VLB access */ - -static void put_cmd640_reg_vlb(u16 reg, u8 val) -{ - outb_p(reg, cmd640_key); - outb_p(val, cmd640_key + 4); -} - -static u8 get_cmd640_reg_vlb(u16 reg) -{ - outb_p(reg, cmd640_key); - return inb_p(cmd640_key + 4); -} - -static u8 get_cmd640_reg(u16 reg) -{ - unsigned long flags; - u8 b; - - spin_lock_irqsave(&cmd640_lock, flags); - b = __get_cmd640_reg(reg); - spin_unlock_irqrestore(&cmd640_lock, flags); - return b; -} - -static void put_cmd640_reg(u16 reg, u8 val) -{ - unsigned long flags; - - spin_lock_irqsave(&cmd640_lock, flags); - __put_cmd640_reg(reg, val); - spin_unlock_irqrestore(&cmd640_lock, flags); -} - -static int __init match_pci_cmd640_device(void) -{ - const u8 ven_dev[4] = {0x95, 0x10, 0x40, 0x06}; - unsigned int i; - for (i = 0; i < 4; i++) { - if (get_cmd640_reg(i) != ven_dev[i]) - return 0; - } -#ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT - if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) { - printk("ide: cmd640 on PCI disabled by BIOS\n"); - return 0; - } -#endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */ - return 1; /* success */ -} - -/* - * Probe for CMD640x -- pci method 1 - */ -static int __init probe_for_cmd640_pci1(void) -{ - __get_cmd640_reg = get_cmd640_reg_pci1; - __put_cmd640_reg = put_cmd640_reg_pci1; - for (cmd640_key = 0x80000000; - cmd640_key <= 0x8000f800; - cmd640_key += 0x800) { - if (match_pci_cmd640_device()) - return 1; /* success */ - } - return 0; -} - -/* - * Probe for CMD640x -- pci method 2 - */ -static int __init probe_for_cmd640_pci2(void) -{ - __get_cmd640_reg = get_cmd640_reg_pci2; - __put_cmd640_reg = put_cmd640_reg_pci2; - for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) { - if (match_pci_cmd640_device()) - return 1; /* success */ - } - return 0; -} - -/* - * Probe for CMD640x -- vlb - */ -static int __init probe_for_cmd640_vlb(void) -{ - u8 b; - - __get_cmd640_reg = get_cmd640_reg_vlb; - __put_cmd640_reg = put_cmd640_reg_vlb; - cmd640_key = 0x178; - b = get_cmd640_reg(CFR); - if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) { - cmd640_key = 0x78; - b = get_cmd640_reg(CFR); - if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h)) - return 0; - } - return 1; /* success */ -} - -/* - * Returns 1 if an IDE interface/drive exists at 0x170, - * Returns 0 otherwise. - */ -static int __init secondary_port_responding(void) -{ - unsigned long flags; - - spin_lock_irqsave(&cmd640_lock, flags); - - outb_p(0x0a, 0x176); /* select drive0 */ - udelay(100); - if ((inb_p(0x176) & 0x1f) != 0x0a) { - outb_p(0x1a, 0x176); /* select drive1 */ - udelay(100); - if ((inb_p(0x176) & 0x1f) != 0x1a) { - spin_unlock_irqrestore(&cmd640_lock, flags); - return 0; /* nothing responded */ - } - } - spin_unlock_irqrestore(&cmd640_lock, flags); - return 1; /* success */ -} - -#ifdef CMD640_DUMP_REGS -/* - * Dump out all cmd640 registers. May be called from ide.c - */ -static void cmd640_dump_regs(void) -{ - unsigned int reg = cmd640_vlb ? 0x50 : 0x00; - - /* Dump current state of chip registers */ - printk("ide: cmd640 internal register dump:"); - for (; reg <= 0x59; reg++) { - if (!(reg & 0x0f)) - printk("\n%04x:", reg); - printk(" %02x", get_cmd640_reg(reg)); - } - printk("\n"); -} -#endif - -static void __set_prefetch_mode(ide_drive_t *drive, int mode) -{ - if (mode) { /* want prefetch on? */ -#if CMD640_PREFETCH_MASKS - drive->dev_flags |= IDE_DFLAG_NO_UNMASK; - drive->dev_flags &= ~IDE_DFLAG_UNMASK; -#endif - drive->dev_flags &= ~IDE_DFLAG_NO_IO_32BIT; - } else { - drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK; - drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT; - drive->io_32bit = 0; - } -} - -#ifndef CONFIG_BLK_DEV_CMD640_ENHANCED -/* - * Check whether prefetch is on for a drive, - * and initialize the unmask flags for safe operation. - */ -static void __init check_prefetch(ide_drive_t *drive, unsigned int index) -{ - u8 b = get_cmd640_reg(prefetch_regs[index]); - - __set_prefetch_mode(drive, (b & prefetch_masks[index]) ? 0 : 1); -} -#else - -/* - * Sets prefetch mode for a drive. - */ -static void set_prefetch_mode(ide_drive_t *drive, unsigned int index, int mode) -{ - unsigned long flags; - int reg = prefetch_regs[index]; - u8 b; - - spin_lock_irqsave(&cmd640_lock, flags); - b = __get_cmd640_reg(reg); - __set_prefetch_mode(drive, mode); - if (mode) - b &= ~prefetch_masks[index]; /* enable prefetch */ - else - b |= prefetch_masks[index]; /* disable prefetch */ - __put_cmd640_reg(reg, b); - spin_unlock_irqrestore(&cmd640_lock, flags); -} - -/* - * Dump out current drive clocks settings - */ -static void display_clocks(unsigned int index) -{ - u8 active_count, recovery_count; - - active_count = active_counts[index]; - if (active_count == 1) - ++active_count; - recovery_count = recovery_counts[index]; - if (active_count > 3 && recovery_count == 1) - ++recovery_count; - if (cmd640_chip_version > 1) - recovery_count += 1; /* cmd640b uses (count + 1)*/ - printk(", clocks=%d/%d/%d\n", setup_counts[index], active_count, recovery_count); -} - -/* - * Pack active and recovery counts into single byte representation - * used by controller - */ -static inline u8 pack_nibbles(u8 upper, u8 lower) -{ - return ((upper & 0x0f) << 4) | (lower & 0x0f); -} - -/* - * This routine writes the prepared setup/active/recovery counts - * for a drive into the cmd640 chipset registers to active them. - */ -static void program_drive_counts(ide_drive_t *drive, unsigned int index) -{ - unsigned long flags; - u8 setup_count = setup_counts[index]; - u8 active_count = active_counts[index]; - u8 recovery_count = recovery_counts[index]; - - /* - * Set up address setup count and drive read/write timing registers. - * Primary interface has individual count/timing registers for - * each drive. Secondary interface has one common set of registers, - * so we merge the timings, using the slowest value for each timing. - */ - if (index > 1) { - ide_drive_t *peer = ide_get_pair_dev(drive); - unsigned int mate = index ^ 1; - - if (peer) { - if (setup_count < setup_counts[mate]) - setup_count = setup_counts[mate]; - if (active_count < active_counts[mate]) - active_count = active_counts[mate]; - if (recovery_count < recovery_counts[mate]) - recovery_count = recovery_counts[mate]; - } - } - - /* - * Convert setup_count to internal chipset representation - */ - switch (setup_count) { - case 4: setup_count = 0x00; break; - case 3: setup_count = 0x80; break; - case 1: - case 2: setup_count = 0x40; break; - default: setup_count = 0xc0; /* case 5 */ - } - - /* - * Now that everything is ready, program the new timings - */ - spin_lock_irqsave(&cmd640_lock, flags); - /* - * Program the address_setup clocks into ARTTIM reg, - * and then the active/recovery counts into the DRWTIM reg - * (this converts counts of 16 into counts of zero -- okay). - */ - setup_count |= __get_cmd640_reg(arttim_regs[index]) & 0x3f; - __put_cmd640_reg(arttim_regs[index], setup_count); - __put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count)); - spin_unlock_irqrestore(&cmd640_lock, flags); -} - -/* - * Set a specific pio_mode for a drive - */ -static void cmd640_set_mode(ide_drive_t *drive, unsigned int index, - u8 pio_mode, unsigned int cycle_time) -{ - struct ide_timing *t; - int setup_time, active_time, recovery_time, clock_time; - u8 setup_count, active_count, recovery_count, recovery_count2, cycle_count; - int bus_speed; - - if (cmd640_vlb) - bus_speed = ide_vlb_clk ? ide_vlb_clk : 50; - else - bus_speed = ide_pci_clk ? ide_pci_clk : 33; - - if (pio_mode > 5) - pio_mode = 5; - - t = ide_timing_find_mode(XFER_PIO_0 + pio_mode); - setup_time = t->setup; - active_time = t->active; - - recovery_time = cycle_time - (setup_time + active_time); - clock_time = 1000 / bus_speed; - cycle_count = DIV_ROUND_UP(cycle_time, clock_time); - - setup_count = DIV_ROUND_UP(setup_time, clock_time); - - active_count = DIV_ROUND_UP(active_time, clock_time); - if (active_count < 2) - active_count = 2; /* minimum allowed by cmd640 */ - - recovery_count = DIV_ROUND_UP(recovery_time, clock_time); - recovery_count2 = cycle_count - (setup_count + active_count); - if (recovery_count2 > recovery_count) - recovery_count = recovery_count2; - if (recovery_count < 2) - recovery_count = 2; /* minimum allowed by cmd640 */ - if (recovery_count > 17) { - active_count += recovery_count - 17; - recovery_count = 17; - } - if (active_count > 16) - active_count = 16; /* maximum allowed by cmd640 */ - if (cmd640_chip_version > 1) - recovery_count -= 1; /* cmd640b uses (count + 1)*/ - if (recovery_count > 16) - recovery_count = 16; /* maximum allowed by cmd640 */ - - setup_counts[index] = setup_count; - active_counts[index] = active_count; - recovery_counts[index] = recovery_count; - - /* - * In a perfect world, we might set the drive pio mode here - * (using WIN_SETFEATURE) before continuing. - * - * But we do not, because: - * 1) this is the wrong place to do it (proper is do_special() in ide.c) - * 2) in practice this is rarely, if ever, necessary - */ - program_drive_counts(drive, index); -} - -static void cmd640_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - unsigned int index = 0, cycle_time; - const u8 pio = drive->pio_mode - XFER_PIO_0; - u8 b; - - switch (pio) { - case 6: /* set fast-devsel off */ - case 7: /* set fast-devsel on */ - b = get_cmd640_reg(CNTRL) & ~0x27; - if (pio & 1) - b |= 0x27; - put_cmd640_reg(CNTRL, b); - printk("%s: %sabled cmd640 fast host timing (devsel)\n", - drive->name, (pio & 1) ? "en" : "dis"); - return; - case 8: /* set prefetch off */ - case 9: /* set prefetch on */ - set_prefetch_mode(drive, index, pio & 1); - printk("%s: %sabled cmd640 prefetch\n", - drive->name, (pio & 1) ? "en" : "dis"); - return; - } - - cycle_time = ide_pio_cycle_time(drive, pio); - cmd640_set_mode(drive, index, pio, cycle_time); - - printk("%s: selected cmd640 PIO mode%d (%dns)", - drive->name, pio, cycle_time); - - display_clocks(index); -} -#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ - -static void __init cmd640_init_dev(ide_drive_t *drive) -{ - unsigned int i = drive->hwif->channel * 2 + (drive->dn & 1); - -#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED - /* - * Reset timing to the slowest speed and turn off prefetch. - * This way, the drive identify code has a better chance. - */ - setup_counts[i] = 4; /* max possible */ - active_counts[i] = 16; /* max possible */ - recovery_counts[i] = 16; /* max possible */ - program_drive_counts(drive, i); - set_prefetch_mode(drive, i, 0); - printk(KERN_INFO DRV_NAME ": drive%d timings/prefetch cleared\n", i); -#else - /* - * Set the drive unmask flags to match the prefetch setting. - */ - check_prefetch(drive, i); - printk(KERN_INFO DRV_NAME ": drive%d timings/prefetch(%s) preserved\n", - i, (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT) ? "off" : "on"); -#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ -} - -static int cmd640_test_irq(ide_hwif_t *hwif) -{ - int irq_reg = hwif->channel ? ARTTIM23 : CFR; - u8 irq_mask = hwif->channel ? ARTTIM23_IDE23INTR : - CFR_IDE01INTR; - u8 irq_stat = get_cmd640_reg(irq_reg); - - return (irq_stat & irq_mask) ? 1 : 0; -} - -static const struct ide_port_ops cmd640_port_ops = { - .init_dev = cmd640_init_dev, -#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED - .set_pio_mode = cmd640_set_pio_mode, -#endif - .test_irq = cmd640_test_irq, -}; - -static int pci_conf1(void) -{ - unsigned long flags; - u32 tmp; - - spin_lock_irqsave(&cmd640_lock, flags); - outb(0x01, 0xCFB); - tmp = inl(0xCF8); - outl(0x80000000, 0xCF8); - if (inl(0xCF8) == 0x80000000) { - outl(tmp, 0xCF8); - spin_unlock_irqrestore(&cmd640_lock, flags); - return 1; - } - outl(tmp, 0xCF8); - spin_unlock_irqrestore(&cmd640_lock, flags); - return 0; -} - -static int pci_conf2(void) -{ - unsigned long flags; - - spin_lock_irqsave(&cmd640_lock, flags); - outb(0x00, 0xCFB); - outb(0x00, 0xCF8); - outb(0x00, 0xCFA); - if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) { - spin_unlock_irqrestore(&cmd640_lock, flags); - return 1; - } - spin_unlock_irqrestore(&cmd640_lock, flags); - return 0; -} - -static const struct ide_port_info cmd640_port_info __initconst = { - .chipset = ide_cmd640, - .host_flags = IDE_HFLAG_SERIALIZE | - IDE_HFLAG_NO_DMA | - IDE_HFLAG_ABUSE_PREFETCH | - IDE_HFLAG_ABUSE_FAST_DEVSEL, - .port_ops = &cmd640_port_ops, - .pio_mask = ATA_PIO5, -}; - -static int __init cmd640x_init_one(unsigned long base, unsigned long ctl) -{ - if (!request_region(base, 8, DRV_NAME)) { - printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n", - DRV_NAME, base, base + 7); - return -EBUSY; - } - - if (!request_region(ctl, 1, DRV_NAME)) { - printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n", - DRV_NAME, ctl); - release_region(base, 8); - return -EBUSY; - } - - return 0; -} - -/* - * Probe for a cmd640 chipset, and initialize it if found. - */ -static int __init cmd640x_init(void) -{ - int second_port_cmd640 = 0, rc; - const char *bus_type, *port2; - u8 b, cfr; - struct ide_hw hw[2], *hws[2]; - - if (cmd640_vlb && probe_for_cmd640_vlb()) { - bus_type = "VLB"; - } else { - cmd640_vlb = 0; - /* Find out what kind of PCI probing is supported otherwise - Justin Gibbs will sulk.. */ - if (pci_conf1() && probe_for_cmd640_pci1()) - bus_type = "PCI (type1)"; - else if (pci_conf2() && probe_for_cmd640_pci2()) - bus_type = "PCI (type2)"; - else - return 0; - } - /* - * Undocumented magic (there is no 0x5b reg in specs) - */ - put_cmd640_reg(0x5b, 0xbd); - if (get_cmd640_reg(0x5b) != 0xbd) { - printk(KERN_ERR "ide: cmd640 init failed: wrong value in reg 0x5b\n"); - return 0; - } - put_cmd640_reg(0x5b, 0); - -#ifdef CMD640_DUMP_REGS - cmd640_dump_regs(); -#endif - - /* - * Documented magic begins here - */ - cfr = get_cmd640_reg(CFR); - cmd640_chip_version = cfr & CFR_DEVREV; - if (cmd640_chip_version == 0) { - printk("ide: bad cmd640 revision: %d\n", cmd640_chip_version); - return 0; - } - - rc = cmd640x_init_one(0x1f0, 0x3f6); - if (rc) - return rc; - - rc = cmd640x_init_one(0x170, 0x376); - if (rc) { - release_region(0x3f6, 1); - release_region(0x1f0, 8); - return rc; - } - - memset(&hw, 0, sizeof(hw)); - - ide_std_init_ports(&hw[0], 0x1f0, 0x3f6); - hw[0].irq = 14; - - ide_std_init_ports(&hw[1], 0x170, 0x376); - hw[1].irq = 15; - - printk(KERN_INFO "cmd640: buggy cmd640%c interface on %s, config=0x%02x" - "\n", 'a' + cmd640_chip_version - 1, bus_type, cfr); - - /* - * Initialize data for primary port - */ - hws[0] = &hw[0]; - - /* - * Ensure compatibility by always using the slowest timings - * for access to the drive's command register block, - * and reset the prefetch burstsize to default (512 bytes). - * - * Maybe we need a way to NOT do these on *some* systems? - */ - put_cmd640_reg(CMDTIM, 0); - put_cmd640_reg(BRST, 0x40); - - b = get_cmd640_reg(CNTRL); - - /* - * Try to enable the secondary interface, if not already enabled - */ - if (secondary_port_responding()) { - if ((b & CNTRL_ENA_2ND)) { - second_port_cmd640 = 1; - port2 = "okay"; - } else if (cmd640_vlb) { - second_port_cmd640 = 1; - port2 = "alive"; - } else - port2 = "not cmd640"; - } else { - put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */ - if (secondary_port_responding()) { - second_port_cmd640 = 1; - port2 = "enabled"; - } else { - put_cmd640_reg(CNTRL, b); /* restore original setting */ - port2 = "not responding"; - } - } - - /* - * Initialize data for secondary cmd640 port, if enabled - */ - if (second_port_cmd640) - hws[1] = &hw[1]; - - printk(KERN_INFO "cmd640: %sserialized, secondary interface %s\n", - second_port_cmd640 ? "" : "not ", port2); - -#ifdef CMD640_DUMP_REGS - cmd640_dump_regs(); -#endif - - return ide_host_add(&cmd640_port_info, hws, second_port_cmd640 ? 2 : 1, - NULL); -} - -module_param_named(probe_vlb, cmd640_vlb, bool, 0); -MODULE_PARM_DESC(probe_vlb, "probe for VLB version of CMD640 chipset"); - -module_init(cmd640x_init); - -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c deleted file mode 100644 index 943bf944bf72..000000000000 --- a/drivers/ide/cmd64x.c +++ /dev/null @@ -1,452 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines. - * Due to massive hardware bugs, UltraDMA is only supported - * on the 646U2 and not on the 646U. - * - * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1998 David S. Miller (davem@redhat.com) - * - * Copyright (C) 1999-2002 Andre Hedrick - * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz - * Copyright (C) 2007,2009 MontaVista Software, Inc. - */ - -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "cmd64x" - -/* - * CMD64x specific registers definition. - */ -#define CFR 0x50 -#define CFR_INTR_CH0 0x04 - -#define CMDTIM 0x52 -#define ARTTIM0 0x53 -#define DRWTIM0 0x54 -#define ARTTIM1 0x55 -#define DRWTIM1 0x56 -#define ARTTIM23 0x57 -#define ARTTIM23_DIS_RA2 0x04 -#define ARTTIM23_DIS_RA3 0x08 -#define ARTTIM23_INTR_CH1 0x10 -#define DRWTIM2 0x58 -#define BRST 0x59 -#define DRWTIM3 0x5b - -#define BMIDECR0 0x70 -#define MRDMODE 0x71 -#define MRDMODE_INTR_CH0 0x04 -#define MRDMODE_INTR_CH1 0x08 -#define UDIDETCR0 0x73 -#define DTPR0 0x74 -#define BMIDECR1 0x78 -#define BMIDECSR 0x79 -#define UDIDETCR1 0x7B -#define DTPR1 0x7C - -static void cmd64x_program_timings(ide_drive_t *drive, u8 mode) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(drive->hwif->dev); - int bus_speed = ide_pci_clk ? ide_pci_clk : 33; - const unsigned long T = 1000000 / bus_speed; - static const u8 recovery_values[] = - {15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0}; - static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; - static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23}; - static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3}; - struct ide_timing t; - u8 arttim = 0; - - if (drive->dn >= ARRAY_SIZE(drwtim_regs)) - return; - - ide_timing_compute(drive, mode, &t, T, 0); - - /* - * In case we've got too long recovery phase, try to lengthen - * the active phase - */ - if (t.recover > 16) { - t.active += t.recover - 16; - t.recover = 16; - } - if (t.active > 16) /* shouldn't actually happen... */ - t.active = 16; - - /* - * Convert values to internal chipset representation - */ - t.recover = recovery_values[t.recover]; - t.active &= 0x0f; - - /* Program the active/recovery counts into the DRWTIM register */ - pci_write_config_byte(dev, drwtim_regs[drive->dn], - (t.active << 4) | t.recover); - - /* - * The primary channel has individual address setup timing registers - * for each drive and the hardware selects the slowest timing itself. - * The secondary channel has one common register and we have to select - * the slowest address setup timing ourselves. - */ - if (hwif->channel) { - ide_drive_t *pair = ide_get_pair_dev(drive); - - if (pair) { - struct ide_timing tp; - - ide_timing_compute(pair, pair->pio_mode, &tp, T, 0); - ide_timing_merge(&t, &tp, &t, IDE_TIMING_SETUP); - if (pair->dma_mode) { - ide_timing_compute(pair, pair->dma_mode, - &tp, T, 0); - ide_timing_merge(&tp, &t, &t, IDE_TIMING_SETUP); - } - } - } - - if (t.setup > 5) /* shouldn't actually happen... */ - t.setup = 5; - - /* - * Program the address setup clocks into the ARTTIM registers. - * Avoid clearing the secondary channel's interrupt bit. - */ - (void) pci_read_config_byte (dev, arttim_regs[drive->dn], &arttim); - if (hwif->channel) - arttim &= ~ARTTIM23_INTR_CH1; - arttim &= ~0xc0; - arttim |= setup_values[t.setup]; - (void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim); -} - -/* - * Attempts to set drive's PIO mode. - * Special cases are 8: prefetch off, 9: prefetch on (both never worked) - */ - -static void cmd64x_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - const u8 pio = drive->pio_mode - XFER_PIO_0; - - /* - * Filter out the prefetch control values - * to prevent PIO5 from being programmed - */ - if (pio == 8 || pio == 9) - return; - - cmd64x_program_timings(drive, XFER_PIO_0 + pio); -} - -static void cmd64x_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 unit = drive->dn & 0x01; - u8 regU = 0, pciU = hwif->channel ? UDIDETCR1 : UDIDETCR0; - const u8 speed = drive->dma_mode; - - pci_read_config_byte(dev, pciU, ®U); - regU &= ~(unit ? 0xCA : 0x35); - - switch(speed) { - case XFER_UDMA_5: - regU |= unit ? 0x0A : 0x05; - break; - case XFER_UDMA_4: - regU |= unit ? 0x4A : 0x15; - break; - case XFER_UDMA_3: - regU |= unit ? 0x8A : 0x25; - break; - case XFER_UDMA_2: - regU |= unit ? 0x42 : 0x11; - break; - case XFER_UDMA_1: - regU |= unit ? 0x82 : 0x21; - break; - case XFER_UDMA_0: - regU |= unit ? 0xC2 : 0x31; - break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - cmd64x_program_timings(drive, speed); - break; - } - - pci_write_config_byte(dev, pciU, regU); -} - -static void cmd648_clear_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long base = pci_resource_start(dev, 4); - u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 : - MRDMODE_INTR_CH0; - u8 mrdmode = inb(base + 1); - - /* clear the interrupt bit */ - outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask, - base + 1); -} - -static void cmd64x_clear_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - int irq_reg = hwif->channel ? ARTTIM23 : CFR; - u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 : - CFR_INTR_CH0; - u8 irq_stat = 0; - - (void) pci_read_config_byte(dev, irq_reg, &irq_stat); - /* clear the interrupt bit */ - (void) pci_write_config_byte(dev, irq_reg, irq_stat | irq_mask); -} - -static int cmd648_test_irq(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long base = pci_resource_start(dev, 4); - u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 : - MRDMODE_INTR_CH0; - u8 mrdmode = inb(base + 1); - - pr_debug("%s: mrdmode: 0x%02x irq_mask: 0x%02x\n", - hwif->name, mrdmode, irq_mask); - - return (mrdmode & irq_mask) ? 1 : 0; -} - -static int cmd64x_test_irq(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - int irq_reg = hwif->channel ? ARTTIM23 : CFR; - u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 : - CFR_INTR_CH0; - u8 irq_stat = 0; - - (void) pci_read_config_byte(dev, irq_reg, &irq_stat); - - pr_debug("%s: irq_stat: 0x%02x irq_mask: 0x%02x\n", - hwif->name, irq_stat, irq_mask); - - return (irq_stat & irq_mask) ? 1 : 0; -} - -/* - * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old - * event order for DMA transfers. - */ - -static int cmd646_1_dma_end(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u8 dma_stat = 0, dma_cmd = 0; - - /* get DMA status */ - dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); - /* read DMA command state */ - dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); - /* stop DMA */ - outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD); - /* clear the INTR & ERROR bits */ - outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS); - /* verify good DMA status */ - return (dma_stat & 7) != 4; -} - -static int init_chipset_cmd64x(struct pci_dev *dev) -{ - u8 mrdmode = 0; - - /* Set a good latency timer and cache line size value. */ - (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); - /* FIXME: pci_set_master() to ensure a good latency timer value */ - - /* - * Enable interrupts, select MEMORY READ LINE for reads. - * - * NOTE: although not mentioned in the PCI0646U specs, - * bits 0-1 are write only and won't be read back as - * set or not -- PCI0646U2 specs clarify this point. - */ - (void) pci_read_config_byte (dev, MRDMODE, &mrdmode); - mrdmode &= ~0x30; - (void) pci_write_config_byte(dev, MRDMODE, (mrdmode | 0x02)); - - return 0; -} - -static u8 cmd64x_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 bmidecsr = 0, mask = hwif->channel ? 0x02 : 0x01; - - switch (dev->device) { - case PCI_DEVICE_ID_CMD_648: - case PCI_DEVICE_ID_CMD_649: - pci_read_config_byte(dev, BMIDECSR, &bmidecsr); - return (bmidecsr & mask) ? ATA_CBL_PATA80 : ATA_CBL_PATA40; - default: - return ATA_CBL_PATA40; - } -} - -static const struct ide_port_ops cmd64x_port_ops = { - .set_pio_mode = cmd64x_set_pio_mode, - .set_dma_mode = cmd64x_set_dma_mode, - .clear_irq = cmd64x_clear_irq, - .test_irq = cmd64x_test_irq, - .cable_detect = cmd64x_cable_detect, -}; - -static const struct ide_port_ops cmd648_port_ops = { - .set_pio_mode = cmd64x_set_pio_mode, - .set_dma_mode = cmd64x_set_dma_mode, - .clear_irq = cmd648_clear_irq, - .test_irq = cmd648_test_irq, - .cable_detect = cmd64x_cable_detect, -}; - -static const struct ide_dma_ops cmd646_rev1_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = ide_dma_start, - .dma_end = cmd646_1_dma_end, - .dma_test_irq = ide_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = ide_dma_sff_read_status, -}; - -static const struct ide_port_info cmd64x_chipsets[] = { - { /* 0: CMD643 */ - .name = DRV_NAME, - .init_chipset = init_chipset_cmd64x, - .enablebits = {{0x00,0x00,0x00}, {0x51,0x08,0x08}}, - .port_ops = &cmd64x_port_ops, - .host_flags = IDE_HFLAG_CLEAR_SIMPLEX | - IDE_HFLAG_ABUSE_PREFETCH | - IDE_HFLAG_SERIALIZE, - .pio_mask = ATA_PIO5, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = 0x00, /* no udma */ - }, - { /* 1: CMD646 */ - .name = DRV_NAME, - .init_chipset = init_chipset_cmd64x, - .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, - .port_ops = &cmd648_port_ops, - .host_flags = IDE_HFLAG_ABUSE_PREFETCH | - IDE_HFLAG_SERIALIZE, - .pio_mask = ATA_PIO5, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA2, - }, - { /* 2: CMD648 */ - .name = DRV_NAME, - .init_chipset = init_chipset_cmd64x, - .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, - .port_ops = &cmd648_port_ops, - .host_flags = IDE_HFLAG_ABUSE_PREFETCH, - .pio_mask = ATA_PIO5, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA4, - }, - { /* 3: CMD649 */ - .name = DRV_NAME, - .init_chipset = init_chipset_cmd64x, - .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, - .port_ops = &cmd648_port_ops, - .host_flags = IDE_HFLAG_ABUSE_PREFETCH, - .pio_mask = ATA_PIO5, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA5, - } -}; - -static int cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct ide_port_info d; - u8 idx = id->driver_data; - - d = cmd64x_chipsets[idx]; - - if (idx == 1) { - /* - * UltraDMA only supported on PCI646U and PCI646U2, which - * correspond to revisions 0x03, 0x05 and 0x07 respectively. - * Actually, although the CMD tech support people won't - * tell me the details, the 0x03 revision cannot support - * UDMA correctly without hardware modifications, and even - * then it only works with Quantum disks due to some - * hold time assumptions in the 646U part which are fixed - * in the 646U2. - * - * So we only do UltraDMA on revision 0x05 and 0x07 chipsets. - */ - if (dev->revision < 5) { - d.udma_mask = 0x00; - /* - * The original PCI0646 didn't have the primary - * channel enable bit, it appeared starting with - * PCI0646U (i.e. revision ID 3). - */ - if (dev->revision < 3) { - d.enablebits[0].reg = 0; - d.port_ops = &cmd64x_port_ops; - if (dev->revision == 1) - d.dma_ops = &cmd646_rev1_dma_ops; - } - } - } - - return ide_pci_init_one(dev, &d, NULL); -} - -static const struct pci_device_id cmd64x_pci_tbl[] = { - { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 }, - { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 }, - { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 2 }, - { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 3 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl); - -static struct pci_driver cmd64x_pci_driver = { - .name = "CMD64x_IDE", - .id_table = cmd64x_pci_tbl, - .probe = cmd64x_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init cmd64x_ide_init(void) -{ - return ide_pci_register_driver(&cmd64x_pci_driver); -} - -static void __exit cmd64x_ide_exit(void) -{ - pci_unregister_driver(&cmd64x_pci_driver); -} - -module_init(cmd64x_ide_init); -module_exit(cmd64x_ide_exit); - -MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick, Bartlomiej Zolnierkiewicz"); -MODULE_DESCRIPTION("PCI driver module for CMD64x IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/cs5520.c b/drivers/ide/cs5520.c deleted file mode 100644 index 89a4ff100b7a..000000000000 --- a/drivers/ide/cs5520.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * IDE tuning and bus mastering support for the CS5510/CS5520 - * chipsets - * - * The CS5510/CS5520 are slightly unusual devices. Unlike the - * typical IDE controllers they do bus mastering with the drive in - * PIO mode and smarter silicon. - * - * The practical upshot of this is that we must always tune the - * drive for the right PIO mode. We must also ignore all the blacklists - * and the drive bus mastering DMA information. - * - * *** This driver is strictly experimental *** - * - * (c) Copyright Red Hat Inc 2002 - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * For the avoidance of doubt the "preferred form" of this code is one which - * is in an open non patent encumbered format. Where cryptographic key signing - * forms part of the process of creating an executable the information - * including keys needed to generate an equivalently functional executable - * are deemed to be part of the source code. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "cs5520" - -struct pio_clocks -{ - int address; - int assert; - int recovery; -}; - -static struct pio_clocks cs5520_pio_clocks[]={ - {3, 6, 11}, - {2, 5, 6}, - {1, 4, 3}, - {1, 3, 2}, - {1, 2, 1} -}; - -static void cs5520_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *pdev = to_pci_dev(hwif->dev); - int controller = drive->dn > 1 ? 1 : 0; - const u8 pio = drive->pio_mode - XFER_PIO_0; - - /* 8bit CAT/CRT - 8bit command timing for channel */ - pci_write_config_byte(pdev, 0x62 + controller, - (cs5520_pio_clocks[pio].recovery << 4) | - (cs5520_pio_clocks[pio].assert)); - - /* 0x64 - 16bit Primary, 0x68 - 16bit Secondary */ - - /* FIXME: should these use address ? */ - /* Data read timing */ - pci_write_config_byte(pdev, 0x64 + 4*controller + (drive->dn&1), - (cs5520_pio_clocks[pio].recovery << 4) | - (cs5520_pio_clocks[pio].assert)); - /* Write command timing */ - pci_write_config_byte(pdev, 0x66 + 4*controller + (drive->dn&1), - (cs5520_pio_clocks[pio].recovery << 4) | - (cs5520_pio_clocks[pio].assert)); -} - -static void cs5520_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - printk(KERN_ERR "cs55x0: bad ide timing.\n"); - - drive->pio_mode = XFER_PIO_0 + 0; - cs5520_set_pio_mode(hwif, drive); -} - -static const struct ide_port_ops cs5520_port_ops = { - .set_pio_mode = cs5520_set_pio_mode, - .set_dma_mode = cs5520_set_dma_mode, -}; - -static const struct ide_port_info cyrix_chipset = { - .name = DRV_NAME, - .enablebits = { { 0x60, 0x01, 0x01 }, { 0x60, 0x02, 0x02 } }, - .port_ops = &cs5520_port_ops, - .host_flags = IDE_HFLAG_ISA_PORTS | IDE_HFLAG_CS5520, - .pio_mask = ATA_PIO4, -}; - -/* - * The 5510/5520 are a bit weird. They don't quite set up the way - * the PCI helper layer expects so we must do much of the set up - * work longhand. - */ - -static int cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - const struct ide_port_info *d = &cyrix_chipset; - struct ide_hw hw[2], *hws[] = { NULL, NULL }; - - ide_setup_pci_noise(dev, d); - - /* We must not grab the entire device, it has 'ISA' space in its - * BARS too and we will freak out other bits of the kernel - */ - if (pci_enable_device_io(dev)) { - printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name); - return -ENODEV; - } - pci_set_master(dev); - if (dma_set_mask(&dev->dev, DMA_BIT_MASK(32))) { - printk(KERN_WARNING "%s: No suitable DMA available.\n", - d->name); - return -ENODEV; - } - - /* - * Now the chipset is configured we can let the core - * do all the device setup for us - */ - - ide_pci_setup_ports(dev, d, &hw[0], &hws[0]); - hw[0].irq = 14; - hw[1].irq = 15; - - return ide_host_add(d, hws, 2, NULL); -} - -static const struct pci_device_id cs5520_pci_tbl[] = { - { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), 0 }, - { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), 1 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, cs5520_pci_tbl); - -static struct pci_driver cs5520_pci_driver = { - .name = "Cyrix_IDE", - .id_table = cs5520_pci_tbl, - .probe = cs5520_init_one, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init cs5520_ide_init(void) -{ - return ide_pci_register_driver(&cs5520_pci_driver); -} - -module_init(cs5520_ide_init); - -MODULE_AUTHOR("Alan Cox"); -MODULE_DESCRIPTION("PCI driver module for Cyrix 5510/5520 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c deleted file mode 100644 index 65371599b976..000000000000 --- a/drivers/ide/cs5530.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (C) 2000 Andre Hedrick - * Copyright (C) 2000 Mark Lord - * Copyright (C) 2007 Bartlomiej Zolnierkiewicz - * - * May be copied or modified under the terms of the GNU General Public License - * - * Development of this chipset driver was funded - * by the nice folks at National Semiconductor. - * - * Documentation: - * CS5530 documentation available from National Semiconductor. - */ - -#include -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "cs5530" - -/* - * Here are the standard PIO mode 0-4 timings for each "format". - * Format-0 uses fast data reg timings, with slower command reg timings. - * Format-1 uses fast timings for all registers, but won't work with all drives. - */ -static unsigned int cs5530_pio_timings[2][5] = { - {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, - {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010} -}; - -/* - * After chip reset, the PIO timings are set to 0x0000e132, which is not valid. - */ -#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132) -#define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20)) - -/** - * cs5530_set_pio_mode - set host controller for PIO mode - * @hwif: port - * @drive: drive - * - * Handles setting of PIO mode for the chipset. - * - * The init_hwif_cs5530() routine guarantees that all drives - * will have valid default PIO timings set up before we get here. - */ - -static void cs5530_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - unsigned long basereg = CS5530_BASEREG(hwif); - unsigned int format = (inl(basereg + 4) >> 31) & 1; - const u8 pio = drive->pio_mode - XFER_PIO_0; - - outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3)); -} - -/** - * cs5530_udma_filter - UDMA filter - * @drive: drive - * - * cs5530_udma_filter() does UDMA mask filtering for the given drive - * taking into the consideration capabilities of the mate device. - * - * The CS5530 specifies that two drives sharing a cable cannot mix - * UDMA/MDMA. It has to be one or the other, for the pair, though - * different timings can still be chosen for each drive. We could - * set the appropriate timing bits on the fly, but that might be - * a bit confusing. So, for now we statically handle this requirement - * by looking at our mate drive to see what it is capable of, before - * choosing a mode for our own drive. - * - * Note: This relies on the fact we never fail from UDMA to MWDMA2 - * but instead drop to PIO. - */ - -static u8 cs5530_udma_filter(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - ide_drive_t *mate = ide_get_pair_dev(drive); - u16 *mateid; - u8 mask = hwif->ultra_mask; - - if (mate == NULL) - goto out; - mateid = mate->id; - - if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) { - if ((mateid[ATA_ID_FIELD_VALID] & 4) && - (mateid[ATA_ID_UDMA_MODES] & 7)) - goto out; - if (mateid[ATA_ID_MWDMA_MODES] & 7) - mask = 0; - } -out: - return mask; -} - -static void cs5530_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - unsigned long basereg; - unsigned int reg, timings = 0; - - switch (drive->dma_mode) { - case XFER_UDMA_0: timings = 0x00921250; break; - case XFER_UDMA_1: timings = 0x00911140; break; - case XFER_UDMA_2: timings = 0x00911030; break; - case XFER_MW_DMA_0: timings = 0x00077771; break; - case XFER_MW_DMA_1: timings = 0x00012121; break; - case XFER_MW_DMA_2: timings = 0x00002020; break; - } - basereg = CS5530_BASEREG(hwif); - reg = inl(basereg + 4); /* get drive0 config register */ - timings |= reg & 0x80000000; /* preserve PIO format bit */ - if ((drive-> dn & 1) == 0) { /* are we configuring drive0? */ - outl(timings, basereg + 4); /* write drive0 config register */ - } else { - if (timings & 0x00100000) - reg |= 0x00100000; /* enable UDMA timings for both drives */ - else - reg &= ~0x00100000; /* disable UDMA timings for both drives */ - outl(reg, basereg + 4); /* write drive0 config register */ - outl(timings, basereg + 12); /* write drive1 config register */ - } -} - -/** - * init_chipset_5530 - set up 5530 bridge - * @dev: PCI device - * - * Initialize the cs5530 bridge for reliable IDE DMA operation. - */ - -static int init_chipset_cs5530(struct pci_dev *dev) -{ - struct pci_dev *master_0 = NULL, *cs5530_0 = NULL; - - if (pci_resource_start(dev, 4) == 0) - return -EFAULT; - - dev = NULL; - while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) { - switch (dev->device) { - case PCI_DEVICE_ID_CYRIX_PCI_MASTER: - master_0 = pci_dev_get(dev); - break; - case PCI_DEVICE_ID_CYRIX_5530_LEGACY: - cs5530_0 = pci_dev_get(dev); - break; - } - } - if (!master_0) { - printk(KERN_ERR DRV_NAME ": unable to locate PCI MASTER function\n"); - goto out; - } - if (!cs5530_0) { - printk(KERN_ERR DRV_NAME ": unable to locate CS5530 LEGACY function\n"); - goto out; - } - - /* - * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530: - * --> OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530 - */ - - pci_set_master(cs5530_0); - pci_try_set_mwi(cs5530_0); - - /* - * Set PCI CacheLineSize to 16-bytes: - * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530 - */ - - pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04); - - /* - * Disable trapping of UDMA register accesses (Win98 hack): - * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530 - */ - - pci_write_config_word(cs5530_0, 0xd0, 0x5006); - - /* - * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus: - * The other settings are what is necessary to get the register - * into a sane state for IDE DMA operation. - */ - - pci_write_config_byte(master_0, 0x40, 0x1e); - - /* - * Set max PCI burst size (16-bytes seems to work best): - * 16bytes: set bit-1 at 0x41 (reg value of 0x16) - * all others: clear bit-1 at 0x41, and do: - * 128bytes: OR 0x00 at 0x41 - * 256bytes: OR 0x04 at 0x41 - * 512bytes: OR 0x08 at 0x41 - * 1024bytes: OR 0x0c at 0x41 - */ - - pci_write_config_byte(master_0, 0x41, 0x14); - - /* - * These settings are necessary to get the chip - * into a sane state for IDE DMA operation. - */ - - pci_write_config_byte(master_0, 0x42, 0x00); - pci_write_config_byte(master_0, 0x43, 0xc1); - -out: - pci_dev_put(master_0); - pci_dev_put(cs5530_0); - return 0; -} - -/** - * init_hwif_cs5530 - initialise an IDE channel - * @hwif: IDE to initialize - * - * This gets invoked by the IDE driver once for each channel. It - * performs channel-specific pre-initialization before drive probing. - */ - -static void init_hwif_cs5530 (ide_hwif_t *hwif) -{ - unsigned long basereg; - u32 d0_timings; - - basereg = CS5530_BASEREG(hwif); - d0_timings = inl(basereg + 0); - if (CS5530_BAD_PIO(d0_timings)) - outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 0); - if (CS5530_BAD_PIO(inl(basereg + 8))) - outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 8); -} - -static const struct ide_port_ops cs5530_port_ops = { - .set_pio_mode = cs5530_set_pio_mode, - .set_dma_mode = cs5530_set_dma_mode, - .udma_filter = cs5530_udma_filter, -}; - -static const struct ide_port_info cs5530_chipset = { - .name = DRV_NAME, - .init_chipset = init_chipset_cs5530, - .init_hwif = init_hwif_cs5530, - .port_ops = &cs5530_port_ops, - .host_flags = IDE_HFLAG_SERIALIZE | - IDE_HFLAG_POST_SET_MODE, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA2, -}; - -static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_pci_init_one(dev, &cs5530_chipset, NULL); -} - -static const struct pci_device_id cs5530_pci_tbl[] = { - { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, cs5530_pci_tbl); - -static struct pci_driver cs5530_pci_driver = { - .name = "CS5530 IDE", - .id_table = cs5530_pci_tbl, - .probe = cs5530_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init cs5530_ide_init(void) -{ - return ide_pci_register_driver(&cs5530_pci_driver); -} - -static void __exit cs5530_ide_exit(void) -{ - pci_unregister_driver(&cs5530_pci_driver); -} - -module_init(cs5530_ide_init); -module_exit(cs5530_ide_exit); - -MODULE_AUTHOR("Mark Lord"); -MODULE_DESCRIPTION("PCI driver module for Cyrix/NS 5530 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/cs5535.c b/drivers/ide/cs5535.c deleted file mode 100644 index 70fdbe3161f8..000000000000 --- a/drivers/ide/cs5535.c +++ /dev/null @@ -1,216 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2004-2005 Advanced Micro Devices, Inc. - * Copyright (C) 2007 Bartlomiej Zolnierkiewicz - * - * History: - * 09/20/2005 - Jaya Kumar - * - Reworked tuneproc, set_drive, misc mods to prep for mainline - * - Work was sponsored by CIS (M) Sdn Bhd. - * Ported to Kernel 2.6.11 on June 26, 2005 by - * Wolfgang Zuleger - * Alexander Kiausch - * Originally developed by AMD for 2.4/2.6 - * - * Development of this chipset driver was funded - * by the nice folks at National Semiconductor/AMD. - * - * Documentation: - * CS5535 documentation available from AMD - */ - -#include -#include -#include - -#define DRV_NAME "cs5535" - -#define MSR_ATAC_BASE 0x51300000 -#define ATAC_GLD_MSR_CAP (MSR_ATAC_BASE+0) -#define ATAC_GLD_MSR_CONFIG (MSR_ATAC_BASE+0x01) -#define ATAC_GLD_MSR_SMI (MSR_ATAC_BASE+0x02) -#define ATAC_GLD_MSR_ERROR (MSR_ATAC_BASE+0x03) -#define ATAC_GLD_MSR_PM (MSR_ATAC_BASE+0x04) -#define ATAC_GLD_MSR_DIAG (MSR_ATAC_BASE+0x05) -#define ATAC_IO_BAR (MSR_ATAC_BASE+0x08) -#define ATAC_RESET (MSR_ATAC_BASE+0x10) -#define ATAC_CH0D0_PIO (MSR_ATAC_BASE+0x20) -#define ATAC_CH0D0_DMA (MSR_ATAC_BASE+0x21) -#define ATAC_CH0D1_PIO (MSR_ATAC_BASE+0x22) -#define ATAC_CH0D1_DMA (MSR_ATAC_BASE+0x23) -#define ATAC_PCI_ABRTERR (MSR_ATAC_BASE+0x24) -#define ATAC_BM0_CMD_PRIM 0x00 -#define ATAC_BM0_STS_PRIM 0x02 -#define ATAC_BM0_PRD 0x04 -#define CS5535_CABLE_DETECT 0x48 - -/* Format I PIO settings. We separate out cmd and data for safer timings */ - -static unsigned int cs5535_pio_cmd_timings[5] = -{ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131 }; -static unsigned int cs5535_pio_dta_timings[5] = -{ 0xF7F4, 0xF173, 0x8141, 0x5131, 0x1131 }; - -static unsigned int cs5535_mwdma_timings[3] = -{ 0x7F0FFFF3, 0x7F035352, 0x7f024241 }; - -static unsigned int cs5535_udma_timings[5] = -{ 0x7F7436A1, 0x7F733481, 0x7F723261, 0x7F713161, 0x7F703061 }; - -/* Macros to check if the register is the reset value - reset value is an - invalid timing and indicates the register has not been set previously */ - -#define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL) == 0x00009172 ) -#define CS5535_BAD_DMA(timings) ( (timings & 0x000FFFFF) == 0x00077771 ) - -/**** - * cs5535_set_speed - Configure the chipset to the new speed - * @drive: Drive to set up - * @speed: desired speed - * - * cs5535_set_speed() configures the chipset to a new speed. - */ -static void cs5535_set_speed(ide_drive_t *drive, const u8 speed) -{ - u32 reg = 0, dummy; - u8 unit = drive->dn & 1; - - /* Set the PIO timings */ - if (speed < XFER_SW_DMA_0) { - ide_drive_t *pair = ide_get_pair_dev(drive); - u8 cmd, pioa; - - cmd = pioa = speed - XFER_PIO_0; - - if (pair) { - u8 piob = pair->pio_mode - XFER_PIO_0; - - if (piob < cmd) - cmd = piob; - } - - /* Write the speed of the current drive */ - reg = (cs5535_pio_cmd_timings[cmd] << 16) | - cs5535_pio_dta_timings[pioa]; - wrmsr(unit ? ATAC_CH0D1_PIO : ATAC_CH0D0_PIO, reg, 0); - - /* And if nessesary - change the speed of the other drive */ - rdmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, dummy); - - if (((reg >> 16) & cs5535_pio_cmd_timings[cmd]) != - cs5535_pio_cmd_timings[cmd]) { - reg &= 0x0000FFFF; - reg |= cs5535_pio_cmd_timings[cmd] << 16; - wrmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, 0); - } - - /* Set bit 31 of the DMA register for PIO format 1 timings */ - rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy); - wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, - reg | 0x80000000UL, 0); - } else { - rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy); - - reg &= 0x80000000UL; /* Preserve the PIO format bit */ - - if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_4) - reg |= cs5535_udma_timings[speed - XFER_UDMA_0]; - else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) - reg |= cs5535_mwdma_timings[speed - XFER_MW_DMA_0]; - else - return; - - wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, 0); - } -} - -/** - * cs5535_set_dma_mode - set host controller for DMA mode - * @hwif: port - * @drive: drive - * - * Programs the chipset for DMA mode. - */ - -static void cs5535_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - cs5535_set_speed(drive, drive->dma_mode); -} - -/** - * cs5535_set_pio_mode - set host controller for PIO mode - * @hwif: port - * @drive: drive - * - * A callback from the upper layers for PIO-only tuning. - */ - -static void cs5535_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - cs5535_set_speed(drive, drive->pio_mode); -} - -static u8 cs5535_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 bit; - - /* if a 80 wire cable was detected */ - pci_read_config_byte(dev, CS5535_CABLE_DETECT, &bit); - - return (bit & 1) ? ATA_CBL_PATA80 : ATA_CBL_PATA40; -} - -static const struct ide_port_ops cs5535_port_ops = { - .set_pio_mode = cs5535_set_pio_mode, - .set_dma_mode = cs5535_set_dma_mode, - .cable_detect = cs5535_cable_detect, -}; - -static const struct ide_port_info cs5535_chipset = { - .name = DRV_NAME, - .port_ops = &cs5535_port_ops, - .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA4, -}; - -static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_pci_init_one(dev, &cs5535_chipset, NULL); -} - -static const struct pci_device_id cs5535_pci_tbl[] = { - { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_CS5535_IDE), 0 }, - { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5535_IDE), }, - { 0, }, -}; - -MODULE_DEVICE_TABLE(pci, cs5535_pci_tbl); - -static struct pci_driver cs5535_pci_driver = { - .name = "CS5535_IDE", - .id_table = cs5535_pci_tbl, - .probe = cs5535_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init cs5535_ide_init(void) -{ - return ide_pci_register_driver(&cs5535_pci_driver); -} - -static void __exit cs5535_ide_exit(void) -{ - pci_unregister_driver(&cs5535_pci_driver); -} - -module_init(cs5535_ide_init); -module_exit(cs5535_ide_exit); - -MODULE_AUTHOR("AMD"); -MODULE_DESCRIPTION("PCI driver module for AMD/NS CS5535 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/cs5536.c b/drivers/ide/cs5536.c deleted file mode 100644 index 8b5ca145191b..000000000000 --- a/drivers/ide/cs5536.c +++ /dev/null @@ -1,294 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * CS5536 PATA support - * (C) 2007 Martin K. Petersen - * (C) 2009 Bartlomiej Zolnierkiewicz - * - * Documentation: - * Available from AMD web site. - * - * The IDE timing registers for the CS5536 live in the Geode Machine - * Specific Register file and not PCI config space. Most BIOSes - * virtualize the PCI registers so the chip looks like a standard IDE - * controller. Unfortunately not all implementations get this right. - * In particular some have problems with unaligned accesses to the - * virtualized PCI registers. This driver always does full dword - * writes to work around the issue. Also, in case of a bad BIOS this - * driver can be loaded with the "msr=1" parameter which forces using - * the Machine Specific Registers to configure the device. - */ - -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "cs5536" - -enum { - MSR_IDE_CFG = 0x51300010, - PCI_IDE_CFG = 0x40, - - CFG = 0, - DTC = 2, - CAST = 3, - ETC = 4, - - IDE_CFG_CHANEN = (1 << 1), - IDE_CFG_CABLE = (1 << 17) | (1 << 16), - - IDE_D0_SHIFT = 24, - IDE_D1_SHIFT = 16, - IDE_DRV_MASK = 0xff, - - IDE_CAST_D0_SHIFT = 6, - IDE_CAST_D1_SHIFT = 4, - IDE_CAST_DRV_MASK = 0x3, - - IDE_CAST_CMD_SHIFT = 24, - IDE_CAST_CMD_MASK = 0xff, - - IDE_ETC_UDMA_MASK = 0xc0, -}; - -static int use_msr; - -static int cs5536_read(struct pci_dev *pdev, int reg, u32 *val) -{ - if (unlikely(use_msr)) { - u32 dummy; - - rdmsr(MSR_IDE_CFG + reg, *val, dummy); - return 0; - } - - return pci_read_config_dword(pdev, PCI_IDE_CFG + reg * 4, val); -} - -static int cs5536_write(struct pci_dev *pdev, int reg, int val) -{ - if (unlikely(use_msr)) { - wrmsr(MSR_IDE_CFG + reg, val, 0); - return 0; - } - - return pci_write_config_dword(pdev, PCI_IDE_CFG + reg * 4, val); -} - -static void cs5536_program_dtc(ide_drive_t *drive, u8 tim) -{ - struct pci_dev *pdev = to_pci_dev(drive->hwif->dev); - int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT; - u32 dtc; - - cs5536_read(pdev, DTC, &dtc); - dtc &= ~(IDE_DRV_MASK << dshift); - dtc |= tim << dshift; - cs5536_write(pdev, DTC, dtc); -} - -/** - * cs5536_cable_detect - detect cable type - * @hwif: Port to detect on - * - * Perform cable detection for ATA66 capable cable. - * - * Returns a cable type. - */ - -static u8 cs5536_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *pdev = to_pci_dev(hwif->dev); - u32 cfg; - - cs5536_read(pdev, CFG, &cfg); - - if (cfg & IDE_CFG_CABLE) - return ATA_CBL_PATA80; - else - return ATA_CBL_PATA40; -} - -/** - * cs5536_set_pio_mode - PIO timing setup - * @hwif: ATA port - * @drive: ATA device - */ - -static void cs5536_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - static const u8 drv_timings[5] = { - 0x98, 0x55, 0x32, 0x21, 0x20, - }; - - static const u8 addr_timings[5] = { - 0x2, 0x1, 0x0, 0x0, 0x0, - }; - - static const u8 cmd_timings[5] = { - 0x99, 0x92, 0x90, 0x22, 0x20, - }; - - struct pci_dev *pdev = to_pci_dev(hwif->dev); - ide_drive_t *pair = ide_get_pair_dev(drive); - int cshift = (drive->dn & 1) ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT; - unsigned long timings = (unsigned long)ide_get_drivedata(drive); - u32 cast; - const u8 pio = drive->pio_mode - XFER_PIO_0; - u8 cmd_pio = pio; - - if (pair) - cmd_pio = min_t(u8, pio, pair->pio_mode - XFER_PIO_0); - - timings &= (IDE_DRV_MASK << 8); - timings |= drv_timings[pio]; - ide_set_drivedata(drive, (void *)timings); - - cs5536_program_dtc(drive, drv_timings[pio]); - - cs5536_read(pdev, CAST, &cast); - - cast &= ~(IDE_CAST_DRV_MASK << cshift); - cast |= addr_timings[pio] << cshift; - - cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT); - cast |= cmd_timings[cmd_pio] << IDE_CAST_CMD_SHIFT; - - cs5536_write(pdev, CAST, cast); -} - -/** - * cs5536_set_dma_mode - DMA timing setup - * @hwif: ATA port - * @drive: ATA device - */ - -static void cs5536_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - static const u8 udma_timings[6] = { - 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6, - }; - - static const u8 mwdma_timings[3] = { - 0x67, 0x21, 0x20, - }; - - struct pci_dev *pdev = to_pci_dev(hwif->dev); - int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT; - unsigned long timings = (unsigned long)ide_get_drivedata(drive); - u32 etc; - const u8 mode = drive->dma_mode; - - cs5536_read(pdev, ETC, &etc); - - if (mode >= XFER_UDMA_0) { - etc &= ~(IDE_DRV_MASK << dshift); - etc |= udma_timings[mode - XFER_UDMA_0] << dshift; - } else { /* MWDMA */ - etc &= ~(IDE_ETC_UDMA_MASK << dshift); - timings &= IDE_DRV_MASK; - timings |= mwdma_timings[mode - XFER_MW_DMA_0] << 8; - ide_set_drivedata(drive, (void *)timings); - } - - cs5536_write(pdev, ETC, etc); -} - -static void cs5536_dma_start(ide_drive_t *drive) -{ - unsigned long timings = (unsigned long)ide_get_drivedata(drive); - - if (drive->current_speed < XFER_UDMA_0 && - (timings >> 8) != (timings & IDE_DRV_MASK)) - cs5536_program_dtc(drive, timings >> 8); - - ide_dma_start(drive); -} - -static int cs5536_dma_end(ide_drive_t *drive) -{ - int ret = ide_dma_end(drive); - unsigned long timings = (unsigned long)ide_get_drivedata(drive); - - if (drive->current_speed < XFER_UDMA_0 && - (timings >> 8) != (timings & IDE_DRV_MASK)) - cs5536_program_dtc(drive, timings & IDE_DRV_MASK); - - return ret; -} - -static const struct ide_port_ops cs5536_port_ops = { - .set_pio_mode = cs5536_set_pio_mode, - .set_dma_mode = cs5536_set_dma_mode, - .cable_detect = cs5536_cable_detect, -}; - -static const struct ide_dma_ops cs5536_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = cs5536_dma_start, - .dma_end = cs5536_dma_end, - .dma_test_irq = ide_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = ide_dma_sff_read_status, -}; - -static const struct ide_port_info cs5536_info = { - .name = DRV_NAME, - .port_ops = &cs5536_port_ops, - .dma_ops = &cs5536_dma_ops, - .host_flags = IDE_HFLAG_SINGLE, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA5, -}; - -/** - * cs5536_init_one - * @dev: PCI device - * @id: Entry in match table - */ - -static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - u32 cfg; - - if (use_msr) - printk(KERN_INFO DRV_NAME ": Using MSR regs instead of PCI\n"); - - cs5536_read(dev, CFG, &cfg); - - if ((cfg & IDE_CFG_CHANEN) == 0) { - printk(KERN_ERR DRV_NAME ": disabled by BIOS\n"); - return -ENODEV; - } - - return ide_pci_init_one(dev, &cs5536_info, NULL); -} - -static const struct pci_device_id cs5536_pci_tbl[] = { - { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), }, - { }, -}; - -static struct pci_driver cs5536_pci_driver = { - .name = DRV_NAME, - .id_table = cs5536_pci_tbl, - .probe = cs5536_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -module_pci_driver(cs5536_pci_driver); - -MODULE_AUTHOR("Martin K. Petersen, Bartlomiej Zolnierkiewicz"); -MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller"); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(pci, cs5536_pci_tbl); - -module_param_named(msr, use_msr, int, 0644); -MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)"); diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c deleted file mode 100644 index bc01660ee8fd..000000000000 --- a/drivers/ide/cy82c693.c +++ /dev/null @@ -1,234 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer - * Copyright (C) 1998-2002 Andre Hedrick , Integrator - * Copyright (C) 2007-2011 Bartlomiej Zolnierkiewicz - * - * CYPRESS CY82C693 chipset IDE controller - * - * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards. - */ - -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "cy82c693" - -/* - * NOTE: the value for busmaster timeout is tricky and I got it by - * trial and error! By using a to low value will cause DMA timeouts - * and drop IDE performance, and by using a to high value will cause - * audio playback to scatter. - * If you know a better value or how to calc it, please let me know. - */ - -/* twice the value written in cy82c693ub datasheet */ -#define BUSMASTER_TIMEOUT 0x50 -/* - * the value above was tested on my machine and it seems to work okay - */ - -/* here are the offset definitions for the registers */ -#define CY82_IDE_CMDREG 0x04 -#define CY82_IDE_ADDRSETUP 0x48 -#define CY82_IDE_MASTER_IOR 0x4C -#define CY82_IDE_MASTER_IOW 0x4D -#define CY82_IDE_SLAVE_IOR 0x4E -#define CY82_IDE_SLAVE_IOW 0x4F -#define CY82_IDE_MASTER_8BIT 0x50 -#define CY82_IDE_SLAVE_8BIT 0x51 - -#define CY82_INDEX_PORT 0x22 -#define CY82_DATA_PORT 0x23 - -#define CY82_INDEX_CHANNEL0 0x30 -#define CY82_INDEX_CHANNEL1 0x31 -#define CY82_INDEX_TIMEOUT 0x32 - -/* - * set DMA mode a specific channel for CY82C693 - */ - -static void cy82c693_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - const u8 mode = drive->dma_mode; - u8 single = (mode & 0x10) >> 4, index = 0, data = 0; - - index = hwif->channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0; - - data = (mode & 3) | (single << 2); - - outb(index, CY82_INDEX_PORT); - outb(data, CY82_DATA_PORT); - - /* - * note: below we set the value for Bus Master IDE TimeOut Register - * I'm not absolutely sure what this does, but it solved my problem - * with IDE DMA and sound, so I now can play sound and work with - * my IDE driver at the same time :-) - * - * If you know the correct (best) value for this register please - * let me know - ASK - */ - - data = BUSMASTER_TIMEOUT; - outb(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT); - outb(data, CY82_DATA_PORT); -} - -static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - int bus_speed = ide_pci_clk ? ide_pci_clk : 33; - const unsigned long T = 1000000 / bus_speed; - unsigned int addrCtrl; - struct ide_timing t; - u8 time_16, time_8; - - /* select primary or secondary channel */ - if (drive->dn > 1) { /* drive is on the secondary channel */ - dev = pci_get_slot(dev->bus, dev->devfn+1); - if (!dev) { - printk(KERN_ERR "%s: tune_drive: " - "Cannot find secondary interface!\n", - drive->name); - return; - } - } - - ide_timing_compute(drive, drive->pio_mode, &t, T, 1); - - time_16 = clamp_val(t.recover - 1, 0, 15) | - (clamp_val(t.active - 1, 0, 15) << 4); - time_8 = clamp_val(t.act8b - 1, 0, 15) | - (clamp_val(t.rec8b - 1, 0, 15) << 4); - - /* now let's write the clocks registers */ - if ((drive->dn & 1) == 0) { - /* - * set master drive - * address setup control register - * is 32 bit !!! - */ - pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); - - addrCtrl &= (~0xF); - addrCtrl |= clamp_val(t.setup - 1, 0, 15); - pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl); - - /* now let's set the remaining registers */ - pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, time_16); - pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, time_16); - pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, time_8); - } else { - /* - * set slave drive - * address setup control register - * is 32 bit !!! - */ - pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); - - addrCtrl &= (~0xF0); - addrCtrl |= (clamp_val(t.setup - 1, 0, 15) << 4); - pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl); - - /* now let's set the remaining registers */ - pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, time_16); - pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, time_16); - pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, time_8); - } - if (drive->dn > 1) - pci_dev_put(dev); -} - -static void init_iops_cy82c693(ide_hwif_t *hwif) -{ - static ide_hwif_t *primary; - struct pci_dev *dev = to_pci_dev(hwif->dev); - - if (PCI_FUNC(dev->devfn) == 1) - primary = hwif; - else { - hwif->mate = primary; - hwif->channel = 1; - } -} - -static const struct ide_port_ops cy82c693_port_ops = { - .set_pio_mode = cy82c693_set_pio_mode, - .set_dma_mode = cy82c693_set_dma_mode, -}; - -static const struct ide_port_info cy82c693_chipset = { - .name = DRV_NAME, - .init_iops = init_iops_cy82c693, - .port_ops = &cy82c693_port_ops, - .host_flags = IDE_HFLAG_SINGLE, - .pio_mask = ATA_PIO4, - .swdma_mask = ATA_SWDMA2, - .mwdma_mask = ATA_MWDMA2, -}; - -static int cy82c693_init_one(struct pci_dev *dev, - const struct pci_device_id *id) -{ - struct pci_dev *dev2; - int ret = -ENODEV; - - /* CY82C693 is more than only a IDE controller. - Function 1 is primary IDE channel, function 2 - secondary. */ - if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && - PCI_FUNC(dev->devfn) == 1) { - dev2 = pci_get_slot(dev->bus, dev->devfn + 1); - ret = ide_pci_init_two(dev, dev2, &cy82c693_chipset, NULL); - if (ret) - pci_dev_put(dev2); - } - return ret; -} - -static void cy82c693_remove(struct pci_dev *dev) -{ - struct ide_host *host = pci_get_drvdata(dev); - struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL; - - ide_pci_remove(dev); - pci_dev_put(dev2); -} - -static const struct pci_device_id cy82c693_pci_tbl[] = { - { PCI_VDEVICE(CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693), 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, cy82c693_pci_tbl); - -static struct pci_driver cy82c693_pci_driver = { - .name = "Cypress_IDE", - .id_table = cy82c693_pci_tbl, - .probe = cy82c693_init_one, - .remove = cy82c693_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init cy82c693_ide_init(void) -{ - return ide_pci_register_driver(&cy82c693_pci_driver); -} - -static void __exit cy82c693_ide_exit(void) -{ - pci_unregister_driver(&cy82c693_pci_driver); -} - -module_init(cy82c693_ide_init); -module_exit(cy82c693_ide_exit); - -MODULE_AUTHOR("Andreas Krebs, Andre Hedrick, Bartlomiej Zolnierkiewicz"); -MODULE_DESCRIPTION("PCI driver module for the Cypress CY82C693 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/delkin_cb.c b/drivers/ide/delkin_cb.c deleted file mode 100644 index 300daabaa575..000000000000 --- a/drivers/ide/delkin_cb.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Created 20 Oct 2004 by Mark Lord - * - * Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter - * - * Modeled after the 16-bit PCMCIA driver: ide-cs.c - * - * This is slightly peculiar, in that it is a PCI driver, - * but is NOT an IDE PCI driver -- the IDE layer does not directly - * support hot insertion/removal of PCI interfaces, so this driver - * is unable to use the IDE PCI interfaces. Instead, it uses the - * same interfaces as the ide-cs (PCMCIA) driver uses. - * On the plus side, the driver is also smaller/simpler this way. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#include -#include -#include -#include -#include - -#include - -/* - * No chip documentation has yet been found, - * so these configuration values were pulled from - * a running Win98 system using "debug". - * This gives around 3MByte/second read performance, - * which is about 2/3 of what the chip is capable of. - * - * There is also a 4KByte mmio region on the card, - * but its purpose has yet to be reverse-engineered. - */ -static const u8 setup[] = { - 0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00, - 0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13, -}; - -static const struct ide_port_ops delkin_cb_port_ops = { - .quirkproc = ide_undecoded_slave, -}; - -static int delkin_cb_init_chipset(struct pci_dev *dev) -{ - unsigned long base = pci_resource_start(dev, 0); - int i; - - outb(0x02, base + 0x1e); /* set nIEN to block interrupts */ - inb(base + 0x17); /* read status to clear interrupts */ - - for (i = 0; i < sizeof(setup); ++i) { - if (setup[i]) - outb(setup[i], base + i); - } - - return 0; -} - -static const struct ide_port_info delkin_cb_port_info = { - .port_ops = &delkin_cb_port_ops, - .host_flags = IDE_HFLAG_IO_32BIT | IDE_HFLAG_UNMASK_IRQS | - IDE_HFLAG_NO_DMA, - .irq_flags = IRQF_SHARED, - .init_chipset = delkin_cb_init_chipset, - .chipset = ide_pci, -}; - -static int delkin_cb_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct ide_host *host; - unsigned long base; - int rc; - struct ide_hw hw, *hws[] = { &hw }; - - rc = pci_enable_device(dev); - if (rc) { - printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc); - return rc; - } - rc = pci_request_regions(dev, "delkin_cb"); - if (rc) { - printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc); - pci_disable_device(dev); - return rc; - } - base = pci_resource_start(dev, 0); - - delkin_cb_init_chipset(dev); - - memset(&hw, 0, sizeof(hw)); - ide_std_init_ports(&hw, base + 0x10, base + 0x1e); - hw.irq = dev->irq; - hw.dev = &dev->dev; - - rc = ide_host_add(&delkin_cb_port_info, hws, 1, &host); - if (rc) - goto out_disable; - - pci_set_drvdata(dev, host); - - return 0; - -out_disable: - pci_release_regions(dev); - pci_disable_device(dev); - return rc; -} - -static void -delkin_cb_remove (struct pci_dev *dev) -{ - struct ide_host *host = pci_get_drvdata(dev); - - ide_host_remove(host); - - pci_release_regions(dev); - pci_disable_device(dev); -} - -#ifdef CONFIG_PM -static int delkin_cb_suspend(struct pci_dev *dev, pm_message_t state) -{ - pci_save_state(dev); - pci_disable_device(dev); - pci_set_power_state(dev, pci_choose_state(dev, state)); - - return 0; -} - -static int delkin_cb_resume(struct pci_dev *dev) -{ - struct ide_host *host = pci_get_drvdata(dev); - int rc; - - pci_set_power_state(dev, PCI_D0); - - rc = pci_enable_device(dev); - if (rc) - return rc; - - pci_restore_state(dev); - pci_set_master(dev); - - if (host->init_chipset) - host->init_chipset(dev); - - return 0; -} -#else -#define delkin_cb_suspend NULL -#define delkin_cb_resume NULL -#endif - -static struct pci_device_id delkin_cb_pci_tbl[] = { - { 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { 0x1145, 0xf024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl); - -static struct pci_driver delkin_cb_pci_driver = { - .name = "Delkin-ASKA-Workbit Cardbus IDE", - .id_table = delkin_cb_pci_tbl, - .probe = delkin_cb_probe, - .remove = delkin_cb_remove, - .suspend = delkin_cb_suspend, - .resume = delkin_cb_resume, -}; - -module_pci_driver(delkin_cb_pci_driver); - -MODULE_AUTHOR("Mark Lord"); -MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c deleted file mode 100644 index 714e8cd0fa49..000000000000 --- a/drivers/ide/dtc2278.c +++ /dev/null @@ -1,155 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1996 Linus Torvalds & author (see below) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "dtc2278" - -/* - * Changing this #undef to #define may solve start up problems in some systems. - */ -#undef ALWAYS_SET_DTC2278_PIO_MODE - -/* - * From: andy@cercle.cts.com (Dyan Wile) - * - * Below is a patch for DTC-2278 - alike software-programmable controllers - * The code enables the secondary IDE controller and the PIO4 (3?) timings on - * the primary (EIDE). You may probably have to enable the 32-bit support to - * get the full speed. You better get the disk interrupts disabled ( hdparm -u0 - * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my - * filesystem corrupted with -u1, but under heavy disk load only :-) - * - * This card is now forced to use the "serialize" feature, - * and irq-unmasking is disallowed. If io_32bit is enabled, - * it must be done for BOTH drives on each interface. - * - * This code was written for the DTC2278E, but might work with any of these: - * - * DTC2278S has only a single IDE interface. - * DTC2278D has two IDE interfaces and is otherwise identical to the S version. - * DTC2278E also has serial ports and a printer port - * DTC2278EB: has onboard BIOS, and "works like a charm" -- Kent Bradford - * - * There may be a fourth controller type. The S and D versions use the - * Winbond chip, and I think the E version does also. - * - */ - -static void sub22 (char b, char c) -{ - int i; - - for(i = 0; i < 3; ++i) { - inb(0x3f6); - outb_p(b,0xb0); - inb(0x3f6); - outb_p(c,0xb4); - inb(0x3f6); - if(inb(0xb4) == c) { - outb_p(7,0xb0); - inb(0x3f6); - return; /* success */ - } - } -} - -static DEFINE_SPINLOCK(dtc2278_lock); - -static void dtc2278_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - unsigned long flags; - - if (drive->pio_mode >= XFER_PIO_3) { - spin_lock_irqsave(&dtc2278_lock, flags); - /* - * This enables PIO mode4 (3?) on the first interface - */ - sub22(1,0xc3); - sub22(0,0xa0); - spin_unlock_irqrestore(&dtc2278_lock, flags); - } else { - /* we don't know how to set it back again.. */ - /* Actually we do - there is a data sheet available for the - Winbond but does anyone actually care */ - } -} - -static const struct ide_port_ops dtc2278_port_ops = { - .set_pio_mode = dtc2278_set_pio_mode, -}; - -static const struct ide_port_info dtc2278_port_info __initconst = { - .name = DRV_NAME, - .chipset = ide_dtc2278, - .port_ops = &dtc2278_port_ops, - .host_flags = IDE_HFLAG_SERIALIZE | - IDE_HFLAG_NO_UNMASK_IRQS | - IDE_HFLAG_IO_32BIT | - /* disallow ->io_32bit changes */ - IDE_HFLAG_NO_IO_32BIT | - IDE_HFLAG_NO_DMA | - IDE_HFLAG_DTC2278, - .pio_mask = ATA_PIO4, -}; - -static int __init dtc2278_probe(void) -{ - unsigned long flags; - - local_irq_save(flags); - /* - * This enables the second interface - */ - outb_p(4,0xb0); - inb(0x3f6); - outb_p(0x20,0xb4); - inb(0x3f6); -#ifdef ALWAYS_SET_DTC2278_PIO_MODE - /* - * This enables PIO mode4 (3?) on the first interface - * and may solve start-up problems for some people. - */ - sub22(1,0xc3); - sub22(0,0xa0); -#endif - local_irq_restore(flags); - - return ide_legacy_device_add(&dtc2278_port_info, 0); -} - -static bool probe_dtc2278; - -module_param_named(probe, probe_dtc2278, bool, 0); -MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets"); - -static int __init dtc2278_init(void) -{ - if (probe_dtc2278 == 0) - return -ENODEV; - - if (dtc2278_probe()) { - printk(KERN_ERR "dtc2278: ide interfaces already in use!\n"); - return -EBUSY; - } - return 0; -} - -module_init(dtc2278_init); - -MODULE_AUTHOR("See Local File"); -MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/falconide.c b/drivers/ide/falconide.c deleted file mode 100644 index a73a9dc17e4d..000000000000 --- a/drivers/ide/falconide.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Atari Falcon IDE Driver - * - * Created 12 Jul 1997 by Geert Uytterhoeven - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define DRV_NAME "falconide" - -#ifdef CONFIG_ATARI - /* - * falconide_intr_lock is used to obtain access to the IDE interrupt, - * which is shared between several drivers. - */ - -static int falconide_intr_lock; - -static void falconide_release_lock(void) -{ - if (falconide_intr_lock == 0) { - printk(KERN_ERR "%s: bug\n", __func__); - return; - } - falconide_intr_lock = 0; - stdma_release(); -} - -static void falconide_get_lock(irq_handler_t handler, void *data) -{ - if (falconide_intr_lock == 0) { - stdma_lock(handler, data); - falconide_intr_lock = 1; - } -} -#endif - -static void falconide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, - void *buf, unsigned int len) -{ - unsigned long data_addr = drive->hwif->io_ports.data_addr; - - if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) { - __ide_mm_insw(data_addr, buf, (len + 1) / 2); - return; - } - - raw_insw_swapw((u16 *)data_addr, buf, (len + 1) / 2); -} - -static void falconide_output_data(ide_drive_t *drive, struct ide_cmd *cmd, - void *buf, unsigned int len) -{ - unsigned long data_addr = drive->hwif->io_ports.data_addr; - - if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) { - __ide_mm_outsw(data_addr, buf, (len + 1) / 2); - return; - } - - raw_outsw_swapw((u16 *)data_addr, buf, (len + 1) / 2); -} - -/* Atari has a byte-swapped IDE interface */ -static const struct ide_tp_ops falconide_tp_ops = { - .exec_command = ide_exec_command, - .read_status = ide_read_status, - .read_altstatus = ide_read_altstatus, - .write_devctl = ide_write_devctl, - - .dev_select = ide_dev_select, - .tf_load = ide_tf_load, - .tf_read = ide_tf_read, - - .input_data = falconide_input_data, - .output_data = falconide_output_data, -}; - -static const struct ide_port_info falconide_port_info = { -#ifdef CONFIG_ATARI - .get_lock = falconide_get_lock, - .release_lock = falconide_release_lock, -#endif - .tp_ops = &falconide_tp_ops, - .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE | - IDE_HFLAG_NO_DMA, - .irq_flags = IRQF_SHARED, - .chipset = ide_generic, -}; - -static void __init falconide_setup_ports(struct ide_hw *hw, unsigned long base, - unsigned long ctl, int irq) -{ - int i; - - memset(hw, 0, sizeof(*hw)); - - hw->io_ports.data_addr = base; - - for (i = 1; i < 8; i++) - hw->io_ports_array[i] = base + 1 + i * 4; - - hw->io_ports.ctl_addr = ctl + 1; - - hw->irq = irq; -} - - /* - * Probe for a Falcon IDE interface - */ - -static int __init falconide_init(struct platform_device *pdev) -{ - struct resource *base_mem_res, *ctl_mem_res; - struct resource *base_res, *ctl_res, *irq_res; - struct ide_host *host; - struct ide_hw hw, *hws[] = { &hw }; - int rc; - int irq; - - dev_info(&pdev->dev, "Atari Falcon and Q40/Q60 IDE controller\n"); - - base_res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (base_res && !devm_request_region(&pdev->dev, base_res->start, - resource_size(base_res), DRV_NAME)) { - dev_err(&pdev->dev, "resources busy\n"); - return -EBUSY; - } - - ctl_res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (ctl_res && !devm_request_region(&pdev->dev, ctl_res->start, - resource_size(ctl_res), DRV_NAME)) { - dev_err(&pdev->dev, "resources busy\n"); - return -EBUSY; - } - - base_mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!base_mem_res) - return -ENODEV; - - if (!devm_request_mem_region(&pdev->dev, base_mem_res->start, - resource_size(base_mem_res), DRV_NAME)) { - dev_err(&pdev->dev, "resources busy\n"); - return -EBUSY; - } - - ctl_mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!ctl_mem_res) - return -ENODEV; - - if (MACH_IS_ATARI) { - irq = IRQ_MFP_IDE; - } else { - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (irq_res && irq_res->start > 0) - irq = irq_res->start; - else - return -ENODEV; - } - - falconide_setup_ports(&hw, base_mem_res->start, ctl_mem_res->start, irq); - - host = ide_host_alloc(&falconide_port_info, hws, 1); - if (!host) - return -ENOMEM; - - if (!MACH_IS_ATARI) { - host->get_lock = NULL; - host->release_lock = NULL; - } - - if (host->get_lock) - host->get_lock(NULL, NULL); - rc = ide_host_register(host, &falconide_port_info, hws); - if (host->release_lock) - host->release_lock(); - - if (rc) - goto err_free; - - platform_set_drvdata(pdev, host); - return 0; -err_free: - ide_host_free(host); - return rc; -} - -static int falconide_remove(struct platform_device *pdev) -{ - struct ide_host *host = platform_get_drvdata(pdev); - - ide_host_remove(host); - - return 0; -} - -static struct platform_driver ide_falcon_driver = { - .remove = falconide_remove, - .driver = { - .name = "atari-falcon-ide", - }, -}; - -module_platform_driver_probe(ide_falcon_driver, falconide_init); - -MODULE_AUTHOR("Geert Uytterhoeven"); -MODULE_DESCRIPTION("low-level driver for Atari Falcon IDE"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:atari-falcon-ide"); diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c deleted file mode 100644 index 901e6ebfeb96..000000000000 --- a/drivers/ide/gayle.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Amiga Gayle IDE Driver - * - * Created 9 Jul 1997 by Geert Uytterhoeven - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - - - /* - * Offsets from one of the above bases - */ - -#define GAYLE_CONTROL 0x101a - - /* - * These are at different offsets from the base - */ - -#define GAYLE_IRQ_4000 0xdd3020 /* MSB = 1, Harddisk is source of */ -#define GAYLE_IRQ_1200 0xda9000 /* interrupt */ - - - /* - * Offset of the secondary port for IDE doublers - * Note that GAYLE_CONTROL is NOT available then! - */ - -#define GAYLE_NEXT_PORT 0x1000 - -#define GAYLE_NUM_HWIFS 2 -#define GAYLE_NUM_PROBE_HWIFS (ide_doubler ? GAYLE_NUM_HWIFS : \ - GAYLE_NUM_HWIFS-1) -#define GAYLE_HAS_CONTROL_REG (!ide_doubler) - -static bool ide_doubler; -module_param_named(doubler, ide_doubler, bool, 0); -MODULE_PARM_DESC(doubler, "enable support for IDE doublers"); - - /* - * Check and acknowledge the interrupt status - */ - -static int gayle_test_irq(ide_hwif_t *hwif) -{ - unsigned char ch; - - ch = z_readb(hwif->io_ports.irq_addr); - if (!(ch & GAYLE_IRQ_IDE)) - return 0; - return 1; -} - -static void gayle_a1200_clear_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - - (void)z_readb(hwif->io_ports.status_addr); - z_writeb(0x7c, hwif->io_ports.irq_addr); -} - -static void __init gayle_setup_ports(struct ide_hw *hw, unsigned long base, - unsigned long ctl, unsigned long irq_port) -{ - int i; - - memset(hw, 0, sizeof(*hw)); - - hw->io_ports.data_addr = base; - - for (i = 1; i < 8; i++) - hw->io_ports_array[i] = base + 2 + i * 4; - - hw->io_ports.ctl_addr = ctl; - hw->io_ports.irq_addr = irq_port; - - hw->irq = IRQ_AMIGA_PORTS; -} - -static const struct ide_port_ops gayle_a4000_port_ops = { - .test_irq = gayle_test_irq, -}; - -static const struct ide_port_ops gayle_a1200_port_ops = { - .clear_irq = gayle_a1200_clear_irq, - .test_irq = gayle_test_irq, -}; - -static const struct ide_port_info gayle_port_info = { - .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE | - IDE_HFLAG_NO_DMA, - .irq_flags = IRQF_SHARED, - .chipset = ide_generic, -}; - - /* - * Probe for a Gayle IDE interface (and optionally for an IDE doubler) - */ - -static int __init amiga_gayle_ide_probe(struct platform_device *pdev) -{ - struct resource *res; - struct gayle_ide_platform_data *pdata; - unsigned long base, ctrlport, irqport; - unsigned int i; - int error; - struct ide_hw hw[GAYLE_NUM_HWIFS], *hws[GAYLE_NUM_HWIFS]; - struct ide_port_info d = gayle_port_info; - struct ide_host *host; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - if (!request_mem_region(res->start, resource_size(res), "IDE")) - return -EBUSY; - - pdata = dev_get_platdata(&pdev->dev); - pr_info("ide: Gayle IDE controller (A%u style%s)\n", - pdata->explicit_ack ? 1200 : 4000, - ide_doubler ? ", IDE doubler" : ""); - - base = (unsigned long)ZTWO_VADDR(pdata->base); - ctrlport = 0; - irqport = (unsigned long)ZTWO_VADDR(pdata->irqport); - if (pdata->explicit_ack) - d.port_ops = &gayle_a1200_port_ops; - else - d.port_ops = &gayle_a4000_port_ops; - - for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++, base += GAYLE_NEXT_PORT) { - if (GAYLE_HAS_CONTROL_REG) - ctrlport = base + GAYLE_CONTROL; - - gayle_setup_ports(&hw[i], base, ctrlport, irqport); - hws[i] = &hw[i]; - } - - error = ide_host_add(&d, hws, i, &host); - if (error) - goto out; - - platform_set_drvdata(pdev, host); - return 0; - -out: - release_mem_region(res->start, resource_size(res)); - return error; -} - -static int __exit amiga_gayle_ide_remove(struct platform_device *pdev) -{ - struct ide_host *host = platform_get_drvdata(pdev); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - ide_host_remove(host); - release_mem_region(res->start, resource_size(res)); - return 0; -} - -static struct platform_driver amiga_gayle_ide_driver = { - .remove = __exit_p(amiga_gayle_ide_remove), - .driver = { - .name = "amiga-gayle-ide", - }, -}; - -module_platform_driver_probe(amiga_gayle_ide_driver, amiga_gayle_ide_probe); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:amiga-gayle-ide"); diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c deleted file mode 100644 index 50c9a41467c8..000000000000 --- a/drivers/ide/hpt366.c +++ /dev/null @@ -1,1545 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1999-2003 Andre Hedrick - * Portions Copyright (C) 2001 Sun Microsystems, Inc. - * Portions Copyright (C) 2003 Red Hat Inc - * Portions Copyright (C) 2007 Bartlomiej Zolnierkiewicz - * Portions Copyright (C) 2005-2009 MontaVista Software, Inc. - * - * Thanks to HighPoint Technologies for their assistance, and hardware. - * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his - * donation of an ABit BP6 mainboard, processor, and memory acellerated - * development and support. - * - * - * HighPoint has its own drivers (open source except for the RAID part) - * available from http://www.highpoint-tech.com/USA_new/service_support.htm - * This may be useful to anyone wanting to work on this driver, however do not - * trust them too much since the code tends to become less and less meaningful - * as the time passes... :-/ - * - * Note that final HPT370 support was done by force extraction of GPL. - * - * - add function for getting/setting power status of drive - * - the HPT370's state machine can get confused. reset it before each dma - * xfer to prevent that from happening. - * - reset state engine whenever we get an error. - * - check for busmaster state at end of dma. - * - use new highpoint timings. - * - detect bus speed using highpoint register. - * - use pll if we don't have a clock table. added a 66MHz table that's - * just 2x the 33MHz table. - * - removed turnaround. NOTE: we never want to switch between pll and - * pci clocks as the chip can glitch in those cases. the highpoint - * approved workaround slows everything down too much to be useful. in - * addition, we would have to serialize access to each chip. - * Adrian Sun - * - * add drive timings for 66MHz PCI bus, - * fix ATA Cable signal detection, fix incorrect /proc info - * add /proc display for per-drive PIO/DMA/UDMA mode and - * per-channel ATA-33/66 Cable detect. - * Duncan Laurie - * - * fixup /proc output for multiple controllers - * Tim Hockin - * - * On hpt366: - * Reset the hpt366 on error, reset on dma - * Fix disabling Fast Interrupt hpt366. - * Mike Waychison - * - * Added support for 372N clocking and clock switching. The 372N needs - * different clocks on read/write. This requires overloading rw_disk and - * other deeply crazy things. Thanks to for - * keeping me sane. - * Alan Cox - * - * - fix the clock turnaround code: it was writing to the wrong ports when - * called for the secondary channel, caching the current clock mode per- - * channel caused the cached register value to get out of sync with the - * actual one, the channels weren't serialized, the turnaround shouldn't - * be done on 66 MHz PCI bus - * - disable UltraATA/100 for HPT370 by default as the 33 MHz clock being used - * does not allow for this speed anyway - * - avoid touching disabled channels (e.g. HPT371/N are single channel chips, - * their primary channel is kind of virtual, it isn't tied to any pins) - * - fix/remove bad/unused timing tables and use one set of tables for the whole - * HPT37x chip family; save space by introducing the separate transfer mode - * table in which the mode lookup is done - * - use f_CNT value saved by the HighPoint BIOS as reading it directly gives - * the wrong PCI frequency since DPLL has already been calibrated by BIOS; - * read it only from the function 0 of HPT374 chips - * - fix the hotswap code: it caused RESET- to glitch when tristating the bus, - * and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead - * - pass to init_chipset() handlers a copy of the IDE PCI device structure as - * they tamper with its fields - * - pass to the init_setup handlers a copy of the ide_pci_device_t structure - * since they may tamper with its fields - * - prefix the driver startup messages with the real chip name - * - claim the extra 240 bytes of I/O space for all chips - * - optimize the UltraDMA filtering and the drive list lookup code - * - use pci_get_slot() to get to the function 1 of HPT36x/374 - * - cache offset of the channel's misc. control registers (MCRs) being used - * throughout the driver - * - only touch the relevant MCR when detecting the cable type on HPT374's - * function 1 - * - rename all the register related variables consistently - * - move all the interrupt twiddling code from the speedproc handlers into - * init_hwif_hpt366(), also grouping all the DMA related code together there - * - merge HPT36x/HPT37x speedproc handlers, fix PIO timing register mask and - * separate the UltraDMA and MWDMA masks there to avoid changing PIO timings - * when setting an UltraDMA mode - * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select - * the best possible one - * - clean up DMA timeout handling for HPT370 - * - switch to using the enumeration type to differ between the numerous chip - * variants, matching PCI device/revision ID with the chip type early, at the - * init_setup stage - * - extend the hpt_info structure to hold the DPLL and PCI clock frequencies, - * stop duplicating it for each channel by storing the pointer in the pci_dev - * structure: first, at the init_setup stage, point it to a static "template" - * with only the chip type and its specific base DPLL frequency, the highest - * UltraDMA mode, and the chip settings table pointer filled, then, at the - * init_chipset stage, allocate per-chip instance and fill it with the rest - * of the necessary information - * - get rid of the constant thresholds in the HPT37x PCI clock detection code, - * switch to calculating PCI clock frequency based on the chip's base DPLL - * frequency - * - switch to using the DPLL clock and enable UltraATA/133 mode by default on - * anything newer than HPT370/A (except HPT374 that is not capable of this - * mode according to the manual) - * - fold PCI clock detection and DPLL setup code into init_chipset_hpt366(), - * also fixing the interchanged 25/40 MHz PCI clock cases for HPT36x chips; - * unify HPT36x/37x timing setup code and the speedproc handlers by joining - * the register setting lists into the table indexed by the clock selected - * - set the correct hwif->ultra_mask for each individual chip - * - add Ultra and MW DMA mode filtering for the HPT37[24] based SATA cards - * - stop resetting HPT370's state machine before each DMA transfer as that has - * caused more harm than good - * Sergei Shtylyov, or - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define DRV_NAME "hpt366" - -/* various tuning parameters */ -#undef HPT_RESET_STATE_ENGINE -#undef HPT_DELAY_INTERRUPT - -static const char *bad_ata100_5[] = { - "IBM-DTLA-307075", - "IBM-DTLA-307060", - "IBM-DTLA-307045", - "IBM-DTLA-307030", - "IBM-DTLA-307020", - "IBM-DTLA-307015", - "IBM-DTLA-305040", - "IBM-DTLA-305030", - "IBM-DTLA-305020", - "IC35L010AVER07-0", - "IC35L020AVER07-0", - "IC35L030AVER07-0", - "IC35L040AVER07-0", - "IC35L060AVER07-0", - "WDC AC310200R", - NULL -}; - -static const char *bad_ata66_4[] = { - "IBM-DTLA-307075", - "IBM-DTLA-307060", - "IBM-DTLA-307045", - "IBM-DTLA-307030", - "IBM-DTLA-307020", - "IBM-DTLA-307015", - "IBM-DTLA-305040", - "IBM-DTLA-305030", - "IBM-DTLA-305020", - "IC35L010AVER07-0", - "IC35L020AVER07-0", - "IC35L030AVER07-0", - "IC35L040AVER07-0", - "IC35L060AVER07-0", - "WDC AC310200R", - "MAXTOR STM3320620A", - NULL -}; - -static const char *bad_ata66_3[] = { - "WDC AC310200R", - NULL -}; - -static const char *bad_ata33[] = { - "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2", - "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2", - "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4", - "Maxtor 90510D4", - "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2", - "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4", - "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2", - NULL -}; - -static u8 xfer_speeds[] = { - XFER_UDMA_6, - XFER_UDMA_5, - XFER_UDMA_4, - XFER_UDMA_3, - XFER_UDMA_2, - XFER_UDMA_1, - XFER_UDMA_0, - - XFER_MW_DMA_2, - XFER_MW_DMA_1, - XFER_MW_DMA_0, - - XFER_PIO_4, - XFER_PIO_3, - XFER_PIO_2, - XFER_PIO_1, - XFER_PIO_0 -}; - -/* Key for bus clock timings - * 36x 37x - * bits bits - * 0:3 0:3 data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA. - * cycles = value + 1 - * 4:7 4:8 data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA. - * cycles = value + 1 - * 8:11 9:12 cmd_high_time. Inactive time of DIOW_/DIOR_ during task file - * register access. - * 12:15 13:17 cmd_low_time. Active time of DIOW_/DIOR_ during task file - * register access. - * 16:18 18:20 udma_cycle_time. Clock cycles for UDMA xfer. - * - 21 CLK frequency: 0=ATA clock, 1=dual ATA clock. - * 19:21 22:24 pre_high_time. Time to initialize the 1st cycle for PIO and - * MW DMA xfer. - * 22:24 25:27 cmd_pre_high_time. Time to initialize the 1st PIO cycle for - * task file register access. - * 28 28 UDMA enable. - * 29 29 DMA enable. - * 30 30 PIO MST enable. If set, the chip is in bus master mode during - * PIO xfer. - * 31 31 FIFO enable. - */ - -static u32 forty_base_hpt36x[] = { - /* XFER_UDMA_6 */ 0x900fd943, - /* XFER_UDMA_5 */ 0x900fd943, - /* XFER_UDMA_4 */ 0x900fd943, - /* XFER_UDMA_3 */ 0x900ad943, - /* XFER_UDMA_2 */ 0x900bd943, - /* XFER_UDMA_1 */ 0x9008d943, - /* XFER_UDMA_0 */ 0x9008d943, - - /* XFER_MW_DMA_2 */ 0xa008d943, - /* XFER_MW_DMA_1 */ 0xa010d955, - /* XFER_MW_DMA_0 */ 0xa010d9fc, - - /* XFER_PIO_4 */ 0xc008d963, - /* XFER_PIO_3 */ 0xc010d974, - /* XFER_PIO_2 */ 0xc010d997, - /* XFER_PIO_1 */ 0xc010d9c7, - /* XFER_PIO_0 */ 0xc018d9d9 -}; - -static u32 thirty_three_base_hpt36x[] = { - /* XFER_UDMA_6 */ 0x90c9a731, - /* XFER_UDMA_5 */ 0x90c9a731, - /* XFER_UDMA_4 */ 0x90c9a731, - /* XFER_UDMA_3 */ 0x90cfa731, - /* XFER_UDMA_2 */ 0x90caa731, - /* XFER_UDMA_1 */ 0x90cba731, - /* XFER_UDMA_0 */ 0x90c8a731, - - /* XFER_MW_DMA_2 */ 0xa0c8a731, - /* XFER_MW_DMA_1 */ 0xa0c8a732, /* 0xa0c8a733 */ - /* XFER_MW_DMA_0 */ 0xa0c8a797, - - /* XFER_PIO_4 */ 0xc0c8a731, - /* XFER_PIO_3 */ 0xc0c8a742, - /* XFER_PIO_2 */ 0xc0d0a753, - /* XFER_PIO_1 */ 0xc0d0a7a3, /* 0xc0d0a793 */ - /* XFER_PIO_0 */ 0xc0d0a7aa /* 0xc0d0a7a7 */ -}; - -static u32 twenty_five_base_hpt36x[] = { - /* XFER_UDMA_6 */ 0x90c98521, - /* XFER_UDMA_5 */ 0x90c98521, - /* XFER_UDMA_4 */ 0x90c98521, - /* XFER_UDMA_3 */ 0x90cf8521, - /* XFER_UDMA_2 */ 0x90cf8521, - /* XFER_UDMA_1 */ 0x90cb8521, - /* XFER_UDMA_0 */ 0x90cb8521, - - /* XFER_MW_DMA_2 */ 0xa0ca8521, - /* XFER_MW_DMA_1 */ 0xa0ca8532, - /* XFER_MW_DMA_0 */ 0xa0ca8575, - - /* XFER_PIO_4 */ 0xc0ca8521, - /* XFER_PIO_3 */ 0xc0ca8532, - /* XFER_PIO_2 */ 0xc0ca8542, - /* XFER_PIO_1 */ 0xc0d08572, - /* XFER_PIO_0 */ 0xc0d08585 -}; - -/* - * The following are the new timing tables with PIO mode data/taskfile transfer - * overclocking fixed... - */ - -/* This table is taken from the HPT370 data manual rev. 1.02 */ -static u32 thirty_three_base_hpt37x[] = { - /* XFER_UDMA_6 */ 0x16455031, /* 0x16655031 ?? */ - /* XFER_UDMA_5 */ 0x16455031, - /* XFER_UDMA_4 */ 0x16455031, - /* XFER_UDMA_3 */ 0x166d5031, - /* XFER_UDMA_2 */ 0x16495031, - /* XFER_UDMA_1 */ 0x164d5033, - /* XFER_UDMA_0 */ 0x16515097, - - /* XFER_MW_DMA_2 */ 0x26515031, - /* XFER_MW_DMA_1 */ 0x26515033, - /* XFER_MW_DMA_0 */ 0x26515097, - - /* XFER_PIO_4 */ 0x06515021, - /* XFER_PIO_3 */ 0x06515022, - /* XFER_PIO_2 */ 0x06515033, - /* XFER_PIO_1 */ 0x06915065, - /* XFER_PIO_0 */ 0x06d1508a -}; - -static u32 fifty_base_hpt37x[] = { - /* XFER_UDMA_6 */ 0x1a861842, - /* XFER_UDMA_5 */ 0x1a861842, - /* XFER_UDMA_4 */ 0x1aae1842, - /* XFER_UDMA_3 */ 0x1a8e1842, - /* XFER_UDMA_2 */ 0x1a0e1842, - /* XFER_UDMA_1 */ 0x1a161854, - /* XFER_UDMA_0 */ 0x1a1a18ea, - - /* XFER_MW_DMA_2 */ 0x2a821842, - /* XFER_MW_DMA_1 */ 0x2a821854, - /* XFER_MW_DMA_0 */ 0x2a8218ea, - - /* XFER_PIO_4 */ 0x0a821842, - /* XFER_PIO_3 */ 0x0a821843, - /* XFER_PIO_2 */ 0x0a821855, - /* XFER_PIO_1 */ 0x0ac218a8, - /* XFER_PIO_0 */ 0x0b02190c -}; - -static u32 sixty_six_base_hpt37x[] = { - /* XFER_UDMA_6 */ 0x1c86fe62, - /* XFER_UDMA_5 */ 0x1caefe62, /* 0x1c8afe62 */ - /* XFER_UDMA_4 */ 0x1c8afe62, - /* XFER_UDMA_3 */ 0x1c8efe62, - /* XFER_UDMA_2 */ 0x1c92fe62, - /* XFER_UDMA_1 */ 0x1c9afe62, - /* XFER_UDMA_0 */ 0x1c82fe62, - - /* XFER_MW_DMA_2 */ 0x2c82fe62, - /* XFER_MW_DMA_1 */ 0x2c82fe66, - /* XFER_MW_DMA_0 */ 0x2c82ff2e, - - /* XFER_PIO_4 */ 0x0c82fe62, - /* XFER_PIO_3 */ 0x0c82fe84, - /* XFER_PIO_2 */ 0x0c82fea6, - /* XFER_PIO_1 */ 0x0d02ff26, - /* XFER_PIO_0 */ 0x0d42ff7f -}; - -#define HPT371_ALLOW_ATA133_6 1 -#define HPT302_ALLOW_ATA133_6 1 -#define HPT372_ALLOW_ATA133_6 1 -#define HPT370_ALLOW_ATA100_5 0 -#define HPT366_ALLOW_ATA66_4 1 -#define HPT366_ALLOW_ATA66_3 1 - -/* Supported ATA clock frequencies */ -enum ata_clock { - ATA_CLOCK_25MHZ, - ATA_CLOCK_33MHZ, - ATA_CLOCK_40MHZ, - ATA_CLOCK_50MHZ, - ATA_CLOCK_66MHZ, - NUM_ATA_CLOCKS -}; - -struct hpt_timings { - u32 pio_mask; - u32 dma_mask; - u32 ultra_mask; - u32 *clock_table[NUM_ATA_CLOCKS]; -}; - -/* - * Hold all the HighPoint chip information in one place. - */ - -struct hpt_info { - char *chip_name; /* Chip name */ - u8 chip_type; /* Chip type */ - u8 udma_mask; /* Allowed UltraDMA modes mask. */ - u8 dpll_clk; /* DPLL clock in MHz */ - u8 pci_clk; /* PCI clock in MHz */ - struct hpt_timings *timings; /* Chipset timing data */ - u8 clock; /* ATA clock selected */ -}; - -/* Supported HighPoint chips */ -enum { - HPT36x, - HPT370, - HPT370A, - HPT374, - HPT372, - HPT372A, - HPT302, - HPT371, - HPT372N, - HPT302N, - HPT371N -}; - -static struct hpt_timings hpt36x_timings = { - .pio_mask = 0xc1f8ffff, - .dma_mask = 0x303800ff, - .ultra_mask = 0x30070000, - .clock_table = { - [ATA_CLOCK_25MHZ] = twenty_five_base_hpt36x, - [ATA_CLOCK_33MHZ] = thirty_three_base_hpt36x, - [ATA_CLOCK_40MHZ] = forty_base_hpt36x, - [ATA_CLOCK_50MHZ] = NULL, - [ATA_CLOCK_66MHZ] = NULL - } -}; - -static struct hpt_timings hpt37x_timings = { - .pio_mask = 0xcfc3ffff, - .dma_mask = 0x31c001ff, - .ultra_mask = 0x303c0000, - .clock_table = { - [ATA_CLOCK_25MHZ] = NULL, - [ATA_CLOCK_33MHZ] = thirty_three_base_hpt37x, - [ATA_CLOCK_40MHZ] = NULL, - [ATA_CLOCK_50MHZ] = fifty_base_hpt37x, - [ATA_CLOCK_66MHZ] = sixty_six_base_hpt37x - } -}; - -static const struct hpt_info hpt36x = { - .chip_name = "HPT36x", - .chip_type = HPT36x, - .udma_mask = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2, - .dpll_clk = 0, /* no DPLL */ - .timings = &hpt36x_timings -}; - -static const struct hpt_info hpt370 = { - .chip_name = "HPT370", - .chip_type = HPT370, - .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4, - .dpll_clk = 48, - .timings = &hpt37x_timings -}; - -static const struct hpt_info hpt370a = { - .chip_name = "HPT370A", - .chip_type = HPT370A, - .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4, - .dpll_clk = 48, - .timings = &hpt37x_timings -}; - -static const struct hpt_info hpt374 = { - .chip_name = "HPT374", - .chip_type = HPT374, - .udma_mask = ATA_UDMA5, - .dpll_clk = 48, - .timings = &hpt37x_timings -}; - -static const struct hpt_info hpt372 = { - .chip_name = "HPT372", - .chip_type = HPT372, - .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, - .dpll_clk = 55, - .timings = &hpt37x_timings -}; - -static const struct hpt_info hpt372a = { - .chip_name = "HPT372A", - .chip_type = HPT372A, - .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, - .dpll_clk = 66, - .timings = &hpt37x_timings -}; - -static const struct hpt_info hpt302 = { - .chip_name = "HPT302", - .chip_type = HPT302, - .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, - .dpll_clk = 66, - .timings = &hpt37x_timings -}; - -static const struct hpt_info hpt371 = { - .chip_name = "HPT371", - .chip_type = HPT371, - .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, - .dpll_clk = 66, - .timings = &hpt37x_timings -}; - -static const struct hpt_info hpt372n = { - .chip_name = "HPT372N", - .chip_type = HPT372N, - .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, - .dpll_clk = 77, - .timings = &hpt37x_timings -}; - -static const struct hpt_info hpt302n = { - .chip_name = "HPT302N", - .chip_type = HPT302N, - .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, - .dpll_clk = 77, - .timings = &hpt37x_timings -}; - -static const struct hpt_info hpt371n = { - .chip_name = "HPT371N", - .chip_type = HPT371N, - .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, - .dpll_clk = 77, - .timings = &hpt37x_timings -}; - -static bool check_in_drive_list(ide_drive_t *drive, const char **list) -{ - return match_string(list, -1, (char *)&drive->id[ATA_ID_PROD]) >= 0; -} - -static struct hpt_info *hpt3xx_get_info(struct device *dev) -{ - struct ide_host *host = dev_get_drvdata(dev); - struct hpt_info *info = (struct hpt_info *)host->host_priv; - - return dev == host->dev[1] ? info + 1 : info; -} - -/* - * The Marvell bridge chips used on the HighPoint SATA cards do not seem - * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes... - */ - -static u8 hpt3xx_udma_filter(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = hpt3xx_get_info(hwif->dev); - u8 mask = hwif->ultra_mask; - - switch (info->chip_type) { - case HPT36x: - if (!HPT366_ALLOW_ATA66_4 || - check_in_drive_list(drive, bad_ata66_4)) - mask = ATA_UDMA3; - - if (!HPT366_ALLOW_ATA66_3 || - check_in_drive_list(drive, bad_ata66_3)) - mask = ATA_UDMA2; - break; - case HPT370: - if (!HPT370_ALLOW_ATA100_5 || - check_in_drive_list(drive, bad_ata100_5)) - mask = ATA_UDMA4; - break; - case HPT370A: - if (!HPT370_ALLOW_ATA100_5 || - check_in_drive_list(drive, bad_ata100_5)) - return ATA_UDMA4; - fallthrough; - case HPT372 : - case HPT372A: - case HPT372N: - case HPT374 : - if (ata_id_is_sata(drive->id)) - mask &= ~0x0e; - fallthrough; - default: - return mask; - } - - return check_in_drive_list(drive, bad_ata33) ? 0x00 : mask; -} - -static u8 hpt3xx_mdma_filter(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = hpt3xx_get_info(hwif->dev); - - switch (info->chip_type) { - case HPT372 : - case HPT372A: - case HPT372N: - case HPT374 : - if (ata_id_is_sata(drive->id)) - return 0x00; - fallthrough; - default: - return 0x07; - } -} - -static u32 get_speed_setting(u8 speed, struct hpt_info *info) -{ - int i; - - /* - * Lookup the transfer mode table to get the index into - * the timing table. - * - * NOTE: For XFER_PIO_SLOW, PIO mode 0 timings will be used. - */ - for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++) - if (xfer_speeds[i] == speed) - break; - - return info->timings->clock_table[info->clock][i]; -} - -static void hpt3xx_set_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - struct hpt_info *info = hpt3xx_get_info(hwif->dev); - struct hpt_timings *t = info->timings; - u8 itr_addr = 0x40 + (drive->dn * 4); - u32 old_itr = 0; - const u8 speed = drive->dma_mode; - u32 new_itr = get_speed_setting(speed, info); - u32 itr_mask = speed < XFER_MW_DMA_0 ? t->pio_mask : - (speed < XFER_UDMA_0 ? t->dma_mask : - t->ultra_mask); - - pci_read_config_dword(dev, itr_addr, &old_itr); - new_itr = (old_itr & ~itr_mask) | (new_itr & itr_mask); - /* - * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well) - * to avoid problems handling I/O errors later - */ - new_itr &= ~0xc0000000; - - pci_write_config_dword(dev, itr_addr, new_itr); -} - -static void hpt3xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - drive->dma_mode = drive->pio_mode; - hpt3xx_set_mode(hwif, drive); -} - -static void hpt3xx_maskproc(ide_drive_t *drive, int mask) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - struct hpt_info *info = hpt3xx_get_info(hwif->dev); - - if ((drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) == 0) - return; - - if (info->chip_type >= HPT370) { - u8 scr1 = 0; - - pci_read_config_byte(dev, 0x5a, &scr1); - if (((scr1 & 0x10) >> 4) != mask) { - if (mask) - scr1 |= 0x10; - else - scr1 &= ~0x10; - pci_write_config_byte(dev, 0x5a, scr1); - } - } else if (mask) - disable_irq(hwif->irq); - else - enable_irq(hwif->irq); -} - -/* - * This is specific to the HPT366 UDMA chipset - * by HighPoint|Triones Technologies, Inc. - */ -static void hpt366_dma_lost_irq(ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(drive->hwif->dev); - u8 mcr1 = 0, mcr3 = 0, scr1 = 0; - - pci_read_config_byte(dev, 0x50, &mcr1); - pci_read_config_byte(dev, 0x52, &mcr3); - pci_read_config_byte(dev, 0x5a, &scr1); - printk("%s: (%s) mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n", - drive->name, __func__, mcr1, mcr3, scr1); - if (scr1 & 0x10) - pci_write_config_byte(dev, 0x5a, scr1 & ~0x10); - ide_dma_lost_irq(drive); -} - -static void hpt370_clear_engine(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - - pci_write_config_byte(dev, hwif->select_data, 0x37); - udelay(10); -} - -static void hpt370_irq_timeout(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - u16 bfifo = 0; - u8 dma_cmd; - - pci_read_config_word(dev, hwif->select_data + 2, &bfifo); - printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff); - - /* get DMA command mode */ - dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); - /* stop DMA */ - outb(dma_cmd & ~ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD); - hpt370_clear_engine(drive); -} - -static void hpt370_dma_start(ide_drive_t *drive) -{ -#ifdef HPT_RESET_STATE_ENGINE - hpt370_clear_engine(drive); -#endif - ide_dma_start(drive); -} - -static int hpt370_dma_end(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); - - if (dma_stat & ATA_DMA_ACTIVE) { - /* wait a little */ - udelay(20); - dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); - if (dma_stat & ATA_DMA_ACTIVE) - hpt370_irq_timeout(drive); - } - return ide_dma_end(drive); -} - -/* returns 1 if DMA IRQ issued, 0 otherwise */ -static int hpt374_dma_test_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - u16 bfifo = 0; - u8 dma_stat; - - pci_read_config_word(dev, hwif->select_data + 2, &bfifo); - if (bfifo & 0x1FF) { -// printk("%s: %d bytes in FIFO\n", drive->name, bfifo); - return 0; - } - - dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); - /* return 1 if INTR asserted */ - if (dma_stat & ATA_DMA_INTR) - return 1; - - return 0; -} - -static int hpt374_dma_end(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 mcr = 0, mcr_addr = hwif->select_data; - u8 bwsr = 0, mask = hwif->channel ? 0x02 : 0x01; - - pci_read_config_byte(dev, 0x6a, &bwsr); - pci_read_config_byte(dev, mcr_addr, &mcr); - if (bwsr & mask) - pci_write_config_byte(dev, mcr_addr, mcr | 0x30); - return ide_dma_end(drive); -} - -/** - * hpt3xxn_set_clock - perform clock switching dance - * @hwif: hwif to switch - * @mode: clocking mode (0x21 for write, 0x23 otherwise) - * - * Switch the DPLL clock on the HPT3xxN devices. This is a right mess. - */ - -static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode) -{ - unsigned long base = hwif->extra_base; - u8 scr2 = inb(base + 0x6b); - - if ((scr2 & 0x7f) == mode) - return; - - /* Tristate the bus */ - outb(0x80, base + 0x63); - outb(0x80, base + 0x67); - - /* Switch clock and reset channels */ - outb(mode, base + 0x6b); - outb(0xc0, base + 0x69); - - /* - * Reset the state machines. - * NOTE: avoid accidentally enabling the disabled channels. - */ - outb(inb(base + 0x60) | 0x32, base + 0x60); - outb(inb(base + 0x64) | 0x32, base + 0x64); - - /* Complete reset */ - outb(0x00, base + 0x69); - - /* Reconnect channels to bus */ - outb(0x00, base + 0x63); - outb(0x00, base + 0x67); -} - -/** - * hpt3xxn_rw_disk - prepare for I/O - * @drive: drive for command - * @rq: block request structure - * - * This is called when a disk I/O is issued to HPT3xxN. - * We need it because of the clock switching. - */ - -static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq) -{ - hpt3xxn_set_clock(drive->hwif, rq_data_dir(rq) ? 0x21 : 0x23); -} - -/** - * hpt37x_calibrate_dpll - calibrate the DPLL - * @dev: PCI device - * - * Perform a calibration cycle on the DPLL. - * Returns 1 if this succeeds - */ -static int hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high) -{ - u32 dpll = (f_high << 16) | f_low | 0x100; - u8 scr2; - int i; - - pci_write_config_dword(dev, 0x5c, dpll); - - /* Wait for oscillator ready */ - for(i = 0; i < 0x5000; ++i) { - udelay(50); - pci_read_config_byte(dev, 0x5b, &scr2); - if (scr2 & 0x80) - break; - } - /* See if it stays ready (we'll just bail out if it's not yet) */ - for(i = 0; i < 0x1000; ++i) { - pci_read_config_byte(dev, 0x5b, &scr2); - /* DPLL destabilized? */ - if(!(scr2 & 0x80)) - return 0; - } - /* Turn off tuning, we have the DPLL set */ - pci_read_config_dword (dev, 0x5c, &dpll); - pci_write_config_dword(dev, 0x5c, (dpll & ~0x100)); - return 1; -} - -static void hpt3xx_disable_fast_irq(struct pci_dev *dev, u8 mcr_addr) -{ - struct ide_host *host = pci_get_drvdata(dev); - struct hpt_info *info = host->host_priv + (&dev->dev == host->dev[1]); - u8 chip_type = info->chip_type; - u8 new_mcr, old_mcr = 0; - - /* - * Disable the "fast interrupt" prediction. Don't hold off - * on interrupts. (== 0x01 despite what the docs say) - */ - pci_read_config_byte(dev, mcr_addr + 1, &old_mcr); - - if (chip_type >= HPT374) - new_mcr = old_mcr & ~0x07; - else if (chip_type >= HPT370) { - new_mcr = old_mcr; - new_mcr &= ~0x02; -#ifdef HPT_DELAY_INTERRUPT - new_mcr &= ~0x01; -#else - new_mcr |= 0x01; -#endif - } else /* HPT366 and HPT368 */ - new_mcr = old_mcr & ~0x80; - - if (new_mcr != old_mcr) - pci_write_config_byte(dev, mcr_addr + 1, new_mcr); -} - -static int init_chipset_hpt366(struct pci_dev *dev) -{ - unsigned long io_base = pci_resource_start(dev, 4); - struct hpt_info *info = hpt3xx_get_info(&dev->dev); - const char *name = DRV_NAME; - u8 pci_clk, dpll_clk = 0; /* PCI and DPLL clock in MHz */ - u8 chip_type; - enum ata_clock clock; - - chip_type = info->chip_type; - - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); - pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); - pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); - - /* - * First, try to estimate the PCI clock frequency... - */ - if (chip_type >= HPT370) { - u8 scr1 = 0; - u16 f_cnt = 0; - u32 temp = 0; - - /* Interrupt force enable. */ - pci_read_config_byte(dev, 0x5a, &scr1); - if (scr1 & 0x10) - pci_write_config_byte(dev, 0x5a, scr1 & ~0x10); - - /* - * HighPoint does this for HPT372A. - * NOTE: This register is only writeable via I/O space. - */ - if (chip_type == HPT372A) - outb(0x0e, io_base + 0x9c); - - /* - * Default to PCI clock. Make sure MA15/16 are set to output - * to prevent drives having problems with 40-pin cables. - */ - pci_write_config_byte(dev, 0x5b, 0x23); - - /* - * We'll have to read f_CNT value in order to determine - * the PCI clock frequency according to the following ratio: - * - * f_CNT = Fpci * 192 / Fdpll - * - * First try reading the register in which the HighPoint BIOS - * saves f_CNT value before reprogramming the DPLL from its - * default setting (which differs for the various chips). - * - * NOTE: This register is only accessible via I/O space; - * HPT374 BIOS only saves it for the function 0, so we have to - * always read it from there -- no need to check the result of - * pci_get_slot() for the function 0 as the whole device has - * been already "pinned" (via function 1) in init_setup_hpt374() - */ - if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) { - struct pci_dev *dev1 = pci_get_slot(dev->bus, - dev->devfn - 1); - unsigned long io_base = pci_resource_start(dev1, 4); - - temp = inl(io_base + 0x90); - pci_dev_put(dev1); - } else - temp = inl(io_base + 0x90); - - /* - * In case the signature check fails, we'll have to - * resort to reading the f_CNT register itself in hopes - * that nobody has touched the DPLL yet... - */ - if ((temp & 0xFFFFF000) != 0xABCDE000) { - int i; - - printk(KERN_WARNING "%s %s: no clock data saved by " - "BIOS\n", name, pci_name(dev)); - - /* Calculate the average value of f_CNT. */ - for (temp = i = 0; i < 128; i++) { - pci_read_config_word(dev, 0x78, &f_cnt); - temp += f_cnt & 0x1ff; - mdelay(1); - } - f_cnt = temp / 128; - } else - f_cnt = temp & 0x1ff; - - dpll_clk = info->dpll_clk; - pci_clk = (f_cnt * dpll_clk) / 192; - - /* Clamp PCI clock to bands. */ - if (pci_clk < 40) - pci_clk = 33; - else if(pci_clk < 45) - pci_clk = 40; - else if(pci_clk < 55) - pci_clk = 50; - else - pci_clk = 66; - - printk(KERN_INFO "%s %s: DPLL base: %d MHz, f_CNT: %d, " - "assuming %d MHz PCI\n", name, pci_name(dev), - dpll_clk, f_cnt, pci_clk); - } else { - u32 itr1 = 0; - - pci_read_config_dword(dev, 0x40, &itr1); - - /* Detect PCI clock by looking at cmd_high_time. */ - switch ((itr1 >> 8) & 0x0f) { - case 0x09: - pci_clk = 40; - break; - case 0x05: - pci_clk = 25; - break; - case 0x07: - default: - pci_clk = 33; - break; - } - } - - /* Let's assume we'll use PCI clock for the ATA clock... */ - switch (pci_clk) { - case 25: - clock = ATA_CLOCK_25MHZ; - break; - case 33: - default: - clock = ATA_CLOCK_33MHZ; - break; - case 40: - clock = ATA_CLOCK_40MHZ; - break; - case 50: - clock = ATA_CLOCK_50MHZ; - break; - case 66: - clock = ATA_CLOCK_66MHZ; - break; - } - - /* - * Only try the DPLL if we don't have a table for the PCI clock that - * we are running at for HPT370/A, always use it for anything newer... - * - * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI. - * We also don't like using the DPLL because this causes glitches - * on PRST-/SRST- when the state engine gets reset... - */ - if (chip_type >= HPT374 || info->timings->clock_table[clock] == NULL) { - u16 f_low, delta = pci_clk < 50 ? 2 : 4; - int adjust; - - /* - * Select 66 MHz DPLL clock only if UltraATA/133 mode is - * supported/enabled, use 50 MHz DPLL clock otherwise... - */ - if (info->udma_mask == ATA_UDMA6) { - dpll_clk = 66; - clock = ATA_CLOCK_66MHZ; - } else if (dpll_clk) { /* HPT36x chips don't have DPLL */ - dpll_clk = 50; - clock = ATA_CLOCK_50MHZ; - } - - if (info->timings->clock_table[clock] == NULL) { - printk(KERN_ERR "%s %s: unknown bus timing!\n", - name, pci_name(dev)); - return -EIO; - } - - /* Select the DPLL clock. */ - pci_write_config_byte(dev, 0x5b, 0x21); - - /* - * Adjust the DPLL based upon PCI clock, enable it, - * and wait for stabilization... - */ - f_low = (pci_clk * 48) / dpll_clk; - - for (adjust = 0; adjust < 8; adjust++) { - if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta)) - break; - - /* - * See if it'll settle at a fractionally different clock - */ - if (adjust & 1) - f_low -= adjust >> 1; - else - f_low += adjust >> 1; - } - if (adjust == 8) { - printk(KERN_ERR "%s %s: DPLL did not stabilize!\n", - name, pci_name(dev)); - return -EIO; - } - - printk(KERN_INFO "%s %s: using %d MHz DPLL clock\n", - name, pci_name(dev), dpll_clk); - } else { - /* Mark the fact that we're not using the DPLL. */ - dpll_clk = 0; - - printk(KERN_INFO "%s %s: using %d MHz PCI clock\n", - name, pci_name(dev), pci_clk); - } - - /* Store the clock frequencies. */ - info->dpll_clk = dpll_clk; - info->pci_clk = pci_clk; - info->clock = clock; - - if (chip_type >= HPT370) { - u8 mcr1, mcr4; - - /* - * Reset the state engines. - * NOTE: Avoid accidentally enabling the disabled channels. - */ - pci_read_config_byte (dev, 0x50, &mcr1); - pci_read_config_byte (dev, 0x54, &mcr4); - pci_write_config_byte(dev, 0x50, (mcr1 | 0x32)); - pci_write_config_byte(dev, 0x54, (mcr4 | 0x32)); - udelay(100); - } - - /* - * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in - * the MISC. register to stretch the UltraDMA Tss timing. - * NOTE: This register is only writeable via I/O space. - */ - if (chip_type == HPT371N && clock == ATA_CLOCK_66MHZ) - outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c); - - hpt3xx_disable_fast_irq(dev, 0x50); - hpt3xx_disable_fast_irq(dev, 0x54); - - return 0; -} - -static u8 hpt3xx_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - struct hpt_info *info = hpt3xx_get_info(hwif->dev); - u8 chip_type = info->chip_type; - u8 scr1 = 0, ata66 = hwif->channel ? 0x01 : 0x02; - - /* - * The HPT37x uses the CBLID pins as outputs for MA15/MA16 - * address lines to access an external EEPROM. To read valid - * cable detect state the pins must be enabled as inputs. - */ - if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) { - /* - * HPT374 PCI function 1 - * - set bit 15 of reg 0x52 to enable TCBLID as input - * - set bit 15 of reg 0x56 to enable FCBLID as input - */ - u8 mcr_addr = hwif->select_data + 2; - u16 mcr; - - pci_read_config_word(dev, mcr_addr, &mcr); - pci_write_config_word(dev, mcr_addr, mcr | 0x8000); - /* Debounce, then read cable ID register */ - udelay(10); - pci_read_config_byte(dev, 0x5a, &scr1); - pci_write_config_word(dev, mcr_addr, mcr); - } else if (chip_type >= HPT370) { - /* - * HPT370/372 and 374 pcifn 0 - * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs - */ - u8 scr2 = 0; - - pci_read_config_byte(dev, 0x5b, &scr2); - pci_write_config_byte(dev, 0x5b, scr2 & ~1); - /* Debounce, then read cable ID register */ - udelay(10); - pci_read_config_byte(dev, 0x5a, &scr1); - pci_write_config_byte(dev, 0x5b, scr2); - } else - pci_read_config_byte(dev, 0x5a, &scr1); - - return (scr1 & ata66) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; -} - -static void init_hwif_hpt366(ide_hwif_t *hwif) -{ - struct hpt_info *info = hpt3xx_get_info(hwif->dev); - u8 chip_type = info->chip_type; - - /* Cache the channel's MISC. control registers' offset */ - hwif->select_data = hwif->channel ? 0x54 : 0x50; - - /* - * HPT3xxN chips have some complications: - * - * - on 33 MHz PCI we must clock switch - * - on 66 MHz PCI we must NOT use the PCI clock - */ - if (chip_type >= HPT372N && info->dpll_clk && info->pci_clk < 66) { - /* - * Clock is shared between the channels, - * so we'll have to serialize them... :-( - */ - hwif->host->host_flags |= IDE_HFLAG_SERIALIZE; - hwif->rw_disk = &hpt3xxn_rw_disk; - } -} - -static int init_dma_hpt366(ide_hwif_t *hwif, - const struct ide_port_info *d) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long flags, base = ide_pci_dma_base(hwif, d); - u8 dma_old, dma_new, masterdma = 0, slavedma = 0; - - if (base == 0) - return -1; - - hwif->dma_base = base; - - if (ide_pci_check_simplex(hwif, d) < 0) - return -1; - - if (ide_pci_set_master(dev, d->name) < 0) - return -1; - - dma_old = inb(base + 2); - - local_irq_save(flags); - - dma_new = dma_old; - pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma); - pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47, &slavedma); - - if (masterdma & 0x30) dma_new |= 0x20; - if ( slavedma & 0x30) dma_new |= 0x40; - if (dma_new != dma_old) - outb(dma_new, base + 2); - - local_irq_restore(flags); - - printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n", - hwif->name, base, base + 7); - - hwif->extra_base = base + (hwif->channel ? 8 : 16); - - if (ide_allocate_dma_engine(hwif)) - return -1; - - return 0; -} - -static void hpt374_init(struct pci_dev *dev, struct pci_dev *dev2) -{ - if (dev2->irq != dev->irq) { - /* FIXME: we need a core pci_set_interrupt() */ - dev2->irq = dev->irq; - printk(KERN_INFO DRV_NAME " %s: PCI config space interrupt " - "fixed\n", pci_name(dev2)); - } -} - -static void hpt371_init(struct pci_dev *dev) -{ - u8 mcr1 = 0; - - /* - * HPT371 chips physically have only one channel, the secondary one, - * but the primary channel registers do exist! Go figure... - * So, we manually disable the non-existing channel here - * (if the BIOS hasn't done this already). - */ - pci_read_config_byte(dev, 0x50, &mcr1); - if (mcr1 & 0x04) - pci_write_config_byte(dev, 0x50, mcr1 & ~0x04); -} - -static int hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2) -{ - u8 mcr1 = 0, pin1 = 0, pin2 = 0; - - /* - * Now we'll have to force both channels enabled if - * at least one of them has been enabled by BIOS... - */ - pci_read_config_byte(dev, 0x50, &mcr1); - if (mcr1 & 0x30) - pci_write_config_byte(dev, 0x50, mcr1 | 0x30); - - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); - pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2); - - if (pin1 != pin2 && dev->irq == dev2->irq) { - printk(KERN_INFO DRV_NAME " %s: onboard version of chipset, " - "pin1=%d pin2=%d\n", pci_name(dev), pin1, pin2); - return 1; - } - - return 0; -} - -#define IDE_HFLAGS_HPT3XX \ - (IDE_HFLAG_NO_ATAPI_DMA | \ - IDE_HFLAG_OFF_BOARD) - -static const struct ide_port_ops hpt3xx_port_ops = { - .set_pio_mode = hpt3xx_set_pio_mode, - .set_dma_mode = hpt3xx_set_mode, - .maskproc = hpt3xx_maskproc, - .mdma_filter = hpt3xx_mdma_filter, - .udma_filter = hpt3xx_udma_filter, - .cable_detect = hpt3xx_cable_detect, -}; - -static const struct ide_dma_ops hpt37x_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = ide_dma_start, - .dma_end = hpt374_dma_end, - .dma_test_irq = hpt374_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = ide_dma_sff_read_status, -}; - -static const struct ide_dma_ops hpt370_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = hpt370_dma_start, - .dma_end = hpt370_dma_end, - .dma_test_irq = ide_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_clear = hpt370_irq_timeout, - .dma_sff_read_status = ide_dma_sff_read_status, -}; - -static const struct ide_dma_ops hpt36x_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = ide_dma_start, - .dma_end = ide_dma_end, - .dma_test_irq = ide_dma_test_irq, - .dma_lost_irq = hpt366_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = ide_dma_sff_read_status, -}; - -static const struct ide_port_info hpt366_chipsets[] = { - { /* 0: HPT36x */ - .name = DRV_NAME, - .init_chipset = init_chipset_hpt366, - .init_hwif = init_hwif_hpt366, - .init_dma = init_dma_hpt366, - /* - * HPT36x chips have one channel per function and have - * both channel enable bits located differently and visible - * to both functions -- really stupid design decision... :-( - * Bit 4 is for the primary channel, bit 5 for the secondary. - */ - .enablebits = {{0x50,0x10,0x10}, {0x54,0x04,0x04}}, - .port_ops = &hpt3xx_port_ops, - .dma_ops = &hpt36x_dma_ops, - .host_flags = IDE_HFLAGS_HPT3XX | IDE_HFLAG_SINGLE, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - }, - { /* 1: HPT3xx */ - .name = DRV_NAME, - .init_chipset = init_chipset_hpt366, - .init_hwif = init_hwif_hpt366, - .init_dma = init_dma_hpt366, - .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, - .port_ops = &hpt3xx_port_ops, - .dma_ops = &hpt37x_dma_ops, - .host_flags = IDE_HFLAGS_HPT3XX, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - } -}; - -/** - * hpt366_init_one - called when an HPT366 is found - * @dev: the hpt366 device - * @id: the matching pci id - * - * Called when the PCI registration layer (or the IDE initialization) - * finds a device matching our IDE device tables. - */ -static int hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - const struct hpt_info *info = NULL; - struct hpt_info *dyn_info; - struct pci_dev *dev2 = NULL; - struct ide_port_info d; - u8 idx = id->driver_data; - u8 rev = dev->revision; - int ret; - - if ((idx == 0 || idx == 4) && (PCI_FUNC(dev->devfn) & 1)) - return -ENODEV; - - switch (idx) { - case 0: - if (rev < 3) - info = &hpt36x; - else { - switch (min_t(u8, rev, 6)) { - case 3: info = &hpt370; break; - case 4: info = &hpt370a; break; - case 5: info = &hpt372; break; - case 6: info = &hpt372n; break; - } - idx++; - } - break; - case 1: - info = (rev > 1) ? &hpt372n : &hpt372a; - break; - case 2: - info = (rev > 1) ? &hpt302n : &hpt302; - break; - case 3: - hpt371_init(dev); - info = (rev > 1) ? &hpt371n : &hpt371; - break; - case 4: - info = &hpt374; - break; - case 5: - info = &hpt372n; - break; - } - - printk(KERN_INFO DRV_NAME ": %s chipset detected\n", info->chip_name); - - d = hpt366_chipsets[min_t(u8, idx, 1)]; - - d.udma_mask = info->udma_mask; - - /* fixup ->dma_ops for HPT370/HPT370A */ - if (info == &hpt370 || info == &hpt370a) - d.dma_ops = &hpt370_dma_ops; - - if (info == &hpt36x || info == &hpt374) - dev2 = pci_get_slot(dev->bus, dev->devfn + 1); - - dyn_info = kcalloc(dev2 ? 2 : 1, sizeof(*dyn_info), GFP_KERNEL); - if (dyn_info == NULL) { - printk(KERN_ERR "%s %s: out of memory!\n", - d.name, pci_name(dev)); - pci_dev_put(dev2); - return -ENOMEM; - } - - /* - * Copy everything from a static "template" structure - * to just allocated per-chip hpt_info structure. - */ - memcpy(dyn_info, info, sizeof(*dyn_info)); - - if (dev2) { - memcpy(dyn_info + 1, info, sizeof(*dyn_info)); - - if (info == &hpt374) - hpt374_init(dev, dev2); - else { - if (hpt36x_init(dev, dev2)) - d.host_flags &= ~IDE_HFLAG_NON_BOOTABLE; - } - - ret = ide_pci_init_two(dev, dev2, &d, dyn_info); - if (ret < 0) { - pci_dev_put(dev2); - kfree(dyn_info); - } - return ret; - } - - ret = ide_pci_init_one(dev, &d, dyn_info); - if (ret < 0) - kfree(dyn_info); - - return ret; -} - -static void hpt366_remove(struct pci_dev *dev) -{ - struct ide_host *host = pci_get_drvdata(dev); - struct ide_info *info = host->host_priv; - struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL; - - ide_pci_remove(dev); - pci_dev_put(dev2); - kfree(info); -} - -static const struct pci_device_id hpt366_pci_tbl[] = { - { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), 0 }, - { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), 1 }, - { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), 2 }, - { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT371), 3 }, - { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT374), 4 }, - { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), 5 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl); - -static struct pci_driver hpt366_pci_driver = { - .name = "HPT366_IDE", - .id_table = hpt366_pci_tbl, - .probe = hpt366_init_one, - .remove = hpt366_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init hpt366_ide_init(void) -{ - return ide_pci_register_driver(&hpt366_pci_driver); -} - -static void __exit hpt366_ide_exit(void) -{ - pci_unregister_driver(&hpt366_pci_driver); -} - -module_init(hpt366_ide_init); -module_exit(hpt366_ide_exit); - -MODULE_AUTHOR("Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for Highpoint HPT366 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c deleted file mode 100644 index 743bc3693ac8..000000000000 --- a/drivers/ide/ht6560b.c +++ /dev/null @@ -1,383 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1995-2000 Linus Torvalds & author (see below) - */ - -/* - * HT-6560B EIDE-controller support - * To activate controller support use kernel parameter "ide0=ht6560b". - * Use hdparm utility to enable PIO mode support. - * - * Author: Mikko Ala-Fossi - * Jan Evert van Grootheest - * - */ - -#define DRV_NAME "ht6560b" -#define HT6560B_VERSION "v0.08" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* #define DEBUG */ /* remove comments for DEBUG messages */ - -/* - * The special i/o-port that HT-6560B uses to configuration: - * bit0 (0x01): "1" selects secondary interface - * bit2 (0x04): "1" enables FIFO function - * bit5 (0x20): "1" enables prefetched data read function (???) - * - * The special i/o-port that HT-6560A uses to configuration: - * bit0 (0x01): "1" selects secondary interface - * bit1 (0x02): "1" enables prefetched data read function - * bit2 (0x04): "0" enables multi-master system (?) - * bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time (?) - */ -#define HT_CONFIG_PORT 0x3e6 - -static inline u8 HT_CONFIG(ide_drive_t *drive) -{ - return ((unsigned long)ide_get_drivedata(drive) & 0xff00) >> 8; -} - -/* - * FIFO + PREFETCH (both a/b-model) - */ -#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */ -/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */ -#define HT_SECONDARY_IF 0x01 -#define HT_PREFETCH_MODE 0x20 - -/* - * ht6560b Timing values: - * - * I reviewed some assembler source listings of htide drivers and found - * out how they setup those cycle time interfacing values, as they at Holtek - * call them. IDESETUP.COM that is supplied with the drivers figures out - * optimal values and fetches those values to drivers. I found out that - * they use Select register to fetch timings to the ide board right after - * interface switching. After that it was quite easy to add code to - * ht6560b.c. - * - * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine - * for hda and hdc. But hdb needed higher values to work, so I guess - * that sometimes it is necessary to give higher value than IDESETUP - * gives. [see cmd640.c for an extreme example of this. -ml] - * - * Perhaps I should explain something about these timing values: - * The higher nibble of value is the Recovery Time (rt) and the lower nibble - * of the value is the Active Time (at). Minimum value 2 is the fastest and - * the maximum value 15 is the slowest. Default values should be 15 for both. - * So 0x24 means 2 for rt and 4 for at. Each of the drives should have - * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or - * similar. If value is too small there will be all sorts of failures. - * - * Timing byte consists of - * High nibble: Recovery Cycle Time (rt) - * The valid values range from 2 to 15. The default is 15. - * - * Low nibble: Active Cycle Time (at) - * The valid values range from 2 to 15. The default is 15. - * - * You can obtain optimized timing values by running Holtek IDESETUP.COM - * for DOS. DOS drivers get their timing values from command line, where - * the first value is the Recovery Time and the second value is the - * Active Time for each drive. Smaller value gives higher speed. - * In case of failures you should probably fall back to a higher value. - */ -static inline u8 HT_TIMING(ide_drive_t *drive) -{ - return (unsigned long)ide_get_drivedata(drive) & 0x00ff; -} - -#define HT_TIMING_DEFAULT 0xff - -/* - * This routine handles interface switching for the peculiar hardware design - * on the F.G.I./Holtek HT-6560B VLB IDE interface. - * The HT-6560B can only enable one IDE port at a time, and requires a - * silly sequence (below) whenever we switch between primary and secondary. - */ - -/* - * This routine is invoked from ide.c to prepare for access to a given drive. - */ -static void ht6560b_dev_select(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - unsigned long flags; - static u8 current_select = 0; - static u8 current_timing = 0; - u8 select, timing; - - local_irq_save(flags); - - select = HT_CONFIG(drive); - timing = HT_TIMING(drive); - - /* - * Need to enforce prefetch sometimes because otherwise - * it'll hang (hard). - */ - if (drive->media != ide_disk || - (drive->dev_flags & IDE_DFLAG_PRESENT) == 0) - select |= HT_PREFETCH_MODE; - - if (select != current_select || timing != current_timing) { - current_select = select; - current_timing = timing; - (void)inb(HT_CONFIG_PORT); - (void)inb(HT_CONFIG_PORT); - (void)inb(HT_CONFIG_PORT); - (void)inb(HT_CONFIG_PORT); - outb(select, HT_CONFIG_PORT); - /* - * Set timing for this drive: - */ - outb(timing, hwif->io_ports.device_addr); - (void)inb(hwif->io_ports.status_addr); -#ifdef DEBUG - printk("ht6560b: %s: select=%#x timing=%#x\n", - drive->name, select, timing); -#endif - } - local_irq_restore(flags); - - outb(drive->select | ATA_DEVICE_OBS, hwif->io_ports.device_addr); -} - -/* - * Autodetection and initialization of ht6560b - */ -static int __init try_to_init_ht6560b(void) -{ - u8 orig_value; - int i; - - /* Autodetect ht6560b */ - if ((orig_value = inb(HT_CONFIG_PORT)) == 0xff) - return 0; - - for (i=3;i>0;i--) { - outb(0x00, HT_CONFIG_PORT); - if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) { - outb(orig_value, HT_CONFIG_PORT); - return 0; - } - } - outb(0x00, HT_CONFIG_PORT); - if ((~inb(HT_CONFIG_PORT))& 0x3f) { - outb(orig_value, HT_CONFIG_PORT); - return 0; - } - /* - * Ht6560b autodetected - */ - outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT); - outb(HT_TIMING_DEFAULT, 0x1f6); /* Select register */ - (void)inb(0x1f7); /* Status register */ - - printk("ht6560b " HT6560B_VERSION - ": chipset detected and initialized" -#ifdef DEBUG - " with debug enabled" -#endif - "\n" - ); - return 1; -} - -static u8 ht_pio2timings(ide_drive_t *drive, const u8 pio) -{ - int active_time, recovery_time; - int active_cycles, recovery_cycles; - int bus_speed = ide_vlb_clk ? ide_vlb_clk : 50; - - if (pio) { - unsigned int cycle_time; - struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); - - cycle_time = ide_pio_cycle_time(drive, pio); - - /* - * Just like opti621.c we try to calculate the - * actual cycle time for recovery and activity - * according system bus speed. - */ - active_time = t->active; - recovery_time = cycle_time - active_time - t->setup; - /* - * Cycle times should be Vesa bus cycles - */ - active_cycles = (active_time * bus_speed + 999) / 1000; - recovery_cycles = (recovery_time * bus_speed + 999) / 1000; - /* - * Upper and lower limits - */ - if (active_cycles < 2) active_cycles = 2; - if (recovery_cycles < 2) recovery_cycles = 2; - if (active_cycles > 15) active_cycles = 15; - if (recovery_cycles > 15) recovery_cycles = 0; /* 0==16 */ - -#ifdef DEBUG - printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time); -#endif - - return (u8)((recovery_cycles << 4) | active_cycles); - } else { - -#ifdef DEBUG - printk("ht6560b: drive %s setting pio=0\n", drive->name); -#endif - - return HT_TIMING_DEFAULT; /* default setting */ - } -} - -static DEFINE_SPINLOCK(ht6560b_lock); - -/* - * Enable/Disable so called prefetch mode - */ -static void ht_set_prefetch(ide_drive_t *drive, u8 state) -{ - unsigned long flags, config; - int t = HT_PREFETCH_MODE << 8; - - spin_lock_irqsave(&ht6560b_lock, flags); - - config = (unsigned long)ide_get_drivedata(drive); - - /* - * Prefetch mode and unmask irq seems to conflict - */ - if (state) { - config |= t; /* enable prefetch mode */ - drive->dev_flags |= IDE_DFLAG_NO_UNMASK; - drive->dev_flags &= ~IDE_DFLAG_UNMASK; - } else { - config &= ~t; /* disable prefetch mode */ - drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK; - } - - ide_set_drivedata(drive, (void *)config); - - spin_unlock_irqrestore(&ht6560b_lock, flags); - -#ifdef DEBUG - printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis")); -#endif -} - -static void ht6560b_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - unsigned long flags, config; - const u8 pio = drive->pio_mode - XFER_PIO_0; - u8 timing; - - switch (pio) { - case 8: /* set prefetch off */ - case 9: /* set prefetch on */ - ht_set_prefetch(drive, pio & 1); - return; - } - - timing = ht_pio2timings(drive, pio); - - spin_lock_irqsave(&ht6560b_lock, flags); - config = (unsigned long)ide_get_drivedata(drive); - config &= 0xff00; - config |= timing; - ide_set_drivedata(drive, (void *)config); - spin_unlock_irqrestore(&ht6560b_lock, flags); - -#ifdef DEBUG - printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing); -#endif -} - -static void __init ht6560b_init_dev(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - /* Setting default configurations for drives. */ - unsigned long t = (HT_CONFIG_DEFAULT << 8) | HT_TIMING_DEFAULT; - - if (hwif->channel) - t |= (HT_SECONDARY_IF << 8); - - ide_set_drivedata(drive, (void *)t); -} - -static bool probe_ht6560b; - -module_param_named(probe, probe_ht6560b, bool, 0); -MODULE_PARM_DESC(probe, "probe for HT6560B chipset"); - -static const struct ide_tp_ops ht6560b_tp_ops = { - .exec_command = ide_exec_command, - .read_status = ide_read_status, - .read_altstatus = ide_read_altstatus, - .write_devctl = ide_write_devctl, - - .dev_select = ht6560b_dev_select, - .tf_load = ide_tf_load, - .tf_read = ide_tf_read, - - .input_data = ide_input_data, - .output_data = ide_output_data, -}; - -static const struct ide_port_ops ht6560b_port_ops = { - .init_dev = ht6560b_init_dev, - .set_pio_mode = ht6560b_set_pio_mode, -}; - -static const struct ide_port_info ht6560b_port_info __initconst = { - .name = DRV_NAME, - .chipset = ide_ht6560b, - .tp_ops = &ht6560b_tp_ops, - .port_ops = &ht6560b_port_ops, - .host_flags = IDE_HFLAG_SERIALIZE | /* is this needed? */ - IDE_HFLAG_NO_DMA | - IDE_HFLAG_ABUSE_PREFETCH, - .pio_mask = ATA_PIO4, -}; - -static int __init ht6560b_init(void) -{ - if (probe_ht6560b == 0) - return -ENODEV; - - if (!request_region(HT_CONFIG_PORT, 1, DRV_NAME)) { - printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n", - __func__); - return -ENODEV; - } - - if (!try_to_init_ht6560b()) { - printk(KERN_NOTICE "%s: HBA not found\n", __func__); - goto release_region; - } - - return ide_legacy_device_add(&ht6560b_port_info, 0); - -release_region: - release_region(HT_CONFIG_PORT, 1); - return -ENODEV; -} - -module_init(ht6560b_init); - -MODULE_AUTHOR("See Local File"); -MODULE_DESCRIPTION("HT-6560B EIDE-controller support"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c deleted file mode 100644 index 329c7e4bc9d0..000000000000 --- a/drivers/ide/icside.c +++ /dev/null @@ -1,692 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 1996-2004 Russell King. - * - * Please note that this platform does not support 32-bit IDE IO. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define DRV_NAME "icside" - -#define ICS_IDENT_OFFSET 0x2280 - -#define ICS_ARCIN_V5_INTRSTAT 0x0000 -#define ICS_ARCIN_V5_INTROFFSET 0x0004 -#define ICS_ARCIN_V5_IDEOFFSET 0x2800 -#define ICS_ARCIN_V5_IDEALTOFFSET 0x2b80 -#define ICS_ARCIN_V5_IDESTEPPING 6 - -#define ICS_ARCIN_V6_IDEOFFSET_1 0x2000 -#define ICS_ARCIN_V6_INTROFFSET_1 0x2200 -#define ICS_ARCIN_V6_INTRSTAT_1 0x2290 -#define ICS_ARCIN_V6_IDEALTOFFSET_1 0x2380 -#define ICS_ARCIN_V6_IDEOFFSET_2 0x3000 -#define ICS_ARCIN_V6_INTROFFSET_2 0x3200 -#define ICS_ARCIN_V6_INTRSTAT_2 0x3290 -#define ICS_ARCIN_V6_IDEALTOFFSET_2 0x3380 -#define ICS_ARCIN_V6_IDESTEPPING 6 - -struct cardinfo { - unsigned int dataoffset; - unsigned int ctrloffset; - unsigned int stepping; -}; - -static struct cardinfo icside_cardinfo_v5 = { - .dataoffset = ICS_ARCIN_V5_IDEOFFSET, - .ctrloffset = ICS_ARCIN_V5_IDEALTOFFSET, - .stepping = ICS_ARCIN_V5_IDESTEPPING, -}; - -static struct cardinfo icside_cardinfo_v6_1 = { - .dataoffset = ICS_ARCIN_V6_IDEOFFSET_1, - .ctrloffset = ICS_ARCIN_V6_IDEALTOFFSET_1, - .stepping = ICS_ARCIN_V6_IDESTEPPING, -}; - -static struct cardinfo icside_cardinfo_v6_2 = { - .dataoffset = ICS_ARCIN_V6_IDEOFFSET_2, - .ctrloffset = ICS_ARCIN_V6_IDEALTOFFSET_2, - .stepping = ICS_ARCIN_V6_IDESTEPPING, -}; - -struct icside_state { - unsigned int channel; - unsigned int enabled; - void __iomem *irq_port; - void __iomem *ioc_base; - unsigned int sel; - unsigned int type; - struct ide_host *host; -}; - -#define ICS_TYPE_A3IN 0 -#define ICS_TYPE_A3USER 1 -#define ICS_TYPE_V6 3 -#define ICS_TYPE_V5 15 -#define ICS_TYPE_NOTYPE ((unsigned int)-1) - -/* ---------------- Version 5 PCB Support Functions --------------------- */ -/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) - * Purpose : enable interrupts from card - */ -static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) -{ - struct icside_state *state = ec->irq_data; - - writeb(0, state->irq_port + ICS_ARCIN_V5_INTROFFSET); -} - -/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) - * Purpose : disable interrupts from card - */ -static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) -{ - struct icside_state *state = ec->irq_data; - - readb(state->irq_port + ICS_ARCIN_V5_INTROFFSET); -} - -static const expansioncard_ops_t icside_ops_arcin_v5 = { - .irqenable = icside_irqenable_arcin_v5, - .irqdisable = icside_irqdisable_arcin_v5, -}; - - -/* ---------------- Version 6 PCB Support Functions --------------------- */ -/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) - * Purpose : enable interrupts from card - */ -static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) -{ - struct icside_state *state = ec->irq_data; - void __iomem *base = state->irq_port; - - state->enabled = 1; - - switch (state->channel) { - case 0: - writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1); - readb(base + ICS_ARCIN_V6_INTROFFSET_2); - break; - case 1: - writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2); - readb(base + ICS_ARCIN_V6_INTROFFSET_1); - break; - } -} - -/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) - * Purpose : disable interrupts from card - */ -static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) -{ - struct icside_state *state = ec->irq_data; - - state->enabled = 0; - - readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); - readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); -} - -/* Prototype: icside_irqprobe(struct expansion_card *ec) - * Purpose : detect an active interrupt from card - */ -static int icside_irqpending_arcin_v6(struct expansion_card *ec) -{ - struct icside_state *state = ec->irq_data; - - return readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 || - readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1; -} - -static const expansioncard_ops_t icside_ops_arcin_v6 = { - .irqenable = icside_irqenable_arcin_v6, - .irqdisable = icside_irqdisable_arcin_v6, - .irqpending = icside_irqpending_arcin_v6, -}; - -/* - * Handle routing of interrupts. This is called before - * we write the command to the drive. - */ -static void icside_maskproc(ide_drive_t *drive, int mask) -{ - ide_hwif_t *hwif = drive->hwif; - struct expansion_card *ec = ECARD_DEV(hwif->dev); - struct icside_state *state = ecard_get_drvdata(ec); - unsigned long flags; - - local_irq_save(flags); - - state->channel = hwif->channel; - - if (state->enabled && !mask) { - switch (hwif->channel) { - case 0: - writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); - readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); - break; - case 1: - writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); - readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); - break; - } - } else { - readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); - readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); - } - - local_irq_restore(flags); -} - -static const struct ide_port_ops icside_v6_no_dma_port_ops = { - .maskproc = icside_maskproc, -}; - -#ifdef CONFIG_BLK_DEV_IDEDMA_ICS -/* - * SG-DMA support. - * - * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers. - * There is only one DMA controller per card, which means that only - * one drive can be accessed at one time. NOTE! We do not enforce that - * here, but we rely on the main IDE driver spotting that both - * interfaces use the same IRQ, which should guarantee this. - */ - -/* - * Configure the IOMD to give the appropriate timings for the transfer - * mode being requested. We take the advice of the ATA standards, and - * calculate the cycle time based on the transfer mode, and the EIDE - * MW DMA specs that the drive provides in the IDENTIFY command. - * - * We have the following IOMD DMA modes to choose from: - * - * Type Active Recovery Cycle - * A 250 (250) 312 (550) 562 (800) - * B 187 250 437 - * C 125 (125) 125 (375) 250 (500) - * D 62 125 187 - * - * (figures in brackets are actual measured timings) - * - * However, we also need to take care of the read/write active and - * recovery timings: - * - * Read Write - * Mode Active -- Recovery -- Cycle IOMD type - * MW0 215 50 215 480 A - * MW1 80 50 50 150 C - * MW2 70 25 25 120 C - */ -static void icside_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - unsigned long cycle_time = 0; - int use_dma_info = 0; - const u8 xfer_mode = drive->dma_mode; - - switch (xfer_mode) { - case XFER_MW_DMA_2: - cycle_time = 250; - use_dma_info = 1; - break; - - case XFER_MW_DMA_1: - cycle_time = 250; - use_dma_info = 1; - break; - - case XFER_MW_DMA_0: - cycle_time = 480; - break; - - case XFER_SW_DMA_2: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - cycle_time = 480; - break; - } - - /* - * If we're going to be doing MW_DMA_1 or MW_DMA_2, we should - * take care to note the values in the ID... - */ - if (use_dma_info && drive->id[ATA_ID_EIDE_DMA_TIME] > cycle_time) - cycle_time = drive->id[ATA_ID_EIDE_DMA_TIME]; - - ide_set_drivedata(drive, (void *)cycle_time); - - printk(KERN_INFO "%s: %s selected (peak %luMB/s)\n", - drive->name, ide_xfer_verbose(xfer_mode), - 2000 / (cycle_time ? cycle_time : (unsigned long) -1)); -} - -static const struct ide_port_ops icside_v6_port_ops = { - .set_dma_mode = icside_set_dma_mode, - .maskproc = icside_maskproc, -}; - -static void icside_dma_host_set(ide_drive_t *drive, int on) -{ -} - -static int icside_dma_end(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct expansion_card *ec = ECARD_DEV(hwif->dev); - - disable_dma(ec->dma); - - return get_dma_residue(ec->dma) != 0; -} - -static void icside_dma_start(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct expansion_card *ec = ECARD_DEV(hwif->dev); - - /* We can not enable DMA on both channels simultaneously. */ - BUG_ON(dma_channel_active(ec->dma)); - enable_dma(ec->dma); -} - -static int icside_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) -{ - ide_hwif_t *hwif = drive->hwif; - struct expansion_card *ec = ECARD_DEV(hwif->dev); - struct icside_state *state = ecard_get_drvdata(ec); - unsigned int dma_mode; - - if (cmd->tf_flags & IDE_TFLAG_WRITE) - dma_mode = DMA_MODE_WRITE; - else - dma_mode = DMA_MODE_READ; - - /* - * We can not enable DMA on both channels. - */ - BUG_ON(dma_channel_active(ec->dma)); - - /* - * Ensure that we have the right interrupt routed. - */ - icside_maskproc(drive, 0); - - /* - * Route the DMA signals to the correct interface. - */ - writeb(state->sel | hwif->channel, state->ioc_base); - - /* - * Select the correct timing for this drive. - */ - set_dma_speed(ec->dma, (unsigned long)ide_get_drivedata(drive)); - - /* - * Tell the DMA engine about the SG table and - * data direction. - */ - set_dma_sg(ec->dma, hwif->sg_table, cmd->sg_nents); - set_dma_mode(ec->dma, dma_mode); - - return 0; -} - -static int icside_dma_test_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct expansion_card *ec = ECARD_DEV(hwif->dev); - struct icside_state *state = ecard_get_drvdata(ec); - - return readb(state->irq_port + - (hwif->channel ? - ICS_ARCIN_V6_INTRSTAT_2 : - ICS_ARCIN_V6_INTRSTAT_1)) & 1; -} - -static int icside_dma_init(ide_hwif_t *hwif, const struct ide_port_info *d) -{ - hwif->dmatable_cpu = NULL; - hwif->dmatable_dma = 0; - - return 0; -} - -static const struct ide_dma_ops icside_v6_dma_ops = { - .dma_host_set = icside_dma_host_set, - .dma_setup = icside_dma_setup, - .dma_start = icside_dma_start, - .dma_end = icside_dma_end, - .dma_test_irq = icside_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, -}; -#endif - -static int icside_dma_off_init(ide_hwif_t *hwif, const struct ide_port_info *d) -{ - return -EOPNOTSUPP; -} - -static void icside_setup_ports(struct ide_hw *hw, void __iomem *base, - struct cardinfo *info, struct expansion_card *ec) -{ - unsigned long port = (unsigned long)base + info->dataoffset; - - hw->io_ports.data_addr = port; - hw->io_ports.error_addr = port + (1 << info->stepping); - hw->io_ports.nsect_addr = port + (2 << info->stepping); - hw->io_ports.lbal_addr = port + (3 << info->stepping); - hw->io_ports.lbam_addr = port + (4 << info->stepping); - hw->io_ports.lbah_addr = port + (5 << info->stepping); - hw->io_ports.device_addr = port + (6 << info->stepping); - hw->io_ports.status_addr = port + (7 << info->stepping); - hw->io_ports.ctl_addr = (unsigned long)base + info->ctrloffset; - - hw->irq = ec->irq; - hw->dev = &ec->dev; -} - -static const struct ide_port_info icside_v5_port_info = { - .host_flags = IDE_HFLAG_NO_DMA, - .chipset = ide_acorn, -}; - -static int icside_register_v5(struct icside_state *state, - struct expansion_card *ec) -{ - void __iomem *base; - struct ide_host *host; - struct ide_hw hw, *hws[] = { &hw }; - int ret; - - base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0); - if (!base) - return -ENOMEM; - - state->irq_port = base; - - ec->irqaddr = base + ICS_ARCIN_V5_INTRSTAT; - ec->irqmask = 1; - - ecard_setirq(ec, &icside_ops_arcin_v5, state); - - /* - * Be on the safe side - disable interrupts - */ - icside_irqdisable_arcin_v5(ec, 0); - - icside_setup_ports(&hw, base, &icside_cardinfo_v5, ec); - - host = ide_host_alloc(&icside_v5_port_info, hws, 1); - if (host == NULL) - return -ENODEV; - - state->host = host; - - ecard_set_drvdata(ec, state); - - ret = ide_host_register(host, &icside_v5_port_info, hws); - if (ret) - goto err_free; - - return 0; -err_free: - ide_host_free(host); - ecard_set_drvdata(ec, NULL); - return ret; -} - -static const struct ide_port_info icside_v6_port_info = { - .init_dma = icside_dma_off_init, - .port_ops = &icside_v6_no_dma_port_ops, - .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO, - .mwdma_mask = ATA_MWDMA2, - .swdma_mask = ATA_SWDMA2, - .chipset = ide_acorn, -}; - -static int icside_register_v6(struct icside_state *state, - struct expansion_card *ec) -{ - void __iomem *ioc_base, *easi_base; - struct ide_host *host; - unsigned int sel = 0; - int ret; - struct ide_hw hw[2], *hws[] = { &hw[0], &hw[1] }; - struct ide_port_info d = icside_v6_port_info; - - ioc_base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0); - if (!ioc_base) { - ret = -ENOMEM; - goto out; - } - - easi_base = ioc_base; - - if (ecard_resource_flags(ec, ECARD_RES_EASI)) { - easi_base = ecardm_iomap(ec, ECARD_RES_EASI, 0, 0); - if (!easi_base) { - ret = -ENOMEM; - goto out; - } - - /* - * Enable access to the EASI region. - */ - sel = 1 << 5; - } - - writeb(sel, ioc_base); - - ecard_setirq(ec, &icside_ops_arcin_v6, state); - - state->irq_port = easi_base; - state->ioc_base = ioc_base; - state->sel = sel; - - /* - * Be on the safe side - disable interrupts - */ - icside_irqdisable_arcin_v6(ec, 0); - - icside_setup_ports(&hw[0], easi_base, &icside_cardinfo_v6_1, ec); - icside_setup_ports(&hw[1], easi_base, &icside_cardinfo_v6_2, ec); - - host = ide_host_alloc(&d, hws, 2); - if (host == NULL) - return -ENODEV; - - state->host = host; - - ecard_set_drvdata(ec, state); - -#ifdef CONFIG_BLK_DEV_IDEDMA_ICS - if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) { - d.init_dma = icside_dma_init; - d.port_ops = &icside_v6_port_ops; - d.dma_ops = &icside_v6_dma_ops; - } -#endif - - ret = ide_host_register(host, &d, hws); - if (ret) - goto err_free; - - return 0; -err_free: - ide_host_free(host); - if (d.dma_ops) - free_dma(ec->dma); - ecard_set_drvdata(ec, NULL); -out: - return ret; -} - -static int icside_probe(struct expansion_card *ec, const struct ecard_id *id) -{ - struct icside_state *state; - void __iomem *idmem; - int ret; - - ret = ecard_request_resources(ec); - if (ret) - goto out; - - state = kzalloc(sizeof(struct icside_state), GFP_KERNEL); - if (!state) { - ret = -ENOMEM; - goto release; - } - - state->type = ICS_TYPE_NOTYPE; - - idmem = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0); - if (idmem) { - unsigned int type; - - type = readb(idmem + ICS_IDENT_OFFSET) & 1; - type |= (readb(idmem + ICS_IDENT_OFFSET + 4) & 1) << 1; - type |= (readb(idmem + ICS_IDENT_OFFSET + 8) & 1) << 2; - type |= (readb(idmem + ICS_IDENT_OFFSET + 12) & 1) << 3; - ecardm_iounmap(ec, idmem); - - state->type = type; - } - - switch (state->type) { - case ICS_TYPE_A3IN: - dev_warn(&ec->dev, "A3IN unsupported\n"); - ret = -ENODEV; - break; - - case ICS_TYPE_A3USER: - dev_warn(&ec->dev, "A3USER unsupported\n"); - ret = -ENODEV; - break; - - case ICS_TYPE_V5: - ret = icside_register_v5(state, ec); - break; - - case ICS_TYPE_V6: - ret = icside_register_v6(state, ec); - break; - - default: - dev_warn(&ec->dev, "unknown interface type\n"); - ret = -ENODEV; - break; - } - - if (ret == 0) - goto out; - - kfree(state); - release: - ecard_release_resources(ec); - out: - return ret; -} - -static void icside_remove(struct expansion_card *ec) -{ - struct icside_state *state = ecard_get_drvdata(ec); - - switch (state->type) { - case ICS_TYPE_V5: - /* FIXME: tell IDE to stop using the interface */ - - /* Disable interrupts */ - icside_irqdisable_arcin_v5(ec, 0); - break; - - case ICS_TYPE_V6: - /* FIXME: tell IDE to stop using the interface */ - if (ec->dma != NO_DMA) - free_dma(ec->dma); - - /* Disable interrupts */ - icside_irqdisable_arcin_v6(ec, 0); - - /* Reset the ROM pointer/EASI selection */ - writeb(0, state->ioc_base); - break; - } - - ecard_set_drvdata(ec, NULL); - - kfree(state); - ecard_release_resources(ec); -} - -static void icside_shutdown(struct expansion_card *ec) -{ - struct icside_state *state = ecard_get_drvdata(ec); - unsigned long flags; - - /* - * Disable interrupts from this card. We need to do - * this before disabling EASI since we may be accessing - * this register via that region. - */ - local_irq_save(flags); - ec->ops->irqdisable(ec, 0); - local_irq_restore(flags); - - /* - * Reset the ROM pointer so that we can read the ROM - * after a soft reboot. This also disables access to - * the IDE taskfile via the EASI region. - */ - if (state->ioc_base) - writeb(0, state->ioc_base); -} - -static const struct ecard_id icside_ids[] = { - { MANU_ICS, PROD_ICS_IDE }, - { MANU_ICS2, PROD_ICS2_IDE }, - { 0xffff, 0xffff } -}; - -static struct ecard_driver icside_driver = { - .probe = icside_probe, - .remove = icside_remove, - .shutdown = icside_shutdown, - .id_table = icside_ids, - .drv = { - .name = "icside", - }, -}; - -static int __init icside_init(void) -{ - return ecard_register_driver(&icside_driver); -} - -static void __exit icside_exit(void) -{ - ecard_remove_driver(&icside_driver); -} - -MODULE_AUTHOR("Russell King "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("ICS IDE driver"); - -module_init(icside_init); -module_exit(icside_exit); diff --git a/drivers/ide/ide-4drives.c b/drivers/ide/ide-4drives.c deleted file mode 100644 index 06c6215e0cbe..000000000000 --- a/drivers/ide/ide-4drives.c +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -#include -#include -#include -#include - -#define DRV_NAME "ide-4drives" - -static bool probe_4drives; - -module_param_named(probe, probe_4drives, bool, 0); -MODULE_PARM_DESC(probe, "probe for generic IDE chipset with 4 drives/port"); - -static void ide_4drives_init_dev(ide_drive_t *drive) -{ - if (drive->hwif->channel) - drive->select ^= 0x20; -} - -static const struct ide_port_ops ide_4drives_port_ops = { - .init_dev = ide_4drives_init_dev, -}; - -static const struct ide_port_info ide_4drives_port_info = { - .port_ops = &ide_4drives_port_ops, - .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_DMA | - IDE_HFLAG_4DRIVES, - .chipset = ide_4drives, -}; - -static int __init ide_4drives_init(void) -{ - unsigned long base = 0x1f0, ctl = 0x3f6; - struct ide_hw hw, *hws[] = { &hw, &hw }; - - if (probe_4drives == 0) - return -ENODEV; - - if (!request_region(base, 8, DRV_NAME)) { - printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n", - DRV_NAME, base, base + 7); - return -EBUSY; - } - - if (!request_region(ctl, 1, DRV_NAME)) { - printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n", - DRV_NAME, ctl); - release_region(base, 8); - return -EBUSY; - } - - memset(&hw, 0, sizeof(hw)); - - ide_std_init_ports(&hw, base, ctl); - hw.irq = 14; - - return ide_host_add(&ide_4drives_port_info, hws, 2, NULL); -} - -module_init(ide_4drives_init); - -MODULE_AUTHOR("Bartlomiej Zolnierkiewicz"); -MODULE_DESCRIPTION("generic IDE chipset with 4 drives/port support"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c deleted file mode 100644 index 05e18d658141..000000000000 --- a/drivers/ide/ide-acpi.c +++ /dev/null @@ -1,622 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Provides ACPI support for IDE drives. - * - * Copyright (C) 2005 Intel Corp. - * Copyright (C) 2005 Randy Dunlap - * Copyright (C) 2006 SUSE Linux Products GmbH - * Copyright (C) 2006 Hannes Reinecke - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define REGS_PER_GTF 7 - -struct GTM_buffer { - u32 PIO_speed0; - u32 DMA_speed0; - u32 PIO_speed1; - u32 DMA_speed1; - u32 GTM_flags; -}; - -struct ide_acpi_drive_link { - acpi_handle obj_handle; - u8 idbuff[512]; -}; - -struct ide_acpi_hwif_link { - ide_hwif_t *hwif; - acpi_handle obj_handle; - struct GTM_buffer gtm; - struct ide_acpi_drive_link master; - struct ide_acpi_drive_link slave; -}; - -#undef DEBUGGING -/* note: adds function name and KERN_DEBUG */ -#ifdef DEBUGGING -#define DEBPRINT(fmt, args...) \ - printk(KERN_DEBUG "%s: " fmt, __func__, ## args) -#else -#define DEBPRINT(fmt, args...) do {} while (0) -#endif /* DEBUGGING */ - -static bool ide_noacpi; -module_param_named(noacpi, ide_noacpi, bool, 0); -MODULE_PARM_DESC(noacpi, "disable IDE ACPI support"); - -static bool ide_acpigtf; -module_param_named(acpigtf, ide_acpigtf, bool, 0); -MODULE_PARM_DESC(acpigtf, "enable IDE ACPI _GTF support"); - -static bool ide_acpionboot; -module_param_named(acpionboot, ide_acpionboot, bool, 0); -MODULE_PARM_DESC(acpionboot, "call IDE ACPI methods on boot"); - -static bool ide_noacpi_psx; -static int no_acpi_psx(const struct dmi_system_id *id) -{ - ide_noacpi_psx = true; - printk(KERN_NOTICE"%s detected - disable ACPI _PSx.\n", id->ident); - return 0; -} - -static const struct dmi_system_id ide_acpi_dmi_table[] = { - /* Bug 9673. */ - /* We should check if this is because ACPI NVS isn't save/restored. */ - { - .callback = no_acpi_psx, - .ident = "HP nx9005", - .matches = { - DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies Ltd."), - DMI_MATCH(DMI_BIOS_VERSION, "KAM1.60") - }, - }, - - { } /* terminate list */ -}; - -int ide_acpi_init(void) -{ - dmi_check_system(ide_acpi_dmi_table); - return 0; -} - -bool ide_port_acpi(ide_hwif_t *hwif) -{ - return ide_noacpi == 0 && hwif->acpidata; -} - -static acpi_handle acpi_get_child(acpi_handle handle, u64 addr) -{ - struct acpi_device *adev; - - if (!handle || acpi_bus_get_device(handle, &adev)) - return NULL; - - adev = acpi_find_child_device(adev, addr, false); - return adev ? adev->handle : NULL; -} - -/** - * ide_get_dev_handle - finds acpi_handle and PCI device.function - * @dev: device to locate - * @handle: returned acpi_handle for @dev - * @pcidevfn: return PCI device.func for @dev - * - * Returns the ACPI object handle to the corresponding PCI device. - * - * Returns 0 on success, <0 on error. - */ -static int ide_get_dev_handle(struct device *dev, acpi_handle *handle, - u64 *pcidevfn) -{ - struct pci_dev *pdev = to_pci_dev(dev); - unsigned int bus, devnum, func; - u64 addr; - acpi_handle dev_handle; - acpi_status status; - struct acpi_device_info *dinfo = NULL; - int ret = -ENODEV; - - bus = pdev->bus->number; - devnum = PCI_SLOT(pdev->devfn); - func = PCI_FUNC(pdev->devfn); - /* ACPI _ADR encoding for PCI bus: */ - addr = (u64)(devnum << 16 | func); - - DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func); - - dev_handle = ACPI_HANDLE(dev); - if (!dev_handle) { - DEBPRINT("no acpi handle for device\n"); - goto err; - } - - status = acpi_get_object_info(dev_handle, &dinfo); - if (ACPI_FAILURE(status)) { - DEBPRINT("get_object_info for device failed\n"); - goto err; - } - if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && - dinfo->address == addr) { - *pcidevfn = addr; - *handle = dev_handle; - } else { - DEBPRINT("get_object_info for device has wrong " - " address: %llu, should be %u\n", - dinfo ? (unsigned long long)dinfo->address : -1ULL, - (unsigned int)addr); - goto err; - } - - DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n", - devnum, func, (unsigned long long)addr, *handle); - ret = 0; -err: - kfree(dinfo); - return ret; -} - -/** - * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif - * @hwif: device to locate - * - * Retrieves the object handle for a given hwif. - * - * Returns handle on success, 0 on error. - */ -static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif) -{ - struct device *dev = hwif->gendev.parent; - acpi_handle dev_handle; - u64 pcidevfn; - acpi_handle chan_handle; - int err; - - DEBPRINT("ENTER: device %s\n", hwif->name); - - if (!dev) { - DEBPRINT("no PCI device for %s\n", hwif->name); - return NULL; - } - - err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn); - if (err < 0) { - DEBPRINT("ide_get_dev_handle failed (%d)\n", err); - return NULL; - } - - /* get child objects of dev_handle == channel objects, - * + _their_ children == drive objects */ - /* channel is hwif->channel */ - chan_handle = acpi_get_child(dev_handle, hwif->channel); - DEBPRINT("chan adr=%d: handle=0x%p\n", - hwif->channel, chan_handle); - - return chan_handle; -} - -/** - * do_drive_get_GTF - get the drive bootup default taskfile settings - * @drive: the drive for which the taskfile settings should be retrieved - * @gtf_length: number of bytes of _GTF data returned at @gtf_address - * @gtf_address: buffer containing _GTF taskfile arrays - * - * The _GTF method has no input parameters. - * It returns a variable number of register set values (registers - * hex 1F1..1F7, taskfiles). - * The is not known in advance, so have ACPI-CA - * allocate the buffer as needed and return it, then free it later. - * - * The returned @gtf_length and @gtf_address are only valid if the - * function return value is 0. - */ -static int do_drive_get_GTF(ide_drive_t *drive, - unsigned int *gtf_length, unsigned long *gtf_address, - unsigned long *obj_loc) -{ - acpi_status status; - struct acpi_buffer output; - union acpi_object *out_obj; - int err = -ENODEV; - - *gtf_length = 0; - *gtf_address = 0UL; - *obj_loc = 0UL; - - if (!drive->acpidata->obj_handle) { - DEBPRINT("No ACPI object found for %s\n", drive->name); - goto out; - } - - /* Setting up output buffer */ - output.length = ACPI_ALLOCATE_BUFFER; - output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ - - /* _GTF has no input parameters */ - err = -EIO; - status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF", - NULL, &output); - if (ACPI_FAILURE(status)) { - printk(KERN_DEBUG - "%s: Run _GTF error: status = 0x%x\n", - __func__, status); - goto out; - } - - if (!output.length || !output.pointer) { - DEBPRINT("Run _GTF: " - "length or ptr is NULL (0x%llx, 0x%p)\n", - (unsigned long long)output.length, - output.pointer); - goto out; - } - - out_obj = output.pointer; - if (out_obj->type != ACPI_TYPE_BUFFER) { - DEBPRINT("Run _GTF: error: " - "expected object type of ACPI_TYPE_BUFFER, " - "got 0x%x\n", out_obj->type); - err = -ENOENT; - kfree(output.pointer); - goto out; - } - - if (!out_obj->buffer.length || !out_obj->buffer.pointer || - out_obj->buffer.length % REGS_PER_GTF) { - printk(KERN_ERR - "%s: unexpected GTF length (%d) or addr (0x%p)\n", - __func__, out_obj->buffer.length, - out_obj->buffer.pointer); - err = -ENOENT; - kfree(output.pointer); - goto out; - } - - *gtf_length = out_obj->buffer.length; - *gtf_address = (unsigned long)out_obj->buffer.pointer; - *obj_loc = (unsigned long)out_obj; - DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n", - *gtf_length, *gtf_address, *obj_loc); - err = 0; -out: - return err; -} - -/** - * do_drive_set_taskfiles - write the drive taskfile settings from _GTF - * @drive: the drive to which the taskfile command should be sent - * @gtf_length: total number of bytes of _GTF taskfiles - * @gtf_address: location of _GTF taskfile arrays - * - * Write {gtf_address, length gtf_length} in groups of - * REGS_PER_GTF bytes. - */ -static int do_drive_set_taskfiles(ide_drive_t *drive, - unsigned int gtf_length, - unsigned long gtf_address) -{ - int rc = 0, err; - int gtf_count = gtf_length / REGS_PER_GTF; - int ix; - - DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n", - gtf_length, gtf_length, gtf_count, gtf_address); - - /* send all taskfile registers (0x1f1-0x1f7) *in*that*order* */ - for (ix = 0; ix < gtf_count; ix++) { - u8 *gtf = (u8 *)(gtf_address + ix * REGS_PER_GTF); - struct ide_cmd cmd; - - DEBPRINT("(0x1f1-1f7): " - "hex: %02x %02x %02x %02x %02x %02x %02x\n", - gtf[0], gtf[1], gtf[2], - gtf[3], gtf[4], gtf[5], gtf[6]); - - if (!ide_acpigtf) { - DEBPRINT("_GTF execution disabled\n"); - continue; - } - - /* convert GTF to taskfile */ - memset(&cmd, 0, sizeof(cmd)); - memcpy(&cmd.tf.feature, gtf, REGS_PER_GTF); - cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - - err = ide_no_data_taskfile(drive, &cmd); - if (err) { - printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n", - __func__, err); - rc = err; - } - } - - return rc; -} - -/** - * ide_acpi_exec_tfs - get then write drive taskfile settings - * @drive: the drive for which the taskfile settings should be - * written. - * - * According to the ACPI spec this should be called after _STM - * has been evaluated for the interface. Some ACPI vendors interpret - * that as a hard requirement and modify the taskfile according - * to the Identify Drive information passed down with _STM. - * So one should really make sure to call this only after _STM has - * been executed. - */ -int ide_acpi_exec_tfs(ide_drive_t *drive) -{ - int ret; - unsigned int gtf_length; - unsigned long gtf_address; - unsigned long obj_loc; - - DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn); - - ret = do_drive_get_GTF(drive, >f_length, >f_address, &obj_loc); - if (ret < 0) { - DEBPRINT("get_GTF error (%d)\n", ret); - return ret; - } - - DEBPRINT("call set_taskfiles, drive=%s\n", drive->name); - - ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address); - kfree((void *)obj_loc); - if (ret < 0) { - DEBPRINT("set_taskfiles error (%d)\n", ret); - } - - DEBPRINT("ret=%d\n", ret); - - return ret; -} - -/** - * ide_acpi_get_timing - get the channel (controller) timings - * @hwif: target IDE interface (channel) - * - * This function executes the _GTM ACPI method for the target channel. - * - */ -void ide_acpi_get_timing(ide_hwif_t *hwif) -{ - acpi_status status; - struct acpi_buffer output; - union acpi_object *out_obj; - - /* Setting up output buffer for _GTM */ - output.length = ACPI_ALLOCATE_BUFFER; - output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ - - /* _GTM has no input parameters */ - status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM", - NULL, &output); - - DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n", - status, output.pointer, - (unsigned long long)output.length); - - if (ACPI_FAILURE(status)) { - DEBPRINT("Run _GTM error: status = 0x%x\n", status); - return; - } - - if (!output.length || !output.pointer) { - DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n", - (unsigned long long)output.length, - output.pointer); - kfree(output.pointer); - return; - } - - out_obj = output.pointer; - if (out_obj->type != ACPI_TYPE_BUFFER) { - DEBPRINT("Run _GTM: error: " - "expected object type of ACPI_TYPE_BUFFER, " - "got 0x%x\n", out_obj->type); - kfree(output.pointer); - return; - } - - if (!out_obj->buffer.length || !out_obj->buffer.pointer || - out_obj->buffer.length != sizeof(struct GTM_buffer)) { - printk(KERN_ERR - "%s: unexpected _GTM length (0x%x)[should be 0x%zx] or " - "addr (0x%p)\n", - __func__, out_obj->buffer.length, - sizeof(struct GTM_buffer), out_obj->buffer.pointer); - kfree(output.pointer); - return; - } - - memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer, - sizeof(struct GTM_buffer)); - - DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%zx\n", - out_obj->buffer.pointer, out_obj->buffer.length, - sizeof(struct GTM_buffer)); - - DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", - hwif->acpidata->gtm.PIO_speed0, - hwif->acpidata->gtm.DMA_speed0, - hwif->acpidata->gtm.PIO_speed1, - hwif->acpidata->gtm.DMA_speed1, - hwif->acpidata->gtm.GTM_flags); - - kfree(output.pointer); -} - -/** - * ide_acpi_push_timing - set the channel (controller) timings - * @hwif: target IDE interface (channel) - * - * This function executes the _STM ACPI method for the target channel. - * - * _STM requires Identify Drive data, which has to passed as an argument. - * Unfortunately drive->id is a mangled version which we can't readily - * use; hence we'll get the information afresh. - */ -void ide_acpi_push_timing(ide_hwif_t *hwif) -{ - acpi_status status; - struct acpi_object_list input; - union acpi_object in_params[3]; - struct ide_acpi_drive_link *master = &hwif->acpidata->master; - struct ide_acpi_drive_link *slave = &hwif->acpidata->slave; - - /* Give the GTM buffer + drive Identify data to the channel via the - * _STM method: */ - /* setup input parameters buffer for _STM */ - input.count = 3; - input.pointer = in_params; - in_params[0].type = ACPI_TYPE_BUFFER; - in_params[0].buffer.length = sizeof(struct GTM_buffer); - in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm; - in_params[1].type = ACPI_TYPE_BUFFER; - in_params[1].buffer.length = ATA_ID_WORDS * 2; - in_params[1].buffer.pointer = (u8 *)&master->idbuff; - in_params[2].type = ACPI_TYPE_BUFFER; - in_params[2].buffer.length = ATA_ID_WORDS * 2; - in_params[2].buffer.pointer = (u8 *)&slave->idbuff; - /* Output buffer: _STM has no output */ - - status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM", - &input, NULL); - - if (ACPI_FAILURE(status)) { - DEBPRINT("Run _STM error: status = 0x%x\n", status); - } - DEBPRINT("_STM status: %d\n", status); -} - -/** - * ide_acpi_set_state - set the channel power state - * @hwif: target IDE interface - * @on: state, on/off - * - * This function executes the _PS0/_PS3 ACPI method to set the power state. - * ACPI spec requires _PS0 when IDE power on and _PS3 when power off - */ -void ide_acpi_set_state(ide_hwif_t *hwif, int on) -{ - ide_drive_t *drive; - int i; - - if (ide_noacpi_psx) - return; - - DEBPRINT("ENTER:\n"); - - /* channel first and then drives for power on and verse versa for power off */ - if (on) - acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0); - - ide_port_for_each_present_dev(i, drive, hwif) { - if (drive->acpidata->obj_handle) - acpi_bus_set_power(drive->acpidata->obj_handle, - on ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD); - } - - if (!on) - acpi_bus_set_power(hwif->acpidata->obj_handle, - ACPI_STATE_D3_COLD); -} - -/** - * ide_acpi_init_port - initialize the ACPI link for an IDE interface - * @hwif: target IDE interface (channel) - * - * The ACPI spec is not quite clear when the drive identify buffer - * should be obtained. Calling IDENTIFY DEVICE during shutdown - * is not the best of ideas as the drive might already being put to - * sleep. And obviously we can't call it during resume. - * So we get the information during startup; but this means that - * any changes during run-time will be lost after resume. - */ -void ide_acpi_init_port(ide_hwif_t *hwif) -{ - hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL); - if (!hwif->acpidata) - return; - - hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif); - if (!hwif->acpidata->obj_handle) { - DEBPRINT("no ACPI object for %s found\n", hwif->name); - kfree(hwif->acpidata); - hwif->acpidata = NULL; - } -} - -void ide_acpi_port_init_devices(ide_hwif_t *hwif) -{ - ide_drive_t *drive; - int i, err; - - if (hwif->acpidata == NULL) - return; - - /* - * The ACPI spec mandates that we send information - * for both drives, regardless whether they are connected - * or not. - */ - hwif->devices[0]->acpidata = &hwif->acpidata->master; - hwif->devices[1]->acpidata = &hwif->acpidata->slave; - - /* get _ADR info for each device */ - ide_port_for_each_present_dev(i, drive, hwif) { - acpi_handle dev_handle; - - DEBPRINT("ENTER: %s at channel#: %d port#: %d\n", - drive->name, hwif->channel, drive->dn & 1); - - /* TBD: could also check ACPI object VALID bits */ - dev_handle = acpi_get_child(hwif->acpidata->obj_handle, - drive->dn & 1); - - DEBPRINT("drive %s handle 0x%p\n", drive->name, dev_handle); - - drive->acpidata->obj_handle = dev_handle; - } - - /* send IDENTIFY for each device */ - ide_port_for_each_present_dev(i, drive, hwif) { - err = taskfile_lib_get_identify(drive, drive->acpidata->idbuff); - if (err) - DEBPRINT("identify device %s failed (%d)\n", - drive->name, err); - } - - if (ide_noacpi || ide_acpionboot == 0) { - DEBPRINT("ACPI methods disabled on boot\n"); - return; - } - - /* ACPI _PS0 before _STM */ - ide_acpi_set_state(hwif, 1); - /* - * ACPI requires us to call _STM on startup - */ - ide_acpi_get_timing(hwif); - ide_acpi_push_timing(hwif); - - ide_port_for_each_present_dev(i, drive, hwif) { - ide_acpi_exec_tfs(drive); - } -} diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c deleted file mode 100644 index a1ce9f5ac3aa..000000000000 --- a/drivers/ide/ide-atapi.c +++ /dev/null @@ -1,756 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * ATAPI support. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "ide-atapi" -#define PFX DRV_NAME ": " - -#ifdef DEBUG -#define debug_log(fmt, args...) \ - printk(KERN_INFO "ide: " fmt, ## args) -#else -#define debug_log(fmt, args...) do {} while (0) -#endif - -#define ATAPI_MIN_CDB_BYTES 12 - -static inline int dev_is_idecd(ide_drive_t *drive) -{ - return drive->media == ide_cdrom || drive->media == ide_optical; -} - -/* - * Check whether we can support a device, - * based on the ATAPI IDENTIFY command results. - */ -int ide_check_atapi_device(ide_drive_t *drive, const char *s) -{ - u16 *id = drive->id; - u8 gcw[2], protocol, device_type, removable, drq_type, packet_size; - - *((u16 *)&gcw) = id[ATA_ID_CONFIG]; - - protocol = (gcw[1] & 0xC0) >> 6; - device_type = gcw[1] & 0x1F; - removable = (gcw[0] & 0x80) >> 7; - drq_type = (gcw[0] & 0x60) >> 5; - packet_size = gcw[0] & 0x03; - -#ifdef CONFIG_PPC - /* kludge for Apple PowerBook internal zip */ - if (drive->media == ide_floppy && device_type == 5 && - !strstr((char *)&id[ATA_ID_PROD], "CD-ROM") && - strstr((char *)&id[ATA_ID_PROD], "ZIP")) - device_type = 0; -#endif - - if (protocol != 2) - printk(KERN_ERR "%s: %s: protocol (0x%02x) is not ATAPI\n", - s, drive->name, protocol); - else if ((drive->media == ide_floppy && device_type != 0) || - (drive->media == ide_tape && device_type != 1)) - printk(KERN_ERR "%s: %s: invalid device type (0x%02x)\n", - s, drive->name, device_type); - else if (removable == 0) - printk(KERN_ERR "%s: %s: the removable flag is not set\n", - s, drive->name); - else if (drive->media == ide_floppy && drq_type == 3) - printk(KERN_ERR "%s: %s: sorry, DRQ type (0x%02x) not " - "supported\n", s, drive->name, drq_type); - else if (packet_size != 0) - printk(KERN_ERR "%s: %s: packet size (0x%02x) is not 12 " - "bytes\n", s, drive->name, packet_size); - else - return 1; - return 0; -} -EXPORT_SYMBOL_GPL(ide_check_atapi_device); - -void ide_init_pc(struct ide_atapi_pc *pc) -{ - memset(pc, 0, sizeof(*pc)); -} -EXPORT_SYMBOL_GPL(ide_init_pc); - -/* - * Add a special packet command request to the tail of the request queue, - * and wait for it to be serviced. - */ -int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk, - struct ide_atapi_pc *pc, void *buf, unsigned int bufflen) -{ - struct request *rq; - int error; - - rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); - ide_req(rq)->type = ATA_PRIV_MISC; - ide_req(rq)->special = pc; - - if (buf && bufflen) { - error = blk_rq_map_kern(drive->queue, rq, buf, bufflen, - GFP_NOIO); - if (error) - goto put_req; - } - - memcpy(scsi_req(rq)->cmd, pc->c, 12); - if (drive->media == ide_tape) - scsi_req(rq)->cmd[13] = REQ_IDETAPE_PC1; - blk_execute_rq(disk, rq, 0); - error = scsi_req(rq)->result ? -EIO : 0; -put_req: - blk_put_request(rq); - return error; -} -EXPORT_SYMBOL_GPL(ide_queue_pc_tail); - -int ide_do_test_unit_ready(ide_drive_t *drive, struct gendisk *disk) -{ - struct ide_atapi_pc pc; - - ide_init_pc(&pc); - pc.c[0] = TEST_UNIT_READY; - - return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); -} -EXPORT_SYMBOL_GPL(ide_do_test_unit_ready); - -int ide_do_start_stop(ide_drive_t *drive, struct gendisk *disk, int start) -{ - struct ide_atapi_pc pc; - - ide_init_pc(&pc); - pc.c[0] = START_STOP; - pc.c[4] = start; - - if (drive->media == ide_tape) - pc.flags |= PC_FLAG_WAIT_FOR_DSC; - - return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); -} -EXPORT_SYMBOL_GPL(ide_do_start_stop); - -int ide_set_media_lock(ide_drive_t *drive, struct gendisk *disk, int on) -{ - struct ide_atapi_pc pc; - - if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0) - return 0; - - ide_init_pc(&pc); - pc.c[0] = ALLOW_MEDIUM_REMOVAL; - pc.c[4] = on; - - return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); -} -EXPORT_SYMBOL_GPL(ide_set_media_lock); - -void ide_create_request_sense_cmd(ide_drive_t *drive, struct ide_atapi_pc *pc) -{ - ide_init_pc(pc); - pc->c[0] = REQUEST_SENSE; - if (drive->media == ide_floppy) { - pc->c[4] = 255; - pc->req_xfer = 18; - } else { - pc->c[4] = 20; - pc->req_xfer = 20; - } -} -EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd); - -void ide_prep_sense(ide_drive_t *drive, struct request *rq) -{ - struct request_sense *sense = &drive->sense_data; - struct request *sense_rq; - struct scsi_request *req; - unsigned int cmd_len, sense_len; - int err; - - switch (drive->media) { - case ide_floppy: - cmd_len = 255; - sense_len = 18; - break; - case ide_tape: - cmd_len = 20; - sense_len = 20; - break; - default: - cmd_len = 18; - sense_len = 18; - } - - BUG_ON(sense_len > sizeof(*sense)); - - if (ata_sense_request(rq) || drive->sense_rq_armed) - return; - - sense_rq = drive->sense_rq; - if (!sense_rq) { - sense_rq = blk_mq_alloc_request(drive->queue, REQ_OP_DRV_IN, - BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT); - drive->sense_rq = sense_rq; - } - req = scsi_req(sense_rq); - - memset(sense, 0, sizeof(*sense)); - - scsi_req_init(req); - - err = blk_rq_map_kern(drive->queue, sense_rq, sense, sense_len, - GFP_NOIO); - if (unlikely(err)) { - if (printk_ratelimit()) - printk(KERN_WARNING PFX "%s: failed to map sense " - "buffer\n", drive->name); - blk_mq_free_request(sense_rq); - drive->sense_rq = NULL; - return; - } - - sense_rq->rq_disk = rq->rq_disk; - sense_rq->cmd_flags = REQ_OP_DRV_IN; - ide_req(sense_rq)->type = ATA_PRIV_SENSE; - - req->cmd[0] = GPCMD_REQUEST_SENSE; - req->cmd[4] = cmd_len; - if (drive->media == ide_tape) - req->cmd[13] = REQ_IDETAPE_PC1; - - drive->sense_rq_armed = true; -} -EXPORT_SYMBOL_GPL(ide_prep_sense); - -int ide_queue_sense_rq(ide_drive_t *drive, void *special) -{ - ide_hwif_t *hwif = drive->hwif; - struct request *sense_rq; - unsigned long flags; - - spin_lock_irqsave(&hwif->lock, flags); - - /* deferred failure from ide_prep_sense() */ - if (!drive->sense_rq_armed) { - printk(KERN_WARNING PFX "%s: error queuing a sense request\n", - drive->name); - spin_unlock_irqrestore(&hwif->lock, flags); - return -ENOMEM; - } - - sense_rq = drive->sense_rq; - ide_req(sense_rq)->special = special; - drive->sense_rq_armed = false; - - drive->hwif->rq = NULL; - - ide_insert_request_head(drive, sense_rq); - spin_unlock_irqrestore(&hwif->lock, flags); - return 0; -} -EXPORT_SYMBOL_GPL(ide_queue_sense_rq); - -/* - * Called when an error was detected during the last packet command. - * We queue a request sense packet command at the head of the request - * queue. - */ -void ide_retry_pc(ide_drive_t *drive) -{ - struct request *failed_rq = drive->hwif->rq; - struct request *sense_rq = drive->sense_rq; - struct ide_atapi_pc *pc = &drive->request_sense_pc; - - (void)ide_read_error(drive); - - /* init pc from sense_rq */ - ide_init_pc(pc); - memcpy(pc->c, scsi_req(sense_rq)->cmd, 12); - - if (drive->media == ide_tape) - drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC; - - /* - * Push back the failed request and put request sense on top - * of it. The failed command will be retried after sense data - * is acquired. - */ - drive->hwif->rq = NULL; - ide_requeue_and_plug(drive, failed_rq); - if (ide_queue_sense_rq(drive, pc)) - ide_complete_rq(drive, BLK_STS_IOERR, blk_rq_bytes(failed_rq)); -} -EXPORT_SYMBOL_GPL(ide_retry_pc); - -int ide_cd_expiry(ide_drive_t *drive) -{ - struct request *rq = drive->hwif->rq; - unsigned long wait = 0; - - debug_log("%s: scsi_req(rq)->cmd[0]: 0x%x\n", __func__, scsi_req(rq)->cmd[0]); - - /* - * Some commands are *slow* and normally take a long time to complete. - * Usually we can use the ATAPI "disconnect" to bypass this, but not all - * commands/drives support that. Let ide_timer_expiry keep polling us - * for these. - */ - switch (scsi_req(rq)->cmd[0]) { - case GPCMD_BLANK: - case GPCMD_FORMAT_UNIT: - case GPCMD_RESERVE_RZONE_TRACK: - case GPCMD_CLOSE_TRACK: - case GPCMD_FLUSH_CACHE: - wait = ATAPI_WAIT_PC; - break; - default: - if (!(rq->rq_flags & RQF_QUIET)) - printk(KERN_INFO PFX "cmd 0x%x timed out\n", - scsi_req(rq)->cmd[0]); - wait = 0; - break; - } - return wait; -} -EXPORT_SYMBOL_GPL(ide_cd_expiry); - -int ide_cd_get_xferlen(struct request *rq) -{ - switch (req_op(rq)) { - default: - return 32768; - case REQ_OP_SCSI_IN: - case REQ_OP_SCSI_OUT: - return blk_rq_bytes(rq); - case REQ_OP_DRV_IN: - case REQ_OP_DRV_OUT: - switch (ide_req(rq)->type) { - case ATA_PRIV_PC: - case ATA_PRIV_SENSE: - return blk_rq_bytes(rq); - default: - return 0; - } - } -} -EXPORT_SYMBOL_GPL(ide_cd_get_xferlen); - -void ide_read_bcount_and_ireason(ide_drive_t *drive, u16 *bcount, u8 *ireason) -{ - struct ide_taskfile tf; - - drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_NSECT | - IDE_VALID_LBAM | IDE_VALID_LBAH); - - *bcount = (tf.lbah << 8) | tf.lbam; - *ireason = tf.nsect & 3; -} -EXPORT_SYMBOL_GPL(ide_read_bcount_and_ireason); - -/* - * Check the contents of the interrupt reason register and attempt to recover if - * there are problems. - * - * Returns: - * - 0 if everything's ok - * - 1 if the request has to be terminated. - */ -int ide_check_ireason(ide_drive_t *drive, struct request *rq, int len, - int ireason, int rw) -{ - ide_hwif_t *hwif = drive->hwif; - - debug_log("ireason: 0x%x, rw: 0x%x\n", ireason, rw); - - if (ireason == (!rw << 1)) - return 0; - else if (ireason == (rw << 1)) { - printk(KERN_ERR PFX "%s: %s: wrong transfer direction!\n", - drive->name, __func__); - - if (dev_is_idecd(drive)) - ide_pad_transfer(drive, rw, len); - } else if (!rw && ireason == ATAPI_COD) { - if (dev_is_idecd(drive)) { - /* - * Some drives (ASUS) seem to tell us that status info - * is available. Just get it and ignore. - */ - (void)hwif->tp_ops->read_status(hwif); - return 0; - } - } else { - if (ireason & ATAPI_COD) - printk(KERN_ERR PFX "%s: CoD != 0 in %s\n", drive->name, - __func__); - - /* drive wants a command packet, or invalid ireason... */ - printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n", - drive->name, __func__, ireason); - } - - if (dev_is_idecd(drive) && ata_pc_request(rq)) - rq->rq_flags |= RQF_FAILED; - - return 1; -} -EXPORT_SYMBOL_GPL(ide_check_ireason); - -/* - * This is the usual interrupt handler which will be called during a packet - * command. We will transfer some of the data (as requested by the drive) - * and will re-point interrupt handler to us. - */ -static ide_startstop_t ide_pc_intr(ide_drive_t *drive) -{ - struct ide_atapi_pc *pc = drive->pc; - ide_hwif_t *hwif = drive->hwif; - struct ide_cmd *cmd = &hwif->cmd; - struct request *rq = hwif->rq; - const struct ide_tp_ops *tp_ops = hwif->tp_ops; - unsigned int timeout, done; - u16 bcount; - u8 stat, ireason, dsc = 0; - u8 write = !!(pc->flags & PC_FLAG_WRITING); - - debug_log("Enter %s - interrupt handler\n", __func__); - - timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD - : WAIT_TAPE_CMD; - - /* Clear the interrupt */ - stat = tp_ops->read_status(hwif); - - if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) { - int rc; - - drive->waiting_for_dma = 0; - rc = hwif->dma_ops->dma_end(drive); - ide_dma_unmap_sg(drive, cmd); - - if (rc || (drive->media == ide_tape && (stat & ATA_ERR))) { - if (drive->media == ide_floppy) - printk(KERN_ERR PFX "%s: DMA %s error\n", - drive->name, rq_data_dir(pc->rq) - ? "write" : "read"); - pc->flags |= PC_FLAG_DMA_ERROR; - } else - scsi_req(rq)->resid_len = 0; - debug_log("%s: DMA finished\n", drive->name); - } - - /* No more interrupts */ - if ((stat & ATA_DRQ) == 0) { - int uptodate; - blk_status_t error; - - debug_log("Packet command completed, %d bytes transferred\n", - blk_rq_bytes(rq)); - - pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS; - - local_irq_enable_in_hardirq(); - - if (drive->media == ide_tape && - (stat & ATA_ERR) && scsi_req(rq)->cmd[0] == REQUEST_SENSE) - stat &= ~ATA_ERR; - - if ((stat & ATA_ERR) || (pc->flags & PC_FLAG_DMA_ERROR)) { - /* Error detected */ - debug_log("%s: I/O error\n", drive->name); - - if (drive->media != ide_tape) - scsi_req(pc->rq)->result++; - - if (scsi_req(rq)->cmd[0] == REQUEST_SENSE) { - printk(KERN_ERR PFX "%s: I/O error in request " - "sense command\n", drive->name); - return ide_do_reset(drive); - } - - debug_log("[cmd %x]: check condition\n", scsi_req(rq)->cmd[0]); - - /* Retry operation */ - ide_retry_pc(drive); - - /* queued, but not started */ - return ide_stopped; - } - pc->error = 0; - - if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0) - dsc = 1; - - /* - * ->pc_callback() might change rq->data_len for - * residual count, cache total length. - */ - done = blk_rq_bytes(rq); - - /* Command finished - Call the callback function */ - uptodate = drive->pc_callback(drive, dsc); - - if (uptodate == 0) - drive->failed_pc = NULL; - - if (ata_misc_request(rq)) { - scsi_req(rq)->result = 0; - error = BLK_STS_OK; - } else { - - if (blk_rq_is_passthrough(rq) && uptodate <= 0) { - if (scsi_req(rq)->result == 0) - scsi_req(rq)->result = -EIO; - } - - error = uptodate ? BLK_STS_OK : BLK_STS_IOERR; - } - - ide_complete_rq(drive, error, blk_rq_bytes(rq)); - return ide_stopped; - } - - if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) { - pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS; - printk(KERN_ERR PFX "%s: The device wants to issue more " - "interrupts in DMA mode\n", drive->name); - ide_dma_off(drive); - return ide_do_reset(drive); - } - - /* Get the number of bytes to transfer on this interrupt. */ - ide_read_bcount_and_ireason(drive, &bcount, &ireason); - - if (ide_check_ireason(drive, rq, bcount, ireason, write)) - return ide_do_reset(drive); - - done = min_t(unsigned int, bcount, cmd->nleft); - ide_pio_bytes(drive, cmd, write, done); - - /* Update transferred byte count */ - scsi_req(rq)->resid_len -= done; - - bcount -= done; - - if (bcount) - ide_pad_transfer(drive, write, bcount); - - debug_log("[cmd %x] transferred %d bytes, padded %d bytes, resid: %u\n", - scsi_req(rq)->cmd[0], done, bcount, scsi_req(rq)->resid_len); - - /* And set the interrupt handler again */ - ide_set_handler(drive, ide_pc_intr, timeout); - return ide_started; -} - -static void ide_init_packet_cmd(struct ide_cmd *cmd, u8 valid_tf, - u16 bcount, u8 dma) -{ - cmd->protocol = dma ? ATAPI_PROT_DMA : ATAPI_PROT_PIO; - cmd->valid.out.tf = IDE_VALID_LBAH | IDE_VALID_LBAM | - IDE_VALID_FEATURE | valid_tf; - cmd->tf.command = ATA_CMD_PACKET; - cmd->tf.feature = dma; /* Use PIO/DMA */ - cmd->tf.lbam = bcount & 0xff; - cmd->tf.lbah = (bcount >> 8) & 0xff; -} - -static u8 ide_read_ireason(ide_drive_t *drive) -{ - struct ide_taskfile tf; - - drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_NSECT); - - return tf.nsect & 3; -} - -static u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason) -{ - int retries = 100; - - while (retries-- && ((ireason & ATAPI_COD) == 0 || - (ireason & ATAPI_IO))) { - printk(KERN_ERR PFX "%s: (IO,CoD != (0,1) while issuing " - "a packet command, retrying\n", drive->name); - udelay(100); - ireason = ide_read_ireason(drive); - if (retries == 0) { - printk(KERN_ERR PFX "%s: (IO,CoD != (0,1) while issuing" - " a packet command, ignoring\n", - drive->name); - ireason |= ATAPI_COD; - ireason &= ~ATAPI_IO; - } - } - - return ireason; -} - -static int ide_delayed_transfer_pc(ide_drive_t *drive) -{ - /* Send the actual packet */ - drive->hwif->tp_ops->output_data(drive, NULL, drive->pc->c, 12); - - /* Timeout for the packet command */ - return WAIT_FLOPPY_CMD; -} - -static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) -{ - struct ide_atapi_pc *pc; - ide_hwif_t *hwif = drive->hwif; - struct request *rq = hwif->rq; - ide_expiry_t *expiry; - unsigned int timeout; - int cmd_len; - ide_startstop_t startstop; - u8 ireason; - - if (ide_wait_stat(&startstop, drive, ATA_DRQ, ATA_BUSY, WAIT_READY)) { - printk(KERN_ERR PFX "%s: Strange, packet command initiated yet " - "DRQ isn't asserted\n", drive->name); - return startstop; - } - - if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) { - if (drive->dma) - drive->waiting_for_dma = 1; - } - - if (dev_is_idecd(drive)) { - /* ATAPI commands get padded out to 12 bytes minimum */ - cmd_len = COMMAND_SIZE(scsi_req(rq)->cmd[0]); - if (cmd_len < ATAPI_MIN_CDB_BYTES) - cmd_len = ATAPI_MIN_CDB_BYTES; - - timeout = rq->timeout; - expiry = ide_cd_expiry; - } else { - pc = drive->pc; - - cmd_len = ATAPI_MIN_CDB_BYTES; - - /* - * If necessary schedule the packet transfer to occur 'timeout' - * milliseconds later in ide_delayed_transfer_pc() after the - * device says it's ready for a packet. - */ - if (drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) { - timeout = drive->pc_delay; - expiry = &ide_delayed_transfer_pc; - } else { - timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD - : WAIT_TAPE_CMD; - expiry = NULL; - } - - ireason = ide_read_ireason(drive); - if (drive->media == ide_tape) - ireason = ide_wait_ireason(drive, ireason); - - if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) { - printk(KERN_ERR PFX "%s: (IO,CoD) != (0,1) while " - "issuing a packet command\n", drive->name); - - return ide_do_reset(drive); - } - } - - hwif->expiry = expiry; - - /* Set the interrupt routine */ - ide_set_handler(drive, - (dev_is_idecd(drive) ? drive->irq_handler - : ide_pc_intr), - timeout); - - /* Send the actual packet */ - if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0) - hwif->tp_ops->output_data(drive, NULL, scsi_req(rq)->cmd, cmd_len); - - /* Begin DMA, if necessary */ - if (dev_is_idecd(drive)) { - if (drive->dma) - hwif->dma_ops->dma_start(drive); - } else { - if (pc->flags & PC_FLAG_DMA_OK) { - pc->flags |= PC_FLAG_DMA_IN_PROGRESS; - hwif->dma_ops->dma_start(drive); - } - } - - return ide_started; -} - -ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) -{ - struct ide_atapi_pc *pc; - ide_hwif_t *hwif = drive->hwif; - ide_expiry_t *expiry = NULL; - struct request *rq = hwif->rq; - unsigned int timeout, bytes; - u16 bcount; - u8 valid_tf; - u8 drq_int = !!(drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT); - - if (dev_is_idecd(drive)) { - valid_tf = IDE_VALID_NSECT | IDE_VALID_LBAL; - bcount = ide_cd_get_xferlen(rq); - expiry = ide_cd_expiry; - timeout = ATAPI_WAIT_PC; - - if (drive->dma) - drive->dma = !ide_dma_prepare(drive, cmd); - } else { - pc = drive->pc; - - valid_tf = IDE_VALID_DEVICE; - bytes = blk_rq_bytes(rq); - bcount = ((drive->media == ide_tape) ? bytes - : min_t(unsigned int, - bytes, 63 * 1024)); - - /* We haven't transferred any data yet */ - scsi_req(rq)->resid_len = bcount; - - if (pc->flags & PC_FLAG_DMA_ERROR) { - pc->flags &= ~PC_FLAG_DMA_ERROR; - ide_dma_off(drive); - } - - if (pc->flags & PC_FLAG_DMA_OK) - drive->dma = !ide_dma_prepare(drive, cmd); - - if (!drive->dma) - pc->flags &= ~PC_FLAG_DMA_OK; - - timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD - : WAIT_TAPE_CMD; - } - - ide_init_packet_cmd(cmd, valid_tf, bcount, drive->dma); - - (void)do_rw_taskfile(drive, cmd); - - if (drq_int) { - if (drive->dma) - drive->waiting_for_dma = 0; - hwif->expiry = expiry; - } - - ide_execute_command(drive, cmd, ide_transfer_pc, timeout); - - return drq_int ? ide_started : ide_transfer_pc(drive); -} -EXPORT_SYMBOL_GPL(ide_issue_pc); diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c deleted file mode 100644 index cffbcc27a34c..000000000000 --- a/drivers/ide/ide-cd.c +++ /dev/null @@ -1,1858 +0,0 @@ -/* - * ATAPI CD-ROM driver. - * - * Copyright (C) 1994-1996 Scott Snyder - * Copyright (C) 1996-1998 Erik Andersen - * Copyright (C) 1998-2000 Jens Axboe - * Copyright (C) 2005, 2007-2009 Bartlomiej Zolnierkiewicz - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * See Documentation/cdrom/ide-cd.rst for usage information. - * - * Suggestions are welcome. Patches that work are more welcome though. ;-) - * - * Documentation: - * Mt. Fuji (SFF8090 version 4) and ATAPI (SFF-8020i rev 2.6) standards. - * - * For historical changelog please see: - * Documentation/ide/ChangeLog.ide-cd.1994-2004 - */ - -#define DRV_NAME "ide-cd" -#define PFX DRV_NAME ": " - -#define IDECD_VERSION "5.00" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* For SCSI -> ATAPI command conversion */ -#include - -#include -#include -#include -#include - -#include "ide-cd.h" - -static DEFINE_MUTEX(ide_cd_mutex); -static DEFINE_MUTEX(idecd_ref_mutex); - -static void ide_cd_release(struct device *); - -static struct cdrom_info *ide_cd_get(struct gendisk *disk) -{ - struct cdrom_info *cd = NULL; - - mutex_lock(&idecd_ref_mutex); - cd = ide_drv_g(disk, cdrom_info); - if (cd) { - if (ide_device_get(cd->drive)) - cd = NULL; - else - get_device(&cd->dev); - - } - mutex_unlock(&idecd_ref_mutex); - return cd; -} - -static void ide_cd_put(struct cdrom_info *cd) -{ - ide_drive_t *drive = cd->drive; - - mutex_lock(&idecd_ref_mutex); - put_device(&cd->dev); - ide_device_put(drive); - mutex_unlock(&idecd_ref_mutex); -} - -/* - * Generic packet command support and error handling routines. - */ - -/* Mark that we've seen a media change and invalidate our internal buffers. */ -static void cdrom_saw_media_change(ide_drive_t *drive) -{ - drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED; - drive->atapi_flags &= ~IDE_AFLAG_TOC_VALID; -} - -static int cdrom_log_sense(ide_drive_t *drive, struct request *rq) -{ - struct request_sense *sense = &drive->sense_data; - int log = 0; - - if (!sense || !rq || (rq->rq_flags & RQF_QUIET)) - return 0; - - ide_debug_log(IDE_DBG_SENSE, "sense_key: 0x%x", sense->sense_key); - - switch (sense->sense_key) { - case NO_SENSE: - case RECOVERED_ERROR: - break; - case NOT_READY: - /* - * don't care about tray state messages for e.g. capacity - * commands or in-progress or becoming ready - */ - if (sense->asc == 0x3a || sense->asc == 0x04) - break; - log = 1; - break; - case ILLEGAL_REQUEST: - /* - * don't log START_STOP unit with LoEj set, since we cannot - * reliably check if drive can auto-close - */ - if (scsi_req(rq)->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24) - break; - log = 1; - break; - case UNIT_ATTENTION: - /* - * Make good and sure we've seen this potential media change. - * Some drives (i.e. Creative) fail to present the correct sense - * key in the error register. - */ - cdrom_saw_media_change(drive); - break; - default: - log = 1; - break; - } - return log; -} - -static void cdrom_analyze_sense_data(ide_drive_t *drive, - struct request *failed_command) -{ - struct request_sense *sense = &drive->sense_data; - struct cdrom_info *info = drive->driver_data; - unsigned long sector; - unsigned long bio_sectors; - - ide_debug_log(IDE_DBG_SENSE, "error_code: 0x%x, sense_key: 0x%x", - sense->error_code, sense->sense_key); - - if (failed_command) - ide_debug_log(IDE_DBG_SENSE, "failed cmd: 0x%x", - failed_command->cmd[0]); - - if (!cdrom_log_sense(drive, failed_command)) - return; - - /* - * If a read toc is executed for a CD-R or CD-RW medium where the first - * toc has not been recorded yet, it will fail with 05/24/00 (which is a - * confusing error) - */ - if (failed_command && scsi_req(failed_command)->cmd[0] == GPCMD_READ_TOC_PMA_ATIP) - if (sense->sense_key == 0x05 && sense->asc == 0x24) - return; - - /* current error */ - if (sense->error_code == 0x70) { - switch (sense->sense_key) { - case MEDIUM_ERROR: - case VOLUME_OVERFLOW: - case ILLEGAL_REQUEST: - if (!sense->valid) - break; - if (failed_command == NULL || - blk_rq_is_passthrough(failed_command)) - break; - sector = (sense->information[0] << 24) | - (sense->information[1] << 16) | - (sense->information[2] << 8) | - (sense->information[3]); - - if (queue_logical_block_size(drive->queue) == 2048) - /* device sector size is 2K */ - sector <<= 2; - - bio_sectors = max(bio_sectors(failed_command->bio), 4U); - sector &= ~(bio_sectors - 1); - - /* - * The SCSI specification allows for the value - * returned by READ CAPACITY to be up to 75 2K - * sectors past the last readable block. - * Therefore, if we hit a medium error within the - * last 75 2K sectors, we decrease the saved size - * value. - */ - if (sector < get_capacity(info->disk) && - drive->probed_capacity - sector < 4 * 75) - set_capacity(info->disk, sector); - } - } - - ide_cd_log_error(drive->name, failed_command, sense); -} - -static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq) -{ - /* - * For ATA_PRIV_SENSE, "ide_req(rq)->special" points to the original - * failed request. Also, the sense data should be read - * directly from rq which might be different from the original - * sense buffer if it got copied during mapping. - */ - struct request *failed = ide_req(rq)->special; - void *sense = bio_data(rq->bio); - - if (failed) { - /* - * Sense is always read into drive->sense_data, copy back to the - * original request. - */ - memcpy(scsi_req(failed)->sense, sense, 18); - scsi_req(failed)->sense_len = scsi_req(rq)->sense_len; - cdrom_analyze_sense_data(drive, failed); - - if (ide_end_rq(drive, failed, BLK_STS_IOERR, blk_rq_bytes(failed))) - BUG(); - } else - cdrom_analyze_sense_data(drive, NULL); -} - - -/* - * Allow the drive 5 seconds to recover; some devices will return NOT_READY - * while flushing data from cache. - * - * returns: 0 failed (write timeout expired) - * 1 success - */ -static int ide_cd_breathe(ide_drive_t *drive, struct request *rq) -{ - - struct cdrom_info *info = drive->driver_data; - - if (!scsi_req(rq)->result) - info->write_timeout = jiffies + ATAPI_WAIT_WRITE_BUSY; - - scsi_req(rq)->result = 1; - - if (time_after(jiffies, info->write_timeout)) - return 0; - else { - /* - * take a breather - */ - blk_mq_requeue_request(rq, false); - blk_mq_delay_kick_requeue_list(drive->queue, 1); - return 1; - } -} - -static void ide_cd_free_sense(ide_drive_t *drive) -{ - if (!drive->sense_rq) - return; - - blk_mq_free_request(drive->sense_rq); - drive->sense_rq = NULL; - drive->sense_rq_armed = false; -} - -/** - * Returns: - * 0: if the request should be continued. - * 1: if the request will be going through error recovery. - * 2: if the request should be ended. - */ -static int cdrom_decode_status(ide_drive_t *drive, u8 stat) -{ - ide_hwif_t *hwif = drive->hwif; - struct request *rq = hwif->rq; - int err, sense_key, do_end_request = 0; - - /* get the IDE error register */ - err = ide_read_error(drive); - sense_key = err >> 4; - - ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, rq->cmd_type: 0x%x, err: 0x%x, " - "stat 0x%x", - rq->cmd[0], rq->cmd_type, err, stat); - - if (ata_sense_request(rq)) { - /* - * We got an error trying to get sense info from the drive - * (probably while trying to recover from a former error). - * Just give up. - */ - rq->rq_flags |= RQF_FAILED; - return 2; - } - - /* if we have an error, pass CHECK_CONDITION as the SCSI status byte */ - if (blk_rq_is_scsi(rq) && !scsi_req(rq)->result) - scsi_req(rq)->result = SAM_STAT_CHECK_CONDITION; - - if (blk_noretry_request(rq)) - do_end_request = 1; - - switch (sense_key) { - case NOT_READY: - if (req_op(rq) == REQ_OP_WRITE) { - if (ide_cd_breathe(drive, rq)) - return 1; - } else { - cdrom_saw_media_change(drive); - - if (!blk_rq_is_passthrough(rq) && - !(rq->rq_flags & RQF_QUIET)) - printk(KERN_ERR PFX "%s: tray open\n", - drive->name); - } - do_end_request = 1; - break; - case UNIT_ATTENTION: - cdrom_saw_media_change(drive); - - if (blk_rq_is_passthrough(rq)) - return 0; - - /* - * Arrange to retry the request but be sure to give up if we've - * retried too many times. - */ - if (++scsi_req(rq)->result > ERROR_MAX) - do_end_request = 1; - break; - case ILLEGAL_REQUEST: - /* - * Don't print error message for this condition -- SFF8090i - * indicates that 5/24/00 is the correct response to a request - * to close the tray if the drive doesn't have that capability. - * - * cdrom_log_sense() knows this! - */ - if (scsi_req(rq)->cmd[0] == GPCMD_START_STOP_UNIT) - break; - fallthrough; - case DATA_PROTECT: - /* - * No point in retrying after an illegal request or data - * protect error. - */ - if (!(rq->rq_flags & RQF_QUIET)) - ide_dump_status(drive, "command error", stat); - do_end_request = 1; - break; - case MEDIUM_ERROR: - /* - * No point in re-trying a zillion times on a bad sector. - * If we got here the error is not correctable. - */ - if (!(rq->rq_flags & RQF_QUIET)) - ide_dump_status(drive, "media error " - "(bad sector)", stat); - do_end_request = 1; - break; - case BLANK_CHECK: - /* disk appears blank? */ - if (!(rq->rq_flags & RQF_QUIET)) - ide_dump_status(drive, "media error (blank)", - stat); - do_end_request = 1; - break; - default: - if (blk_rq_is_passthrough(rq)) - break; - if (err & ~ATA_ABORTED) { - /* go to the default handler for other errors */ - ide_error(drive, "cdrom_decode_status", stat); - return 1; - } else if (++scsi_req(rq)->result > ERROR_MAX) - /* we've racked up too many retries, abort */ - do_end_request = 1; - } - - if (blk_rq_is_passthrough(rq)) { - rq->rq_flags |= RQF_FAILED; - do_end_request = 1; - } - - /* - * End a request through request sense analysis when we have sense data. - * We need this in order to perform end of media processing. - */ - if (do_end_request) - goto end_request; - - /* if we got a CHECK_CONDITION status, queue a request sense command */ - if (stat & ATA_ERR) - return ide_queue_sense_rq(drive, NULL) ? 2 : 1; - return 1; - -end_request: - if (stat & ATA_ERR) { - hwif->rq = NULL; - return ide_queue_sense_rq(drive, rq) ? 2 : 1; - } else - return 2; -} - -static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd) -{ - struct request *rq = cmd->rq; - - ide_debug_log(IDE_DBG_FUNC, "rq->cmd[0]: 0x%x", rq->cmd[0]); - - /* - * Some of the trailing request sense fields are optional, - * and some drives don't send them. Sigh. - */ - if (scsi_req(rq)->cmd[0] == GPCMD_REQUEST_SENSE && - cmd->nleft > 0 && cmd->nleft <= 5) - cmd->nleft = 0; -} - -int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd, - int write, void *buffer, unsigned *bufflen, - struct scsi_sense_hdr *sshdr, int timeout, - req_flags_t rq_flags) -{ - struct cdrom_info *info = drive->driver_data; - struct scsi_sense_hdr local_sshdr; - int retries = 10; - bool failed; - - ide_debug_log(IDE_DBG_PC, "cmd[0]: 0x%x, write: 0x%x, timeout: %d, " - "rq_flags: 0x%x", - cmd[0], write, timeout, rq_flags); - - if (!sshdr) - sshdr = &local_sshdr; - - /* start of retry loop */ - do { - struct request *rq; - int error; - bool delay = false; - - rq = blk_get_request(drive->queue, - write ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); - memcpy(scsi_req(rq)->cmd, cmd, BLK_MAX_CDB); - ide_req(rq)->type = ATA_PRIV_PC; - rq->rq_flags |= rq_flags; - rq->timeout = timeout; - if (buffer) { - error = blk_rq_map_kern(drive->queue, rq, buffer, - *bufflen, GFP_NOIO); - if (error) { - blk_put_request(rq); - return error; - } - } - - blk_execute_rq(info->disk, rq, 0); - error = scsi_req(rq)->result ? -EIO : 0; - - if (buffer) - *bufflen = scsi_req(rq)->resid_len; - scsi_normalize_sense(scsi_req(rq)->sense, - scsi_req(rq)->sense_len, sshdr); - - /* - * FIXME: we should probably abort/retry or something in case of - * failure. - */ - failed = (rq->rq_flags & RQF_FAILED) != 0; - if (failed) { - /* - * The request failed. Retry if it was due to a unit - * attention status (usually means media was changed). - */ - if (sshdr->sense_key == UNIT_ATTENTION) - cdrom_saw_media_change(drive); - else if (sshdr->sense_key == NOT_READY && - sshdr->asc == 4 && sshdr->ascq != 4) { - /* - * The drive is in the process of loading - * a disk. Retry, but wait a little to give - * the drive time to complete the load. - */ - delay = true; - } else { - /* otherwise, don't retry */ - retries = 0; - } - --retries; - } - blk_put_request(rq); - if (delay) - ssleep(2); - } while (failed && retries >= 0); - - /* return an error if the command failed */ - return failed ? -EIO : 0; -} - -/* - * returns true if rq has been completed - */ -static bool ide_cd_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd) -{ - unsigned int nr_bytes = cmd->nbytes - cmd->nleft; - - if (cmd->tf_flags & IDE_TFLAG_WRITE) - nr_bytes -= cmd->last_xfer_len; - - if (nr_bytes > 0) { - ide_complete_rq(drive, BLK_STS_OK, nr_bytes); - return true; - } - - return false; -} - -/* standard prep_rq that builds 10 byte cmds */ -static bool ide_cdrom_prep_fs(struct request_queue *q, struct request *rq) -{ - int hard_sect = queue_logical_block_size(q); - long block = (long)blk_rq_pos(rq) / (hard_sect >> 9); - unsigned long blocks = blk_rq_sectors(rq) / (hard_sect >> 9); - struct scsi_request *req = scsi_req(rq); - - if (rq_data_dir(rq) == READ) - req->cmd[0] = GPCMD_READ_10; - else - req->cmd[0] = GPCMD_WRITE_10; - - /* - * fill in lba - */ - req->cmd[2] = (block >> 24) & 0xff; - req->cmd[3] = (block >> 16) & 0xff; - req->cmd[4] = (block >> 8) & 0xff; - req->cmd[5] = block & 0xff; - - /* - * and transfer length - */ - req->cmd[7] = (blocks >> 8) & 0xff; - req->cmd[8] = blocks & 0xff; - req->cmd_len = 10; - return true; -} - -/* - * Most of the SCSI commands are supported directly by ATAPI devices. - * This transform handles the few exceptions. - */ -static bool ide_cdrom_prep_pc(struct request *rq) -{ - u8 *c = scsi_req(rq)->cmd; - - /* transform 6-byte read/write commands to the 10-byte version */ - if (c[0] == READ_6 || c[0] == WRITE_6) { - c[8] = c[4]; - c[5] = c[3]; - c[4] = c[2]; - c[3] = c[1] & 0x1f; - c[2] = 0; - c[1] &= 0xe0; - c[0] += (READ_10 - READ_6); - scsi_req(rq)->cmd_len = 10; - return true; - } - - /* - * it's silly to pretend we understand 6-byte sense commands, just - * reject with ILLEGAL_REQUEST and the caller should take the - * appropriate action - */ - if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) { - scsi_req(rq)->result = ILLEGAL_REQUEST; - return false; - } - - return true; -} - -static bool ide_cdrom_prep_rq(ide_drive_t *drive, struct request *rq) -{ - if (!blk_rq_is_passthrough(rq)) { - scsi_req_init(scsi_req(rq)); - - return ide_cdrom_prep_fs(drive->queue, rq); - } else if (blk_rq_is_scsi(rq)) - return ide_cdrom_prep_pc(rq); - - return true; -} - -static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_cmd *cmd = &hwif->cmd; - struct request *rq = hwif->rq; - ide_expiry_t *expiry = NULL; - int dma_error = 0, dma, thislen, uptodate = 0; - int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc = 0; - int sense = ata_sense_request(rq); - unsigned int timeout; - u16 len; - u8 ireason, stat; - - ide_debug_log(IDE_DBG_PC, "cmd: 0x%x, write: 0x%x", rq->cmd[0], write); - - /* check for errors */ - dma = drive->dma; - if (dma) { - drive->dma = 0; - drive->waiting_for_dma = 0; - dma_error = hwif->dma_ops->dma_end(drive); - ide_dma_unmap_sg(drive, cmd); - if (dma_error) { - printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name, - write ? "write" : "read"); - ide_dma_off(drive); - } - } - - /* check status */ - stat = hwif->tp_ops->read_status(hwif); - - if (!OK_STAT(stat, 0, BAD_R_STAT)) { - rc = cdrom_decode_status(drive, stat); - if (rc) { - if (rc == 2) - goto out_end; - return ide_stopped; - } - } - - /* using dma, transfer is complete now */ - if (dma) { - if (dma_error) - return ide_error(drive, "dma error", stat); - uptodate = 1; - goto out_end; - } - - ide_read_bcount_and_ireason(drive, &len, &ireason); - - thislen = !blk_rq_is_passthrough(rq) ? len : cmd->nleft; - if (thislen > len) - thislen = len; - - ide_debug_log(IDE_DBG_PC, "DRQ: stat: 0x%x, thislen: %d", - stat, thislen); - - /* If DRQ is clear, the command has completed. */ - if ((stat & ATA_DRQ) == 0) { - switch (req_op(rq)) { - default: - /* - * If we're not done reading/writing, complain. - * Otherwise, complete the command normally. - */ - uptodate = 1; - if (cmd->nleft > 0) { - printk(KERN_ERR PFX "%s: %s: data underrun " - "(%u bytes)\n", drive->name, __func__, - cmd->nleft); - if (!write) - rq->rq_flags |= RQF_FAILED; - uptodate = 0; - } - goto out_end; - case REQ_OP_DRV_IN: - case REQ_OP_DRV_OUT: - ide_cd_request_sense_fixup(drive, cmd); - - uptodate = cmd->nleft ? 0 : 1; - - /* - * suck out the remaining bytes from the drive in an - * attempt to complete the data xfer. (see BZ#13399) - */ - if (!(stat & ATA_ERR) && !uptodate && thislen) { - ide_pio_bytes(drive, cmd, write, thislen); - uptodate = cmd->nleft ? 0 : 1; - } - - if (!uptodate) - rq->rq_flags |= RQF_FAILED; - goto out_end; - case REQ_OP_SCSI_IN: - case REQ_OP_SCSI_OUT: - goto out_end; - } - } - - rc = ide_check_ireason(drive, rq, len, ireason, write); - if (rc) - goto out_end; - - cmd->last_xfer_len = 0; - - ide_debug_log(IDE_DBG_PC, "data transfer, rq->cmd_type: 0x%x, " - "ireason: 0x%x", - rq->cmd_type, ireason); - - /* transfer data */ - while (thislen > 0) { - int blen = min_t(int, thislen, cmd->nleft); - - if (cmd->nleft == 0) - break; - - ide_pio_bytes(drive, cmd, write, blen); - cmd->last_xfer_len += blen; - - thislen -= blen; - len -= blen; - - if (sense && write == 0) - scsi_req(rq)->sense_len += blen; - } - - /* pad, if necessary */ - if (len > 0) { - if (blk_rq_is_passthrough(rq) || write == 0) - ide_pad_transfer(drive, write, len); - else { - printk(KERN_ERR PFX "%s: confused, missing data\n", - drive->name); - blk_dump_rq_flags(rq, "cdrom_newpc_intr"); - } - } - - switch (req_op(rq)) { - case REQ_OP_SCSI_IN: - case REQ_OP_SCSI_OUT: - timeout = rq->timeout; - break; - case REQ_OP_DRV_IN: - case REQ_OP_DRV_OUT: - expiry = ide_cd_expiry; - fallthrough; - default: - timeout = ATAPI_WAIT_PC; - break; - } - - hwif->expiry = expiry; - ide_set_handler(drive, cdrom_newpc_intr, timeout); - return ide_started; - -out_end: - if (blk_rq_is_scsi(rq) && rc == 0) { - scsi_req(rq)->resid_len = 0; - blk_mq_end_request(rq, BLK_STS_OK); - hwif->rq = NULL; - } else { - if (sense && uptodate) - ide_cd_complete_failed_rq(drive, rq); - - if (!blk_rq_is_passthrough(rq)) { - if (cmd->nleft == 0) - uptodate = 1; - } else { - if (uptodate <= 0 && scsi_req(rq)->result == 0) - scsi_req(rq)->result = -EIO; - } - - if (uptodate == 0 && rq->bio) - if (ide_cd_error_cmd(drive, cmd)) - return ide_stopped; - - /* make sure it's fully ended */ - if (blk_rq_is_passthrough(rq)) { - scsi_req(rq)->resid_len -= cmd->nbytes - cmd->nleft; - if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE)) - scsi_req(rq)->resid_len += cmd->last_xfer_len; - } - - ide_complete_rq(drive, uptodate ? BLK_STS_OK : BLK_STS_IOERR, blk_rq_bytes(rq)); - - if (sense && rc == 2) - ide_error(drive, "request sense failure", stat); - } - - ide_cd_free_sense(drive); - return ide_stopped; -} - -static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq) -{ - struct cdrom_info *cd = drive->driver_data; - struct request_queue *q = drive->queue; - int write = rq_data_dir(rq) == WRITE; - unsigned short sectors_per_frame = - queue_logical_block_size(q) >> SECTOR_SHIFT; - - ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, " - "secs_per_frame: %u", - rq->cmd[0], rq->cmd_flags, sectors_per_frame); - - if (write) { - /* disk has become write protected */ - if (get_disk_ro(cd->disk)) - return ide_stopped; - } else { - /* - * We may be retrying this request after an error. Fix up any - * weirdness which might be present in the request packet. - */ - ide_cdrom_prep_rq(drive, rq); - } - - /* fs requests *must* be hardware frame aligned */ - if ((blk_rq_sectors(rq) & (sectors_per_frame - 1)) || - (blk_rq_pos(rq) & (sectors_per_frame - 1))) - return ide_stopped; - - /* use DMA, if possible */ - drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); - - if (write) - cd->devinfo.media_written = 1; - - rq->timeout = ATAPI_WAIT_PC; - - return ide_started; -} - -static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq) -{ - - ide_debug_log(IDE_DBG_PC, "rq->cmd[0]: 0x%x, rq->cmd_type: 0x%x", - rq->cmd[0], rq->cmd_type); - - if (blk_rq_is_scsi(rq)) - rq->rq_flags |= RQF_QUIET; - else - rq->rq_flags &= ~RQF_FAILED; - - drive->dma = 0; - - /* sg request */ - if (rq->bio) { - struct request_queue *q = drive->queue; - char *buf = bio_data(rq->bio); - unsigned int alignment; - - drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); - - /* - * check if dma is safe - * - * NOTE! The "len" and "addr" checks should possibly have - * separate masks. - */ - alignment = queue_dma_alignment(q) | q->dma_pad_mask; - if ((unsigned long)buf & alignment - || blk_rq_bytes(rq) & q->dma_pad_mask - || object_is_on_stack(buf)) - drive->dma = 0; - } -} - -static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, - sector_t block) -{ - struct ide_cmd cmd; - int uptodate = 0; - unsigned int nsectors; - - ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, block: %llu", - rq->cmd[0], (unsigned long long)block); - - if (drive->debug_mask & IDE_DBG_RQ) - blk_dump_rq_flags(rq, "ide_cd_do_request"); - - switch (req_op(rq)) { - default: - if (cdrom_start_rw(drive, rq) == ide_stopped) - goto out_end; - break; - case REQ_OP_SCSI_IN: - case REQ_OP_SCSI_OUT: - handle_pc: - if (!rq->timeout) - rq->timeout = ATAPI_WAIT_PC; - cdrom_do_block_pc(drive, rq); - break; - case REQ_OP_DRV_IN: - case REQ_OP_DRV_OUT: - switch (ide_req(rq)->type) { - case ATA_PRIV_MISC: - /* right now this can only be a reset... */ - uptodate = 1; - goto out_end; - case ATA_PRIV_SENSE: - case ATA_PRIV_PC: - goto handle_pc; - default: - BUG(); - } - } - - /* prepare sense request for this command */ - ide_prep_sense(drive, rq); - - memset(&cmd, 0, sizeof(cmd)); - - if (rq_data_dir(rq)) - cmd.tf_flags |= IDE_TFLAG_WRITE; - - cmd.rq = rq; - - if (!blk_rq_is_passthrough(rq) || blk_rq_bytes(rq)) { - ide_init_sg_cmd(&cmd, blk_rq_bytes(rq)); - ide_map_sg(drive, &cmd); - } - - return ide_issue_pc(drive, &cmd); -out_end: - nsectors = blk_rq_sectors(rq); - - if (nsectors == 0) - nsectors = 1; - - ide_complete_rq(drive, uptodate ? BLK_STS_OK : BLK_STS_IOERR, nsectors << 9); - - return ide_stopped; -} - -/* - * Ioctl handling. - * - * Routines which queue packet commands take as a final argument a pointer to a - * request_sense struct. If execution of the command results in an error with a - * CHECK CONDITION status, this structure will be filled with the results of the - * subsequent request sense command. The pointer can also be NULL, in which case - * no sense information is returned. - */ -static void msf_from_bcd(struct atapi_msf *msf) -{ - msf->minute = bcd2bin(msf->minute); - msf->second = bcd2bin(msf->second); - msf->frame = bcd2bin(msf->frame); -} - -int cdrom_check_status(ide_drive_t *drive, struct scsi_sense_hdr *sshdr) -{ - struct cdrom_info *info = drive->driver_data; - struct cdrom_device_info *cdi; - unsigned char cmd[BLK_MAX_CDB]; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - if (!info) - return -EIO; - - cdi = &info->devinfo; - - memset(cmd, 0, BLK_MAX_CDB); - cmd[0] = GPCMD_TEST_UNIT_READY; - - /* - * Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to switch CDs - * instead of supporting the LOAD_UNLOAD opcode. - */ - cmd[7] = cdi->sanyo_slot % 3; - - return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, sshdr, 0, RQF_QUIET); -} - -static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity, - unsigned long *sectors_per_frame) -{ - struct { - __be32 lba; - __be32 blocklen; - } capbuf; - - int stat; - unsigned char cmd[BLK_MAX_CDB]; - unsigned len = sizeof(capbuf); - u32 blocklen; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - memset(cmd, 0, BLK_MAX_CDB); - cmd[0] = GPCMD_READ_CDVD_CAPACITY; - - stat = ide_cd_queue_pc(drive, cmd, 0, &capbuf, &len, NULL, 0, - RQF_QUIET); - if (stat) - return stat; - - /* - * Sanity check the given block size, in so far as making - * sure the sectors_per_frame we give to the caller won't - * end up being bogus. - */ - blocklen = be32_to_cpu(capbuf.blocklen); - blocklen = (blocklen >> SECTOR_SHIFT) << SECTOR_SHIFT; - switch (blocklen) { - case 512: - case 1024: - case 2048: - case 4096: - break; - default: - printk_once(KERN_ERR PFX "%s: weird block size %u; " - "setting default block size to 2048\n", - drive->name, blocklen); - blocklen = 2048; - break; - } - - *capacity = 1 + be32_to_cpu(capbuf.lba); - *sectors_per_frame = blocklen >> SECTOR_SHIFT; - - ide_debug_log(IDE_DBG_PROBE, "cap: %lu, sectors_per_frame: %lu", - *capacity, *sectors_per_frame); - - return 0; -} - -static int ide_cdrom_read_tocentry(ide_drive_t *drive, int trackno, - int msf_flag, int format, char *buf, int buflen) -{ - unsigned char cmd[BLK_MAX_CDB]; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - memset(cmd, 0, BLK_MAX_CDB); - - cmd[0] = GPCMD_READ_TOC_PMA_ATIP; - cmd[6] = trackno; - cmd[7] = (buflen >> 8); - cmd[8] = (buflen & 0xff); - cmd[9] = (format << 6); - - if (msf_flag) - cmd[1] = 2; - - return ide_cd_queue_pc(drive, cmd, 0, buf, &buflen, NULL, 0, RQF_QUIET); -} - -/* Try to read the entire TOC for the disk into our internal buffer. */ -int ide_cd_read_toc(ide_drive_t *drive) -{ - int stat, ntracks, i; - struct cdrom_info *info = drive->driver_data; - struct cdrom_device_info *cdi = &info->devinfo; - struct atapi_toc *toc = info->toc; - struct { - struct atapi_toc_header hdr; - struct atapi_toc_entry ent; - } ms_tmp; - long last_written; - unsigned long sectors_per_frame = SECTORS_PER_FRAME; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - if (toc == NULL) { - /* try to allocate space */ - toc = kmalloc(sizeof(struct atapi_toc), GFP_KERNEL); - if (toc == NULL) { - printk(KERN_ERR PFX "%s: No cdrom TOC buffer!\n", - drive->name); - return -ENOMEM; - } - info->toc = toc; - } - - /* - * Check to see if the existing data is still valid. If it is, - * just return. - */ - (void) cdrom_check_status(drive, NULL); - - if (drive->atapi_flags & IDE_AFLAG_TOC_VALID) - return 0; - - /* try to get the total cdrom capacity and sector size */ - stat = cdrom_read_capacity(drive, &toc->capacity, §ors_per_frame); - if (stat) - toc->capacity = 0x1fffff; - - set_capacity(info->disk, toc->capacity * sectors_per_frame); - /* save a private copy of the TOC capacity for error handling */ - drive->probed_capacity = toc->capacity * sectors_per_frame; - - blk_queue_logical_block_size(drive->queue, - sectors_per_frame << SECTOR_SHIFT); - - /* first read just the header, so we know how long the TOC is */ - stat = ide_cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr, - sizeof(struct atapi_toc_header)); - if (stat) - return stat; - - if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) { - toc->hdr.first_track = bcd2bin(toc->hdr.first_track); - toc->hdr.last_track = bcd2bin(toc->hdr.last_track); - } - - ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; - if (ntracks <= 0) - return -EIO; - if (ntracks > MAX_TRACKS) - ntracks = MAX_TRACKS; - - /* now read the whole schmeer */ - stat = ide_cdrom_read_tocentry(drive, toc->hdr.first_track, 1, 0, - (char *)&toc->hdr, - sizeof(struct atapi_toc_header) + - (ntracks + 1) * - sizeof(struct atapi_toc_entry)); - - if (stat && toc->hdr.first_track > 1) { - /* - * Cds with CDI tracks only don't have any TOC entries, despite - * of this the returned values are - * first_track == last_track = number of CDI tracks + 1, - * so that this case is indistinguishable from the same layout - * plus an additional audio track. If we get an error for the - * regular case, we assume a CDI without additional audio - * tracks. In this case the readable TOC is empty (CDI tracks - * are not included) and only holds the Leadout entry. - * - * Heiko Eißfeldt. - */ - ntracks = 0; - stat = ide_cdrom_read_tocentry(drive, CDROM_LEADOUT, 1, 0, - (char *)&toc->hdr, - sizeof(struct atapi_toc_header) + - (ntracks + 1) * - sizeof(struct atapi_toc_entry)); - if (stat) - return stat; - - if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) { - toc->hdr.first_track = (u8)bin2bcd(CDROM_LEADOUT); - toc->hdr.last_track = (u8)bin2bcd(CDROM_LEADOUT); - } else { - toc->hdr.first_track = CDROM_LEADOUT; - toc->hdr.last_track = CDROM_LEADOUT; - } - } - - if (stat) - return stat; - - toc->hdr.toc_length = be16_to_cpu(toc->hdr.toc_length); - - if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) { - toc->hdr.first_track = bcd2bin(toc->hdr.first_track); - toc->hdr.last_track = bcd2bin(toc->hdr.last_track); - } - - for (i = 0; i <= ntracks; i++) { - if (drive->atapi_flags & IDE_AFLAG_TOCADDR_AS_BCD) { - if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) - toc->ent[i].track = bcd2bin(toc->ent[i].track); - msf_from_bcd(&toc->ent[i].addr.msf); - } - toc->ent[i].addr.lba = msf_to_lba(toc->ent[i].addr.msf.minute, - toc->ent[i].addr.msf.second, - toc->ent[i].addr.msf.frame); - } - - if (toc->hdr.first_track != CDROM_LEADOUT) { - /* read the multisession information */ - stat = ide_cdrom_read_tocentry(drive, 0, 0, 1, (char *)&ms_tmp, - sizeof(ms_tmp)); - if (stat) - return stat; - - toc->last_session_lba = be32_to_cpu(ms_tmp.ent.addr.lba); - } else { - ms_tmp.hdr.last_track = CDROM_LEADOUT; - ms_tmp.hdr.first_track = ms_tmp.hdr.last_track; - toc->last_session_lba = msf_to_lba(0, 2, 0); /* 0m 2s 0f */ - } - - if (drive->atapi_flags & IDE_AFLAG_TOCADDR_AS_BCD) { - /* re-read multisession information using MSF format */ - stat = ide_cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp, - sizeof(ms_tmp)); - if (stat) - return stat; - - msf_from_bcd(&ms_tmp.ent.addr.msf); - toc->last_session_lba = msf_to_lba(ms_tmp.ent.addr.msf.minute, - ms_tmp.ent.addr.msf.second, - ms_tmp.ent.addr.msf.frame); - } - - toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track); - - /* now try to get the total cdrom capacity */ - stat = cdrom_get_last_written(cdi, &last_written); - if (!stat && (last_written > toc->capacity)) { - toc->capacity = last_written; - set_capacity(info->disk, toc->capacity * sectors_per_frame); - drive->probed_capacity = toc->capacity * sectors_per_frame; - } - - /* Remember that we've read this stuff. */ - drive->atapi_flags |= IDE_AFLAG_TOC_VALID; - - return 0; -} - -int ide_cdrom_get_capabilities(ide_drive_t *drive, u8 *buf) -{ - struct cdrom_info *info = drive->driver_data; - struct cdrom_device_info *cdi = &info->devinfo; - struct packet_command cgc; - int stat, attempts = 3, size = ATAPI_CAPABILITIES_PAGE_SIZE; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - if ((drive->atapi_flags & IDE_AFLAG_FULL_CAPS_PAGE) == 0) - size -= ATAPI_CAPABILITIES_PAGE_PAD_SIZE; - - init_cdrom_command(&cgc, buf, size, CGC_DATA_UNKNOWN); - do { - /* we seem to get stat=0x01,err=0x00 the first time (??) */ - stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); - if (!stat) - break; - } while (--attempts); - return stat; -} - -void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf) -{ - struct cdrom_info *cd = drive->driver_data; - u16 curspeed, maxspeed; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - if (drive->atapi_flags & IDE_AFLAG_LE_SPEED_FIELDS) { - curspeed = le16_to_cpup((__le16 *)&buf[8 + 14]); - maxspeed = le16_to_cpup((__le16 *)&buf[8 + 8]); - } else { - curspeed = be16_to_cpup((__be16 *)&buf[8 + 14]); - maxspeed = be16_to_cpup((__be16 *)&buf[8 + 8]); - } - - ide_debug_log(IDE_DBG_PROBE, "curspeed: %u, maxspeed: %u", - curspeed, maxspeed); - - cd->current_speed = DIV_ROUND_CLOSEST(curspeed, 176); - cd->max_speed = DIV_ROUND_CLOSEST(maxspeed, 176); -} - -#define IDE_CD_CAPABILITIES \ - (CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | \ - CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | \ - CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R | \ - CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET | \ - CDC_MO_DRIVE | CDC_MRW | CDC_MRW_W | CDC_RAM) - -static const struct cdrom_device_ops ide_cdrom_dops = { - .open = ide_cdrom_open_real, - .release = ide_cdrom_release_real, - .drive_status = ide_cdrom_drive_status, - .check_events = ide_cdrom_check_events_real, - .tray_move = ide_cdrom_tray_move, - .lock_door = ide_cdrom_lock_door, - .select_speed = ide_cdrom_select_speed, - .get_last_session = ide_cdrom_get_last_session, - .get_mcn = ide_cdrom_get_mcn, - .reset = ide_cdrom_reset, - .audio_ioctl = ide_cdrom_audio_ioctl, - .capability = IDE_CD_CAPABILITIES, - .generic_packet = ide_cdrom_packet, -}; - -static int ide_cdrom_register(ide_drive_t *drive, int nslots) -{ - struct cdrom_info *info = drive->driver_data; - struct cdrom_device_info *devinfo = &info->devinfo; - - ide_debug_log(IDE_DBG_PROBE, "nslots: %d", nslots); - - devinfo->ops = &ide_cdrom_dops; - devinfo->speed = info->current_speed; - devinfo->capacity = nslots; - devinfo->handle = drive; - strcpy(devinfo->name, drive->name); - - if (drive->atapi_flags & IDE_AFLAG_NO_SPEED_SELECT) - devinfo->mask |= CDC_SELECT_SPEED; - - return register_cdrom(info->disk, devinfo); -} - -static int ide_cdrom_probe_capabilities(ide_drive_t *drive) -{ - struct cdrom_info *cd = drive->driver_data; - struct cdrom_device_info *cdi = &cd->devinfo; - u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE]; - mechtype_t mechtype; - int nslots = 1; - - ide_debug_log(IDE_DBG_PROBE, "media: 0x%x, atapi_flags: 0x%lx", - drive->media, drive->atapi_flags); - - cdi->mask = (CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | - CDC_DVD_RAM | CDC_SELECT_DISC | CDC_PLAY_AUDIO | - CDC_MO_DRIVE | CDC_RAM); - - if (drive->media == ide_optical) { - cdi->mask &= ~(CDC_MO_DRIVE | CDC_RAM); - printk(KERN_ERR PFX "%s: ATAPI magneto-optical drive\n", - drive->name); - return nslots; - } - - if (drive->atapi_flags & IDE_AFLAG_PRE_ATAPI12) { - drive->atapi_flags &= ~IDE_AFLAG_NO_EJECT; - cdi->mask &= ~CDC_PLAY_AUDIO; - return nslots; - } - - /* - * We have to cheat a little here. the packet will eventually be queued - * with ide_cdrom_packet(), which extracts the drive from cdi->handle. - * Since this device hasn't been registered with the Uniform layer yet, - * it can't do this. Same goes for cdi->ops. - */ - cdi->handle = drive; - cdi->ops = &ide_cdrom_dops; - - if (ide_cdrom_get_capabilities(drive, buf)) - return 0; - - if ((buf[8 + 6] & 0x01) == 0) - drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING; - if (buf[8 + 6] & 0x08) - drive->atapi_flags &= ~IDE_AFLAG_NO_EJECT; - if (buf[8 + 3] & 0x01) - cdi->mask &= ~CDC_CD_R; - if (buf[8 + 3] & 0x02) - cdi->mask &= ~(CDC_CD_RW | CDC_RAM); - if (buf[8 + 2] & 0x38) - cdi->mask &= ~CDC_DVD; - if (buf[8 + 3] & 0x20) - cdi->mask &= ~(CDC_DVD_RAM | CDC_RAM); - if (buf[8 + 3] & 0x10) - cdi->mask &= ~CDC_DVD_R; - if ((buf[8 + 4] & 0x01) || (drive->atapi_flags & IDE_AFLAG_PLAY_AUDIO_OK)) - cdi->mask &= ~CDC_PLAY_AUDIO; - - mechtype = buf[8 + 6] >> 5; - if (mechtype == mechtype_caddy || - mechtype == mechtype_popup || - (drive->atapi_flags & IDE_AFLAG_NO_AUTOCLOSE)) - cdi->mask |= CDC_CLOSE_TRAY; - - if (cdi->sanyo_slot > 0) { - cdi->mask &= ~CDC_SELECT_DISC; - nslots = 3; - } else if (mechtype == mechtype_individual_changer || - mechtype == mechtype_cartridge_changer) { - nslots = cdrom_number_of_slots(cdi); - if (nslots > 1) - cdi->mask &= ~CDC_SELECT_DISC; - } - - ide_cdrom_update_speed(drive, buf); - - printk(KERN_INFO PFX "%s: ATAPI", drive->name); - - /* don't print speed if the drive reported 0 */ - if (cd->max_speed) - printk(KERN_CONT " %dX", cd->max_speed); - - printk(KERN_CONT " %s", (cdi->mask & CDC_DVD) ? "CD-ROM" : "DVD-ROM"); - - if ((cdi->mask & CDC_DVD_R) == 0 || (cdi->mask & CDC_DVD_RAM) == 0) - printk(KERN_CONT " DVD%s%s", - (cdi->mask & CDC_DVD_R) ? "" : "-R", - (cdi->mask & CDC_DVD_RAM) ? "" : "/RAM"); - - if ((cdi->mask & CDC_CD_R) == 0 || (cdi->mask & CDC_CD_RW) == 0) - printk(KERN_CONT " CD%s%s", - (cdi->mask & CDC_CD_R) ? "" : "-R", - (cdi->mask & CDC_CD_RW) ? "" : "/RW"); - - if ((cdi->mask & CDC_SELECT_DISC) == 0) - printk(KERN_CONT " changer w/%d slots", nslots); - else - printk(KERN_CONT " drive"); - - printk(KERN_CONT ", %dkB Cache\n", - be16_to_cpup((__be16 *)&buf[8 + 12])); - - return nslots; -} - -struct cd_list_entry { - const char *id_model; - const char *id_firmware; - unsigned int cd_flags; -}; - -#ifdef CONFIG_IDE_PROC_FS -static sector_t ide_cdrom_capacity(ide_drive_t *drive) -{ - unsigned long capacity, sectors_per_frame; - - if (cdrom_read_capacity(drive, &capacity, §ors_per_frame)) - return 0; - - return capacity * sectors_per_frame; -} - -static int idecd_capacity_proc_show(struct seq_file *m, void *v) -{ - ide_drive_t *drive = m->private; - - seq_printf(m, "%llu\n", (long long)ide_cdrom_capacity(drive)); - return 0; -} - -static ide_proc_entry_t idecd_proc[] = { - { "capacity", S_IFREG|S_IRUGO, idecd_capacity_proc_show }, - {} -}; - -static ide_proc_entry_t *ide_cd_proc_entries(ide_drive_t *drive) -{ - return idecd_proc; -} - -static const struct ide_proc_devset *ide_cd_proc_devsets(ide_drive_t *drive) -{ - return NULL; -} -#endif - -static const struct cd_list_entry ide_cd_quirks_list[] = { - /* SCR-3231 doesn't support the SET_CD_SPEED command. */ - { "SAMSUNG CD-ROM SCR-3231", NULL, IDE_AFLAG_NO_SPEED_SELECT }, - /* Old NEC260 (not R) was released before ATAPI 1.2 spec. */ - { "NEC CD-ROM DRIVE:260", "1.01", IDE_AFLAG_TOCADDR_AS_BCD | - IDE_AFLAG_PRE_ATAPI12, }, - /* Vertos 300, some versions of this drive like to talk BCD. */ - { "V003S0DS", NULL, IDE_AFLAG_VERTOS_300_SSD, }, - /* Vertos 600 ESD. */ - { "V006E0DS", NULL, IDE_AFLAG_VERTOS_600_ESD, }, - /* - * Sanyo 3 CD changer uses a non-standard command for CD changing - * (by default standard ATAPI support for CD changers is used). - */ - { "CD-ROM CDR-C3 G", NULL, IDE_AFLAG_SANYO_3CD }, - { "CD-ROM CDR-C3G", NULL, IDE_AFLAG_SANYO_3CD }, - { "CD-ROM CDR_C36", NULL, IDE_AFLAG_SANYO_3CD }, - /* Stingray 8X CD-ROM. */ - { "STINGRAY 8422 IDE 8X CD-ROM 7-27-95", NULL, IDE_AFLAG_PRE_ATAPI12 }, - /* - * ACER 50X CD-ROM and WPI 32X CD-ROM require the full spec length - * mode sense page capabilities size, but older drives break. - */ - { "ATAPI CD ROM DRIVE 50X MAX", NULL, IDE_AFLAG_FULL_CAPS_PAGE }, - { "WPI CDS-32X", NULL, IDE_AFLAG_FULL_CAPS_PAGE }, - /* ACER/AOpen 24X CD-ROM has the speed fields byte-swapped. */ - { "", "241N", IDE_AFLAG_LE_SPEED_FIELDS }, - /* - * Some drives used by Apple don't advertise audio play - * but they do support reading TOC & audio datas. - */ - { "MATSHITADVD-ROM SR-8187", NULL, IDE_AFLAG_PLAY_AUDIO_OK }, - { "MATSHITADVD-ROM SR-8186", NULL, IDE_AFLAG_PLAY_AUDIO_OK }, - { "MATSHITADVD-ROM SR-8176", NULL, IDE_AFLAG_PLAY_AUDIO_OK }, - { "MATSHITADVD-ROM SR-8174", NULL, IDE_AFLAG_PLAY_AUDIO_OK }, - { "Optiarc DVD RW AD-5200A", NULL, IDE_AFLAG_PLAY_AUDIO_OK }, - { "Optiarc DVD RW AD-7200A", NULL, IDE_AFLAG_PLAY_AUDIO_OK }, - { "Optiarc DVD RW AD-7543A", NULL, IDE_AFLAG_NO_AUTOCLOSE }, - { "TEAC CD-ROM CD-224E", NULL, IDE_AFLAG_NO_AUTOCLOSE }, - { NULL, NULL, 0 } -}; - -static unsigned int ide_cd_flags(u16 *id) -{ - const struct cd_list_entry *cle = ide_cd_quirks_list; - - while (cle->id_model) { - if (strcmp(cle->id_model, (char *)&id[ATA_ID_PROD]) == 0 && - (cle->id_firmware == NULL || - strstr((char *)&id[ATA_ID_FW_REV], cle->id_firmware))) - return cle->cd_flags; - cle++; - } - - return 0; -} - -static int ide_cdrom_setup(ide_drive_t *drive) -{ - struct cdrom_info *cd = drive->driver_data; - struct cdrom_device_info *cdi = &cd->devinfo; - struct request_queue *q = drive->queue; - u16 *id = drive->id; - char *fw_rev = (char *)&id[ATA_ID_FW_REV]; - int nslots; - - ide_debug_log(IDE_DBG_PROBE, "enter"); - - drive->prep_rq = ide_cdrom_prep_rq; - blk_queue_dma_alignment(q, 31); - blk_queue_update_dma_pad(q, 15); - - drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED; - drive->atapi_flags = IDE_AFLAG_NO_EJECT | ide_cd_flags(id); - - if ((drive->atapi_flags & IDE_AFLAG_VERTOS_300_SSD) && - fw_rev[4] == '1' && fw_rev[6] <= '2') - drive->atapi_flags |= (IDE_AFLAG_TOCTRACKS_AS_BCD | - IDE_AFLAG_TOCADDR_AS_BCD); - else if ((drive->atapi_flags & IDE_AFLAG_VERTOS_600_ESD) && - fw_rev[4] == '1' && fw_rev[6] <= '2') - drive->atapi_flags |= IDE_AFLAG_TOCTRACKS_AS_BCD; - else if (drive->atapi_flags & IDE_AFLAG_SANYO_3CD) - /* 3 => use CD in slot 0 */ - cdi->sanyo_slot = 3; - - nslots = ide_cdrom_probe_capabilities(drive); - - blk_queue_logical_block_size(q, CD_FRAMESIZE); - - if (ide_cdrom_register(drive, nslots)) { - printk(KERN_ERR PFX "%s: %s failed to register device with the" - " cdrom driver.\n", drive->name, __func__); - cd->devinfo.handle = NULL; - return 1; - } - - ide_proc_register_driver(drive, cd->driver); - return 0; -} - -static void ide_cd_remove(ide_drive_t *drive) -{ - struct cdrom_info *info = drive->driver_data; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - ide_proc_unregister_driver(drive, info->driver); - device_del(&info->dev); - del_gendisk(info->disk); - - mutex_lock(&idecd_ref_mutex); - put_device(&info->dev); - mutex_unlock(&idecd_ref_mutex); -} - -static void ide_cd_release(struct device *dev) -{ - struct cdrom_info *info = to_ide_drv(dev, cdrom_info); - struct cdrom_device_info *devinfo = &info->devinfo; - ide_drive_t *drive = info->drive; - struct gendisk *g = info->disk; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - kfree(info->toc); - if (devinfo->handle == drive) - unregister_cdrom(devinfo); - drive->driver_data = NULL; - drive->prep_rq = NULL; - g->private_data = NULL; - put_disk(g); - kfree(info); -} - -static int ide_cd_probe(ide_drive_t *); - -static struct ide_driver ide_cdrom_driver = { - .gen_driver = { - .owner = THIS_MODULE, - .name = "ide-cdrom", - .bus = &ide_bus_type, - }, - .probe = ide_cd_probe, - .remove = ide_cd_remove, - .version = IDECD_VERSION, - .do_request = ide_cd_do_request, -#ifdef CONFIG_IDE_PROC_FS - .proc_entries = ide_cd_proc_entries, - .proc_devsets = ide_cd_proc_devsets, -#endif -}; - -static int idecd_open(struct block_device *bdev, fmode_t mode) -{ - struct cdrom_info *info; - int rc = -ENXIO; - - if (bdev_check_media_change(bdev)) { - info = ide_drv_g(bdev->bd_disk, cdrom_info); - - ide_cd_read_toc(info->drive); - } - - mutex_lock(&ide_cd_mutex); - info = ide_cd_get(bdev->bd_disk); - if (!info) - goto out; - - rc = cdrom_open(&info->devinfo, bdev, mode); - if (rc < 0) - ide_cd_put(info); -out: - mutex_unlock(&ide_cd_mutex); - return rc; -} - -static void idecd_release(struct gendisk *disk, fmode_t mode) -{ - struct cdrom_info *info = ide_drv_g(disk, cdrom_info); - - mutex_lock(&ide_cd_mutex); - cdrom_release(&info->devinfo, mode); - - ide_cd_put(info); - mutex_unlock(&ide_cd_mutex); -} - -static int idecd_set_spindown(struct cdrom_device_info *cdi, unsigned long arg) -{ - struct packet_command cgc; - char buffer[16]; - int stat; - char spindown; - - if (copy_from_user(&spindown, (void __user *)arg, sizeof(char))) - return -EFAULT; - - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN); - - stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0); - if (stat) - return stat; - - buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f); - return cdrom_mode_select(cdi, &cgc); -} - -static int idecd_get_spindown(struct cdrom_device_info *cdi, unsigned long arg) -{ - struct packet_command cgc; - char buffer[16]; - int stat; - char spindown; - - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN); - - stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0); - if (stat) - return stat; - - spindown = buffer[11] & 0x0f; - if (copy_to_user((void __user *)arg, &spindown, sizeof(char))) - return -EFAULT; - return 0; -} - -static int idecd_locked_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - struct cdrom_info *info = ide_drv_g(bdev->bd_disk, cdrom_info); - int err; - - switch (cmd) { - case CDROMSETSPINDOWN: - return idecd_set_spindown(&info->devinfo, arg); - case CDROMGETSPINDOWN: - return idecd_get_spindown(&info->devinfo, arg); - default: - break; - } - - err = generic_ide_ioctl(info->drive, bdev, cmd, arg); - if (err == -EINVAL) - err = cdrom_ioctl(&info->devinfo, bdev, mode, cmd, arg); - - return err; -} - -static int idecd_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - int ret; - - mutex_lock(&ide_cd_mutex); - ret = idecd_locked_ioctl(bdev, mode, cmd, arg); - mutex_unlock(&ide_cd_mutex); - - return ret; -} - -static int idecd_locked_compat_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - struct cdrom_info *info = ide_drv_g(bdev->bd_disk, cdrom_info); - void __user *argp = compat_ptr(arg); - int err; - - switch (cmd) { - case CDROMSETSPINDOWN: - return idecd_set_spindown(&info->devinfo, (unsigned long)argp); - case CDROMGETSPINDOWN: - return idecd_get_spindown(&info->devinfo, (unsigned long)argp); - default: - break; - } - - err = generic_ide_ioctl(info->drive, bdev, cmd, arg); - if (err == -EINVAL) - err = cdrom_ioctl(&info->devinfo, bdev, mode, cmd, - (unsigned long)argp); - - return err; -} - -static int idecd_compat_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - int ret; - - mutex_lock(&ide_cd_mutex); - ret = idecd_locked_compat_ioctl(bdev, mode, cmd, arg); - mutex_unlock(&ide_cd_mutex); - - return ret; -} - -static unsigned int idecd_check_events(struct gendisk *disk, - unsigned int clearing) -{ - struct cdrom_info *info = ide_drv_g(disk, cdrom_info); - return cdrom_check_events(&info->devinfo, clearing); -} - -static const struct block_device_operations idecd_ops = { - .owner = THIS_MODULE, - .open = idecd_open, - .release = idecd_release, - .ioctl = idecd_ioctl, - .compat_ioctl = IS_ENABLED(CONFIG_COMPAT) ? - idecd_compat_ioctl : NULL, - .check_events = idecd_check_events, -}; - -/* module options */ -static unsigned long debug_mask; -module_param(debug_mask, ulong, 0644); - -MODULE_DESCRIPTION("ATAPI CD-ROM Driver"); - -static int ide_cd_probe(ide_drive_t *drive) -{ - struct cdrom_info *info; - struct gendisk *g; - - ide_debug_log(IDE_DBG_PROBE, "driver_req: %s, media: 0x%x", - drive->driver_req, drive->media); - - if (!strstr("ide-cdrom", drive->driver_req)) - goto failed; - - if (drive->media != ide_cdrom && drive->media != ide_optical) - goto failed; - - drive->debug_mask = debug_mask; - drive->irq_handler = cdrom_newpc_intr; - - info = kzalloc(sizeof(struct cdrom_info), GFP_KERNEL); - if (info == NULL) { - printk(KERN_ERR PFX "%s: Can't allocate a cdrom structure\n", - drive->name); - goto failed; - } - - g = alloc_disk(1 << PARTN_BITS); - if (!g) - goto out_free_cd; - - ide_init_disk(g, drive); - - info->dev.parent = &drive->gendev; - info->dev.release = ide_cd_release; - dev_set_name(&info->dev, "%s", dev_name(&drive->gendev)); - - if (device_register(&info->dev)) - goto out_free_disk; - - info->drive = drive; - info->driver = &ide_cdrom_driver; - info->disk = g; - - g->private_data = &info->driver; - - drive->driver_data = info; - - g->minors = 1; - g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE; - if (ide_cdrom_setup(drive)) { - put_device(&info->dev); - goto failed; - } - - ide_cd_read_toc(drive); - g->fops = &idecd_ops; - g->flags |= GENHD_FL_REMOVABLE | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE; - g->events = DISK_EVENT_MEDIA_CHANGE; - device_add_disk(&drive->gendev, g, NULL); - return 0; - -out_free_disk: - put_disk(g); -out_free_cd: - kfree(info); -failed: - return -ENODEV; -} - -static void __exit ide_cdrom_exit(void) -{ - driver_unregister(&ide_cdrom_driver.gen_driver); -} - -static int __init ide_cdrom_init(void) -{ - printk(KERN_INFO DRV_NAME " driver " IDECD_VERSION "\n"); - return driver_register(&ide_cdrom_driver.gen_driver); -} - -MODULE_ALIAS("ide:*m-cdrom*"); -MODULE_ALIAS("ide-cd"); -module_init(ide_cdrom_init); -module_exit(ide_cdrom_exit); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h deleted file mode 100644 index a69dc7f61c4d..000000000000 --- a/drivers/ide/ide-cd.h +++ /dev/null @@ -1,123 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 1996-98 Erik Andersen - * Copyright (C) 1998-2000 Jens Axboe - */ -#ifndef _IDE_CD_H -#define _IDE_CD_H - -#include -#include - -#define IDECD_DEBUG_LOG 0 - -#if IDECD_DEBUG_LOG -#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, ## args) -#else -#define ide_debug_log(lvl, fmt, args...) do {} while (0) -#endif - -#define ATAPI_WAIT_WRITE_BUSY (10 * HZ) - -/************************************************************************/ - -#define SECTORS_PER_FRAME (CD_FRAMESIZE >> SECTOR_SHIFT) -#define SECTOR_BUFFER_SIZE (CD_FRAMESIZE * 32) - -/* Capabilities Page size including 8 bytes of Mode Page Header */ -#define ATAPI_CAPABILITIES_PAGE_SIZE (8 + 20) -#define ATAPI_CAPABILITIES_PAGE_PAD_SIZE 4 - -/* Structure of a MSF cdrom address. */ -struct atapi_msf { - u8 reserved; - u8 minute; - u8 second; - u8 frame; -}; - -/* Space to hold the disk TOC. */ -#define MAX_TRACKS 99 -struct atapi_toc_header { - unsigned short toc_length; - u8 first_track; - u8 last_track; -}; - -struct atapi_toc_entry { - u8 reserved1; -#if defined(__BIG_ENDIAN_BITFIELD) - u8 adr : 4; - u8 control : 4; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - u8 control : 4; - u8 adr : 4; -#else -#error "Please fix " -#endif - u8 track; - u8 reserved2; - union { - unsigned lba; - struct atapi_msf msf; - } addr; -}; - -struct atapi_toc { - int last_session_lba; - int xa_flag; - unsigned long capacity; - struct atapi_toc_header hdr; - struct atapi_toc_entry ent[MAX_TRACKS+1]; - /* One extra for the leadout. */ -}; - -/* Extra per-device info for cdrom drives. */ -struct cdrom_info { - ide_drive_t *drive; - struct ide_driver *driver; - struct gendisk *disk; - struct device dev; - - /* Buffer for table of contents. NULL if we haven't allocated - a TOC buffer for this device yet. */ - - struct atapi_toc *toc; - - u8 max_speed; /* Max speed of the drive. */ - u8 current_speed; /* Current speed of the drive. */ - - /* Per-device info needed by cdrom.c generic driver. */ - struct cdrom_device_info devinfo; - - unsigned long write_timeout; -}; - -/* ide-cd_verbose.c */ -void ide_cd_log_error(const char *, struct request *, struct request_sense *); - -/* ide-cd.c functions used by ide-cd_ioctl.c */ -int ide_cd_queue_pc(ide_drive_t *, const unsigned char *, int, void *, - unsigned *, struct scsi_sense_hdr *, int, req_flags_t); -int ide_cd_read_toc(ide_drive_t *); -int ide_cdrom_get_capabilities(ide_drive_t *, u8 *); -void ide_cdrom_update_speed(ide_drive_t *, u8 *); -int cdrom_check_status(ide_drive_t *, struct scsi_sense_hdr *); - -/* ide-cd_ioctl.c */ -int ide_cdrom_open_real(struct cdrom_device_info *, int); -void ide_cdrom_release_real(struct cdrom_device_info *); -int ide_cdrom_drive_status(struct cdrom_device_info *, int); -unsigned int ide_cdrom_check_events_real(struct cdrom_device_info *, - unsigned int clearing, int slot_nr); -int ide_cdrom_tray_move(struct cdrom_device_info *, int); -int ide_cdrom_lock_door(struct cdrom_device_info *, int); -int ide_cdrom_select_speed(struct cdrom_device_info *, int); -int ide_cdrom_get_last_session(struct cdrom_device_info *, - struct cdrom_multisession *); -int ide_cdrom_get_mcn(struct cdrom_device_info *, struct cdrom_mcn *); -int ide_cdrom_reset(struct cdrom_device_info *cdi); -int ide_cdrom_audio_ioctl(struct cdrom_device_info *, unsigned int, void *); -int ide_cdrom_packet(struct cdrom_device_info *, struct packet_command *); - -#endif /* _IDE_CD_H */ diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c deleted file mode 100644 index 011eab9c69b7..000000000000 --- a/drivers/ide/ide-cd_ioctl.c +++ /dev/null @@ -1,468 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * cdrom.c IOCTLs handling for ide-cd driver. - * - * Copyright (C) 1994-1996 Scott Snyder - * Copyright (C) 1996-1998 Erik Andersen - * Copyright (C) 1998-2000 Jens Axboe - */ - -#include -#include -#include -#include -#include - -#include "ide-cd.h" - -/**************************************************************************** - * Other driver requests (open, close, check media change). - */ -int ide_cdrom_open_real(struct cdrom_device_info *cdi, int purpose) -{ - return 0; -} - -/* - * Close down the device. Invalidate all cached blocks. - */ -void ide_cdrom_release_real(struct cdrom_device_info *cdi) -{ - ide_drive_t *drive = cdi->handle; - - if (!cdi->use_count) - drive->atapi_flags &= ~IDE_AFLAG_TOC_VALID; -} - -/* - * add logic to try GET_EVENT command first to check for media and tray - * status. this should be supported by newer cd-r/w and all DVD etc - * drives - */ -int ide_cdrom_drive_status(struct cdrom_device_info *cdi, int slot_nr) -{ - ide_drive_t *drive = cdi->handle; - struct media_event_desc med; - struct scsi_sense_hdr sshdr; - int stat; - - if (slot_nr != CDSL_CURRENT) - return -EINVAL; - - stat = cdrom_check_status(drive, &sshdr); - if (!stat || sshdr.sense_key == UNIT_ATTENTION) - return CDS_DISC_OK; - - if (!cdrom_get_media_event(cdi, &med)) { - if (med.media_present) - return CDS_DISC_OK; - else if (med.door_open) - return CDS_TRAY_OPEN; - else - return CDS_NO_DISC; - } - - if (sshdr.sense_key == NOT_READY && sshdr.asc == 0x04 - && sshdr.ascq == 0x04) - return CDS_DISC_OK; - - /* - * If not using Mt Fuji extended media tray reports, - * just return TRAY_OPEN since ATAPI doesn't provide - * any other way to detect this... - */ - if (sshdr.sense_key == NOT_READY) { - if (sshdr.asc == 0x3a && sshdr.ascq == 1) - return CDS_NO_DISC; - else - return CDS_TRAY_OPEN; - } - return CDS_DRIVE_NOT_READY; -} - -/* - * ide-cd always generates media changed event if media is missing, which - * makes it impossible to use for proper event reporting, so - * DISK_EVENT_FLAG_UEVENT is cleared in disk->event_flags - * and the following function is used only to trigger - * revalidation and never propagated to userland. - */ -unsigned int ide_cdrom_check_events_real(struct cdrom_device_info *cdi, - unsigned int clearing, int slot_nr) -{ - ide_drive_t *drive = cdi->handle; - int retval; - - if (slot_nr == CDSL_CURRENT) { - (void) cdrom_check_status(drive, NULL); - retval = (drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED) ? 1 : 0; - drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED; - return retval ? DISK_EVENT_MEDIA_CHANGE : 0; - } else { - return 0; - } -} - -/* Eject the disk if EJECTFLAG is 0. - If EJECTFLAG is 1, try to reload the disk. */ -static -int cdrom_eject(ide_drive_t *drive, int ejectflag) -{ - struct cdrom_info *cd = drive->driver_data; - struct cdrom_device_info *cdi = &cd->devinfo; - char loej = 0x02; - unsigned char cmd[BLK_MAX_CDB]; - - if ((drive->atapi_flags & IDE_AFLAG_NO_EJECT) && !ejectflag) - return -EDRIVE_CANT_DO_THIS; - - /* reload fails on some drives, if the tray is locked */ - if ((drive->atapi_flags & IDE_AFLAG_DOOR_LOCKED) && ejectflag) - return 0; - - /* only tell drive to close tray if open, if it can do that */ - if (ejectflag && (cdi->mask & CDC_CLOSE_TRAY)) - loej = 0; - - memset(cmd, 0, BLK_MAX_CDB); - - cmd[0] = GPCMD_START_STOP_UNIT; - cmd[4] = loej | (ejectflag != 0); - - return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, NULL, 0, 0); -} - -/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */ -static -int ide_cd_lockdoor(ide_drive_t *drive, int lockflag) -{ - struct scsi_sense_hdr sshdr; - int stat; - - /* If the drive cannot lock the door, just pretend. */ - if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0) { - stat = 0; - } else { - unsigned char cmd[BLK_MAX_CDB]; - - memset(cmd, 0, BLK_MAX_CDB); - - cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; - cmd[4] = lockflag ? 1 : 0; - - stat = ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, - &sshdr, 0, 0); - } - - /* If we got an illegal field error, the drive - probably cannot lock the door. */ - if (stat != 0 && - sshdr.sense_key == ILLEGAL_REQUEST && - (sshdr.asc == 0x24 || sshdr.asc == 0x20)) { - printk(KERN_ERR "%s: door locking not supported\n", - drive->name); - drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING; - stat = 0; - } - - /* no medium, that's alright. */ - if (stat != 0 && sshdr.sense_key == NOT_READY && sshdr.asc == 0x3a) - stat = 0; - - if (stat == 0) { - if (lockflag) - drive->atapi_flags |= IDE_AFLAG_DOOR_LOCKED; - else - drive->atapi_flags &= ~IDE_AFLAG_DOOR_LOCKED; - } - - return stat; -} - -int ide_cdrom_tray_move(struct cdrom_device_info *cdi, int position) -{ - ide_drive_t *drive = cdi->handle; - - if (position) { - int stat = ide_cd_lockdoor(drive, 0); - - if (stat) - return stat; - } - - return cdrom_eject(drive, !position); -} - -int ide_cdrom_lock_door(struct cdrom_device_info *cdi, int lock) -{ - ide_drive_t *drive = cdi->handle; - - return ide_cd_lockdoor(drive, lock); -} - -/* - * ATAPI devices are free to select the speed you request or any slower - * rate. :-( Requesting too fast a speed will _not_ produce an error. - */ -int ide_cdrom_select_speed(struct cdrom_device_info *cdi, int speed) -{ - ide_drive_t *drive = cdi->handle; - struct cdrom_info *cd = drive->driver_data; - u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE]; - int stat; - unsigned char cmd[BLK_MAX_CDB]; - - if (speed == 0) - speed = 0xffff; /* set to max */ - else - speed *= 177; /* Nx to kbytes/s */ - - memset(cmd, 0, BLK_MAX_CDB); - - cmd[0] = GPCMD_SET_SPEED; - /* Read Drive speed in kbytes/second MSB/LSB */ - cmd[2] = (speed >> 8) & 0xff; - cmd[3] = speed & 0xff; - if ((cdi->mask & (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) != - (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) { - /* Write Drive speed in kbytes/second MSB/LSB */ - cmd[4] = (speed >> 8) & 0xff; - cmd[5] = speed & 0xff; - } - - stat = ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, NULL, 0, 0); - - if (!ide_cdrom_get_capabilities(drive, buf)) { - ide_cdrom_update_speed(drive, buf); - cdi->speed = cd->current_speed; - } - - return 0; -} - -int ide_cdrom_get_last_session(struct cdrom_device_info *cdi, - struct cdrom_multisession *ms_info) -{ - struct atapi_toc *toc; - ide_drive_t *drive = cdi->handle; - struct cdrom_info *info = drive->driver_data; - int ret; - - if ((drive->atapi_flags & IDE_AFLAG_TOC_VALID) == 0 || !info->toc) { - ret = ide_cd_read_toc(drive); - if (ret) - return ret; - } - - toc = info->toc; - ms_info->addr.lba = toc->last_session_lba; - ms_info->xa_flag = toc->xa_flag; - - return 0; -} - -int ide_cdrom_get_mcn(struct cdrom_device_info *cdi, - struct cdrom_mcn *mcn_info) -{ - ide_drive_t *drive = cdi->handle; - int stat, mcnlen; - char buf[24]; - unsigned char cmd[BLK_MAX_CDB]; - unsigned len = sizeof(buf); - - memset(cmd, 0, BLK_MAX_CDB); - - cmd[0] = GPCMD_READ_SUBCHANNEL; - cmd[1] = 2; /* MSF addressing */ - cmd[2] = 0x40; /* request subQ data */ - cmd[3] = 2; /* format */ - cmd[8] = len; - - stat = ide_cd_queue_pc(drive, cmd, 0, buf, &len, NULL, 0, 0); - if (stat) - return stat; - - mcnlen = sizeof(mcn_info->medium_catalog_number) - 1; - memcpy(mcn_info->medium_catalog_number, buf + 9, mcnlen); - mcn_info->medium_catalog_number[mcnlen] = '\0'; - - return 0; -} - -int ide_cdrom_reset(struct cdrom_device_info *cdi) -{ - ide_drive_t *drive = cdi->handle; - struct cdrom_info *cd = drive->driver_data; - struct request *rq; - int ret; - - rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); - ide_req(rq)->type = ATA_PRIV_MISC; - rq->rq_flags = RQF_QUIET; - blk_execute_rq(cd->disk, rq, 0); - ret = scsi_req(rq)->result ? -EIO : 0; - blk_put_request(rq); - /* - * A reset will unlock the door. If it was previously locked, - * lock it again. - */ - if (drive->atapi_flags & IDE_AFLAG_DOOR_LOCKED) - (void)ide_cd_lockdoor(drive, 1); - - return ret; -} - -static int ide_cd_get_toc_entry(ide_drive_t *drive, int track, - struct atapi_toc_entry **ent) -{ - struct cdrom_info *info = drive->driver_data; - struct atapi_toc *toc = info->toc; - int ntracks; - - /* - * don't serve cached data, if the toc isn't valid - */ - if ((drive->atapi_flags & IDE_AFLAG_TOC_VALID) == 0) - return -EINVAL; - - /* Check validity of requested track number. */ - ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; - - if (toc->hdr.first_track == CDROM_LEADOUT) - ntracks = 0; - - if (track == CDROM_LEADOUT) - *ent = &toc->ent[ntracks]; - else if (track < toc->hdr.first_track || track > toc->hdr.last_track) - return -EINVAL; - else - *ent = &toc->ent[track - toc->hdr.first_track]; - - return 0; -} - -static int ide_cd_fake_play_trkind(ide_drive_t *drive, void *arg) -{ - struct cdrom_ti *ti = arg; - struct atapi_toc_entry *first_toc, *last_toc; - unsigned long lba_start, lba_end; - int stat; - unsigned char cmd[BLK_MAX_CDB]; - - stat = ide_cd_get_toc_entry(drive, ti->cdti_trk0, &first_toc); - if (stat) - return stat; - - stat = ide_cd_get_toc_entry(drive, ti->cdti_trk1, &last_toc); - if (stat) - return stat; - - if (ti->cdti_trk1 != CDROM_LEADOUT) - ++last_toc; - lba_start = first_toc->addr.lba; - lba_end = last_toc->addr.lba; - - if (lba_end <= lba_start) - return -EINVAL; - - memset(cmd, 0, BLK_MAX_CDB); - - cmd[0] = GPCMD_PLAY_AUDIO_MSF; - lba_to_msf(lba_start, &cmd[3], &cmd[4], &cmd[5]); - lba_to_msf(lba_end - 1, &cmd[6], &cmd[7], &cmd[8]); - - return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, NULL, 0, 0); -} - -static int ide_cd_read_tochdr(ide_drive_t *drive, void *arg) -{ - struct cdrom_info *cd = drive->driver_data; - struct cdrom_tochdr *tochdr = arg; - struct atapi_toc *toc; - int stat; - - /* Make sure our saved TOC is valid. */ - stat = ide_cd_read_toc(drive); - if (stat) - return stat; - - toc = cd->toc; - tochdr->cdth_trk0 = toc->hdr.first_track; - tochdr->cdth_trk1 = toc->hdr.last_track; - - return 0; -} - -static int ide_cd_read_tocentry(ide_drive_t *drive, void *arg) -{ - struct cdrom_tocentry *tocentry = arg; - struct atapi_toc_entry *toce; - int stat; - - stat = ide_cd_get_toc_entry(drive, tocentry->cdte_track, &toce); - if (stat) - return stat; - - tocentry->cdte_ctrl = toce->control; - tocentry->cdte_adr = toce->adr; - if (tocentry->cdte_format == CDROM_MSF) { - lba_to_msf(toce->addr.lba, - &tocentry->cdte_addr.msf.minute, - &tocentry->cdte_addr.msf.second, - &tocentry->cdte_addr.msf.frame); - } else - tocentry->cdte_addr.lba = toce->addr.lba; - - return 0; -} - -int ide_cdrom_audio_ioctl(struct cdrom_device_info *cdi, - unsigned int cmd, void *arg) -{ - ide_drive_t *drive = cdi->handle; - - switch (cmd) { - /* - * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_10, since - * atapi doesn't support it - */ - case CDROMPLAYTRKIND: - return ide_cd_fake_play_trkind(drive, arg); - case CDROMREADTOCHDR: - return ide_cd_read_tochdr(drive, arg); - case CDROMREADTOCENTRY: - return ide_cd_read_tocentry(drive, arg); - default: - return -EINVAL; - } -} - -/* the generic packet interface to cdrom.c */ -int ide_cdrom_packet(struct cdrom_device_info *cdi, - struct packet_command *cgc) -{ - ide_drive_t *drive = cdi->handle; - req_flags_t flags = 0; - unsigned len = cgc->buflen; - - if (cgc->timeout <= 0) - cgc->timeout = ATAPI_WAIT_PC; - - /* here we queue the commands from the uniform CD-ROM - layer. the packet must be complete, as we do not - touch it at all. */ - - if (cgc->sshdr) - memset(cgc->sshdr, 0, sizeof(*cgc->sshdr)); - - if (cgc->quiet) - flags |= RQF_QUIET; - - cgc->stat = ide_cd_queue_pc(drive, cgc->cmd, - cgc->data_direction == CGC_DATA_WRITE, - cgc->buffer, &len, - cgc->sshdr, cgc->timeout, flags); - if (!cgc->stat) - cgc->buflen -= len; - return cgc->stat; -} diff --git a/drivers/ide/ide-cd_verbose.c b/drivers/ide/ide-cd_verbose.c deleted file mode 100644 index 5ecd5b2f03a3..000000000000 --- a/drivers/ide/ide-cd_verbose.c +++ /dev/null @@ -1,362 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Verbose error logging for ATAPI CD/DVD devices. - * - * Copyright (C) 1994-1996 Scott Snyder - * Copyright (C) 1996-1998 Erik Andersen - * Copyright (C) 1998-2000 Jens Axboe - */ - -#include -#include -#include -#include -#include -#include "ide-cd.h" - -#ifndef CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS -void ide_cd_log_error(const char *name, struct request *failed_command, - struct request_sense *sense) -{ - /* Suppress printing unit attention and `in progress of becoming ready' - errors when we're not being verbose. */ - if (sense->sense_key == UNIT_ATTENTION || - (sense->sense_key == NOT_READY && (sense->asc == 4 || - sense->asc == 0x3a))) - return; - - printk(KERN_ERR "%s: error code: 0x%02x sense_key: 0x%02x " - "asc: 0x%02x ascq: 0x%02x\n", - name, sense->error_code, sense->sense_key, - sense->asc, sense->ascq); -} -#else -/* The generic packet command opcodes for CD/DVD Logical Units, - * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ -static const struct { - unsigned short packet_command; - const char * const text; -} packet_command_texts[] = { - { GPCMD_TEST_UNIT_READY, "Test Unit Ready" }, - { GPCMD_REQUEST_SENSE, "Request Sense" }, - { GPCMD_FORMAT_UNIT, "Format Unit" }, - { GPCMD_INQUIRY, "Inquiry" }, - { GPCMD_START_STOP_UNIT, "Start/Stop Unit" }, - { GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" }, - { GPCMD_READ_FORMAT_CAPACITIES, "Read Format Capacities" }, - { GPCMD_READ_CDVD_CAPACITY, "Read Cd/Dvd Capacity" }, - { GPCMD_READ_10, "Read 10" }, - { GPCMD_WRITE_10, "Write 10" }, - { GPCMD_SEEK, "Seek" }, - { GPCMD_WRITE_AND_VERIFY_10, "Write and Verify 10" }, - { GPCMD_VERIFY_10, "Verify 10" }, - { GPCMD_FLUSH_CACHE, "Flush Cache" }, - { GPCMD_READ_SUBCHANNEL, "Read Subchannel" }, - { GPCMD_READ_TOC_PMA_ATIP, "Read Table of Contents" }, - { GPCMD_READ_HEADER, "Read Header" }, - { GPCMD_PLAY_AUDIO_10, "Play Audio 10" }, - { GPCMD_GET_CONFIGURATION, "Get Configuration" }, - { GPCMD_PLAY_AUDIO_MSF, "Play Audio MSF" }, - { GPCMD_PLAYAUDIO_TI, "Play Audio TrackIndex" }, - { GPCMD_GET_EVENT_STATUS_NOTIFICATION, - "Get Event Status Notification" }, - { GPCMD_PAUSE_RESUME, "Pause/Resume" }, - { GPCMD_STOP_PLAY_SCAN, "Stop Play/Scan" }, - { GPCMD_READ_DISC_INFO, "Read Disc Info" }, - { GPCMD_READ_TRACK_RZONE_INFO, "Read Track Rzone Info" }, - { GPCMD_RESERVE_RZONE_TRACK, "Reserve Rzone Track" }, - { GPCMD_SEND_OPC, "Send OPC" }, - { GPCMD_MODE_SELECT_10, "Mode Select 10" }, - { GPCMD_REPAIR_RZONE_TRACK, "Repair Rzone Track" }, - { GPCMD_MODE_SENSE_10, "Mode Sense 10" }, - { GPCMD_CLOSE_TRACK, "Close Track" }, - { GPCMD_BLANK, "Blank" }, - { GPCMD_SEND_EVENT, "Send Event" }, - { GPCMD_SEND_KEY, "Send Key" }, - { GPCMD_REPORT_KEY, "Report Key" }, - { GPCMD_LOAD_UNLOAD, "Load/Unload" }, - { GPCMD_SET_READ_AHEAD, "Set Read-ahead" }, - { GPCMD_READ_12, "Read 12" }, - { GPCMD_GET_PERFORMANCE, "Get Performance" }, - { GPCMD_SEND_DVD_STRUCTURE, "Send DVD Structure" }, - { GPCMD_READ_DVD_STRUCTURE, "Read DVD Structure" }, - { GPCMD_SET_STREAMING, "Set Streaming" }, - { GPCMD_READ_CD_MSF, "Read CD MSF" }, - { GPCMD_SCAN, "Scan" }, - { GPCMD_SET_SPEED, "Set Speed" }, - { GPCMD_PLAY_CD, "Play CD" }, - { GPCMD_MECHANISM_STATUS, "Mechanism Status" }, - { GPCMD_READ_CD, "Read CD" }, -}; - -/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ -static const char * const sense_key_texts[16] = { - "No sense data", - "Recovered error", - "Not ready", - "Medium error", - "Hardware error", - "Illegal request", - "Unit attention", - "Data protect", - "Blank check", - "(reserved)", - "(reserved)", - "Aborted command", - "(reserved)", - "(reserved)", - "Miscompare", - "(reserved)", -}; - -/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ -static const struct { - unsigned long asc_ascq; - const char * const text; -} sense_data_texts[] = { - { 0x000000, "No additional sense information" }, - { 0x000011, "Play operation in progress" }, - { 0x000012, "Play operation paused" }, - { 0x000013, "Play operation successfully completed" }, - { 0x000014, "Play operation stopped due to error" }, - { 0x000015, "No current audio status to return" }, - { 0x010c0a, "Write error - padding blocks added" }, - { 0x011700, "Recovered data with no error correction applied" }, - { 0x011701, "Recovered data with retries" }, - { 0x011702, "Recovered data with positive head offset" }, - { 0x011703, "Recovered data with negative head offset" }, - { 0x011704, "Recovered data with retries and/or CIRC applied" }, - { 0x011705, "Recovered data using previous sector ID" }, - { 0x011800, "Recovered data with error correction applied" }, - { 0x011801, "Recovered data with error correction and retries applied"}, - { 0x011802, "Recovered data - the data was auto-reallocated" }, - { 0x011803, "Recovered data with CIRC" }, - { 0x011804, "Recovered data with L-EC" }, - { 0x015d00, "Failure prediction threshold exceeded" - " - Predicted logical unit failure" }, - { 0x015d01, "Failure prediction threshold exceeded" - " - Predicted media failure" }, - { 0x015dff, "Failure prediction threshold exceeded - False" }, - { 0x017301, "Power calibration area almost full" }, - { 0x020400, "Logical unit not ready - cause not reportable" }, - /* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */ - { 0x020401, "Logical unit not ready" - " - in progress [sic] of becoming ready" }, - { 0x020402, "Logical unit not ready - initializing command required" }, - { 0x020403, "Logical unit not ready - manual intervention required" }, - { 0x020404, "Logical unit not ready - format in progress" }, - { 0x020407, "Logical unit not ready - operation in progress" }, - { 0x020408, "Logical unit not ready - long write in progress" }, - { 0x020600, "No reference position found (media may be upside down)" }, - { 0x023000, "Incompatible medium installed" }, - { 0x023a00, "Medium not present" }, - { 0x025300, "Media load or eject failed" }, - { 0x025700, "Unable to recover table of contents" }, - { 0x030300, "Peripheral device write fault" }, - { 0x030301, "No write current" }, - { 0x030302, "Excessive write errors" }, - { 0x030c00, "Write error" }, - { 0x030c01, "Write error - Recovered with auto reallocation" }, - { 0x030c02, "Write error - auto reallocation failed" }, - { 0x030c03, "Write error - recommend reassignment" }, - { 0x030c04, "Compression check miscompare error" }, - { 0x030c05, "Data expansion occurred during compress" }, - { 0x030c06, "Block not compressible" }, - { 0x030c07, "Write error - recovery needed" }, - { 0x030c08, "Write error - recovery failed" }, - { 0x030c09, "Write error - loss of streaming" }, - { 0x031100, "Unrecovered read error" }, - { 0x031106, "CIRC unrecovered error" }, - { 0x033101, "Format command failed" }, - { 0x033200, "No defect spare location available" }, - { 0x033201, "Defect list update failure" }, - { 0x035100, "Erase failure" }, - { 0x037200, "Session fixation error" }, - { 0x037201, "Session fixation error writin lead-in" }, - { 0x037202, "Session fixation error writin lead-out" }, - { 0x037300, "CD control error" }, - { 0x037302, "Power calibration area is full" }, - { 0x037303, "Power calibration area error" }, - { 0x037304, "Program memory area / RMA update failure" }, - { 0x037305, "Program memory area / RMA is full" }, - { 0x037306, "Program memory area / RMA is (almost) full" }, - { 0x040200, "No seek complete" }, - { 0x040300, "Write fault" }, - { 0x040900, "Track following error" }, - { 0x040901, "Tracking servo failure" }, - { 0x040902, "Focus servo failure" }, - { 0x040903, "Spindle servo failure" }, - { 0x041500, "Random positioning error" }, - { 0x041501, "Mechanical positioning or changer error" }, - { 0x041502, "Positioning error detected by read of medium" }, - { 0x043c00, "Mechanical positioning or changer error" }, - { 0x044000, "Diagnostic failure on component (ASCQ)" }, - { 0x044400, "Internal CD/DVD logical unit failure" }, - { 0x04b600, "Media load mechanism failed" }, - { 0x051a00, "Parameter list length error" }, - { 0x052000, "Invalid command operation code" }, - { 0x052100, "Logical block address out of range" }, - { 0x052102, "Invalid address for write" }, - { 0x052400, "Invalid field in command packet" }, - { 0x052600, "Invalid field in parameter list" }, - { 0x052601, "Parameter not supported" }, - { 0x052602, "Parameter value invalid" }, - { 0x052700, "Write protected media" }, - { 0x052c00, "Command sequence error" }, - { 0x052c03, "Current program area is not empty" }, - { 0x052c04, "Current program area is empty" }, - { 0x053001, "Cannot read medium - unknown format" }, - { 0x053002, "Cannot read medium - incompatible format" }, - { 0x053900, "Saving parameters not supported" }, - { 0x054e00, "Overlapped commands attempted" }, - { 0x055302, "Medium removal prevented" }, - { 0x055500, "System resource failure" }, - { 0x056300, "End of user area encountered on this track" }, - { 0x056400, "Illegal mode for this track or incompatible medium" }, - { 0x056f00, "Copy protection key exchange failure" - " - Authentication failure" }, - { 0x056f01, "Copy protection key exchange failure - Key not present" }, - { 0x056f02, "Copy protection key exchange failure" - " - Key not established" }, - { 0x056f03, "Read of scrambled sector without authentication" }, - { 0x056f04, "Media region code is mismatched to logical unit" }, - { 0x056f05, "Drive region must be permanent" - " / region reset count error" }, - { 0x057203, "Session fixation error - incomplete track in session" }, - { 0x057204, "Empty or partially written reserved track" }, - { 0x057205, "No more RZONE reservations are allowed" }, - { 0x05bf00, "Loss of streaming" }, - { 0x062800, "Not ready to ready transition, medium may have changed" }, - { 0x062900, "Power on, reset or hardware reset occurred" }, - { 0x062a00, "Parameters changed" }, - { 0x062a01, "Mode parameters changed" }, - { 0x062e00, "Insufficient time for operation" }, - { 0x063f00, "Logical unit operating conditions have changed" }, - { 0x063f01, "Microcode has been changed" }, - { 0x065a00, "Operator request or state change input (unspecified)" }, - { 0x065a01, "Operator medium removal request" }, - { 0x0bb900, "Play operation aborted" }, - /* Here we use 0xff for the key (not a valid key) to signify - * that these can have _any_ key value associated with them... */ - { 0xff0401, "Logical unit is in process of becoming ready" }, - { 0xff0400, "Logical unit not ready, cause not reportable" }, - { 0xff0402, "Logical unit not ready, initializing command required" }, - { 0xff0403, "Logical unit not ready, manual intervention required" }, - { 0xff0500, "Logical unit does not respond to selection" }, - { 0xff0800, "Logical unit communication failure" }, - { 0xff0802, "Logical unit communication parity error" }, - { 0xff0801, "Logical unit communication time-out" }, - { 0xff2500, "Logical unit not supported" }, - { 0xff4c00, "Logical unit failed self-configuration" }, - { 0xff3e00, "Logical unit has not self-configured yet" }, -}; - -void ide_cd_log_error(const char *name, struct request *failed_command, - struct request_sense *sense) -{ - int i; - const char *s = "bad sense key!"; - char buf[80]; - - printk(KERN_ERR "ATAPI device %s:\n", name); - if (sense->error_code == 0x70) - printk(KERN_CONT " Error: "); - else if (sense->error_code == 0x71) - printk(" Deferred Error: "); - else if (sense->error_code == 0x7f) - printk(KERN_CONT " Vendor-specific Error: "); - else - printk(KERN_CONT " Unknown Error Type: "); - - if (sense->sense_key < ARRAY_SIZE(sense_key_texts)) - s = sense_key_texts[sense->sense_key]; - - printk(KERN_CONT "%s -- (Sense key=0x%02x)\n", s, sense->sense_key); - - if (sense->asc == 0x40) { - sprintf(buf, "Diagnostic failure on component 0x%02x", - sense->ascq); - s = buf; - } else { - int lo = 0, mid, hi = ARRAY_SIZE(sense_data_texts); - unsigned long key = (sense->sense_key << 16); - - key |= (sense->asc << 8); - if (!(sense->ascq >= 0x80 && sense->ascq <= 0xdd)) - key |= sense->ascq; - s = NULL; - - while (hi > lo) { - mid = (lo + hi) / 2; - if (sense_data_texts[mid].asc_ascq == key || - sense_data_texts[mid].asc_ascq == (0xff0000|key)) { - s = sense_data_texts[mid].text; - break; - } else if (sense_data_texts[mid].asc_ascq > key) - hi = mid; - else - lo = mid + 1; - } - } - - if (s == NULL) { - if (sense->asc > 0x80) - s = "(vendor-specific error)"; - else - s = "(reserved error code)"; - } - - printk(KERN_ERR " %s -- (asc=0x%02x, ascq=0x%02x)\n", - s, sense->asc, sense->ascq); - - if (failed_command != NULL) { - int lo = 0, mid, hi = ARRAY_SIZE(packet_command_texts); - s = NULL; - - while (hi > lo) { - mid = (lo + hi) / 2; - if (packet_command_texts[mid].packet_command == - scsi_req(failed_command)->cmd[0]) { - s = packet_command_texts[mid].text; - break; - } - if (packet_command_texts[mid].packet_command > - scsi_req(failed_command)->cmd[0]) - hi = mid; - else - lo = mid + 1; - } - - printk(KERN_ERR " The failed \"%s\" packet command " - "was: \n \"", s); - for (i = 0; i < BLK_MAX_CDB; i++) - printk(KERN_CONT "%02x ", scsi_req(failed_command)->cmd[i]); - printk(KERN_CONT "\"\n"); - } - - /* The SKSV bit specifies validity of the sense_key_specific - * in the next two commands. It is bit 7 of the first byte. - * In the case of NOT_READY, if SKSV is set the drive can - * give us nice ETA readings. - */ - if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) { - int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100; - - printk(KERN_ERR " Command is %02d%% complete\n", - progress / 0xffff); - } - - if (sense->sense_key == ILLEGAL_REQUEST && - (sense->sks[0] & 0x80) != 0) { - printk(KERN_ERR " Error in %s byte %d", - (sense->sks[0] & 0x40) != 0 ? - "command packet" : "command data", - (sense->sks[1] << 8) + sense->sks[2]); - - if ((sense->sks[0] & 0x40) != 0) - printk(KERN_CONT " bit %d", sense->sks[0] & 0x07); - - printk(KERN_CONT "\n"); - } -} -#endif diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c deleted file mode 100644 index f1e922e2479a..000000000000 --- a/drivers/ide/ide-cs.c +++ /dev/null @@ -1,364 +0,0 @@ -/*====================================================================== - - A driver for PCMCIA IDE/ATA disk cards - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in - which case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define DRV_NAME "ide-cs" - -/*====================================================================*/ - -/* Module parameters */ - -MODULE_AUTHOR("David Hinds "); -MODULE_DESCRIPTION("PCMCIA ATA/IDE card driver"); -MODULE_LICENSE("Dual MPL/GPL"); - -/*====================================================================*/ - -typedef struct ide_info_t { - struct pcmcia_device *p_dev; - struct ide_host *host; - int ndev; -} ide_info_t; - -static void ide_release(struct pcmcia_device *); -static int ide_config(struct pcmcia_device *); - -static void ide_detach(struct pcmcia_device *p_dev); - -static int ide_probe(struct pcmcia_device *link) -{ - ide_info_t *info; - - dev_dbg(&link->dev, "ide_attach()\n"); - - /* Create new ide device */ - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->p_dev = link; - link->priv = info; - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO | - CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC; - - return ide_config(link); -} /* ide_attach */ - -static void ide_detach(struct pcmcia_device *link) -{ - ide_info_t *info = link->priv; - - dev_dbg(&link->dev, "ide_detach(0x%p)\n", link); - - ide_release(link); - - kfree(info); -} /* ide_detach */ - -static const struct ide_port_ops idecs_port_ops = { - .quirkproc = ide_undecoded_slave, -}; - -static const struct ide_port_info idecs_port_info = { - .port_ops = &idecs_port_ops, - .host_flags = IDE_HFLAG_NO_DMA, - .irq_flags = IRQF_SHARED, - .chipset = ide_pci, -}; - -static struct ide_host *idecs_register(unsigned long io, unsigned long ctl, - unsigned long irq, struct pcmcia_device *handle) -{ - struct ide_host *host; - ide_hwif_t *hwif; - int i, rc; - struct ide_hw hw, *hws[] = { &hw }; - - if (!request_region(io, 8, DRV_NAME)) { - printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n", - DRV_NAME, io, io + 7); - return NULL; - } - - if (!request_region(ctl, 1, DRV_NAME)) { - printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n", - DRV_NAME, ctl); - release_region(io, 8); - return NULL; - } - - memset(&hw, 0, sizeof(hw)); - ide_std_init_ports(&hw, io, ctl); - hw.irq = irq; - hw.dev = &handle->dev; - - rc = ide_host_add(&idecs_port_info, hws, 1, &host); - if (rc) - goto out_release; - - hwif = host->ports[0]; - - if (hwif->present) - return host; - - /* retry registration in case device is still spinning up */ - for (i = 0; i < 10; i++) { - msleep(100); - ide_port_scan(hwif); - if (hwif->present) - return host; - } - - return host; - -out_release: - release_region(ctl, 1); - release_region(io, 8); - return NULL; -} - -static int pcmcia_check_one_config(struct pcmcia_device *pdev, void *priv_data) -{ - int *is_kme = priv_data; - - if ((pdev->resource[0]->flags & IO_DATA_PATH_WIDTH) - != IO_DATA_PATH_WIDTH_8) { - pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - } - pdev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; - pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; - - if (pdev->resource[1]->end) { - pdev->resource[0]->end = 8; - pdev->resource[1]->end = (*is_kme) ? 2 : 1; - } else { - if (pdev->resource[0]->end < 16) - return -ENODEV; - } - - return pcmcia_request_io(pdev); -} - -static int ide_config(struct pcmcia_device *link) -{ - ide_info_t *info = link->priv; - int ret = 0, is_kme = 0; - unsigned long io_base, ctl_base; - struct ide_host *host; - - dev_dbg(&link->dev, "ide_config(0x%p)\n", link); - - is_kme = ((link->manf_id == MANFID_KME) && - ((link->card_id == PRODID_KME_KXLC005_A) || - (link->card_id == PRODID_KME_KXLC005_B))); - - if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme)) { - link->config_flags &= ~CONF_AUTO_CHECK_VCC; - if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme)) - goto failed; /* No suitable config found */ - } - io_base = link->resource[0]->start; - if (link->resource[1]->end) - ctl_base = link->resource[1]->start; - else - ctl_base = link->resource[0]->start + 0x0e; - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - /* disable drive interrupts during IDE probe */ - outb(0x02, ctl_base); - - /* special setup for KXLC005 card */ - if (is_kme) - outb(0x81, ctl_base+1); - - host = idecs_register(io_base, ctl_base, link->irq, link); - if (host == NULL && resource_size(link->resource[0]) == 0x20) { - outb(0x02, ctl_base + 0x10); - host = idecs_register(io_base + 0x10, ctl_base + 0x10, - link->irq, link); - } - - if (host == NULL) - goto failed; - - info->ndev = 1; - info->host = host; - dev_info(&link->dev, "ide-cs: hd%c: Vpp = %d.%d\n", - 'a' + host->ports[0]->index * 2, - link->vpp / 10, link->vpp % 10); - - return 0; - -failed: - ide_release(link); - return -ENODEV; -} /* ide_config */ - -static void ide_release(struct pcmcia_device *link) -{ - ide_info_t *info = link->priv; - struct ide_host *host = info->host; - - dev_dbg(&link->dev, "ide_release(0x%p)\n", link); - - if (info->ndev) { - ide_hwif_t *hwif = host->ports[0]; - unsigned long data_addr, ctl_addr; - - data_addr = hwif->io_ports.data_addr; - ctl_addr = hwif->io_ports.ctl_addr; - - ide_host_remove(host); - info->ndev = 0; - - release_region(ctl_addr, 1); - release_region(data_addr, 8); - } - - pcmcia_disable_device(link); -} /* ide_release */ - - -static const struct pcmcia_device_id ide_ids[] = { - PCMCIA_DEVICE_FUNC_ID(4), - PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000), /* Corsair */ - PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */ - PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000), /* I-O Data CFA */ - PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001), /* Mitsubishi CFA */ - PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704), - PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904), - PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), /* SanDisk CFA */ - PCMCIA_DEVICE_MANF_CARD(0x004f, 0x0000), /* Kingston */ - PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620), /* TI emulated */ - PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */ - PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d), - PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */ - PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */ - PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001), - PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0100), /* Viking CFA */ - PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar, Viking CFA */ - PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0), - PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74), - PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9), - PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591), - PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728), - PCMCIA_DEVICE_PROD_ID12("CNF ", "CD-ROM", 0x46d7db81, 0x66536591), - PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591), - PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4), - PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde), - PCMCIA_DEVICE_PROD_ID12("EXP", "CD+GAME", 0x6f58c983, 0x63c13aaf), - PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591), - PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728), - PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e), - PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae), - PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178), - PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420), - PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178), - PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753), - PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 1GB", 0x2e6d1829, 0x55d5bffb), - PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 4GB", 0x2e6d1829, 0x531e7d10), - PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e), - PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b), - PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149), - PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674), - PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2 ", 0xe37be2b5, 0x8671043b), - PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF300", 0x7ed2ad87, 0x7e9e78ee), - PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c), - PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79), - PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591), - PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728), - PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1), - PCMCIA_DEVICE_PROD_ID12("SEAGATE", "ST1", 0x87c1b330, 0xe1f30883), - PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d), - PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6), - PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003), - PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443), - PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF45", 0x709b1bf1, 0xf68b6f32), - PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1), - PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2), - PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8), - PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF133", 0x709b1bf1, 0x7558f133), - PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS8GCF133", 0x709b1bf1, 0xb2f89b47), - PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852), - PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918), - PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209), - PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e), - PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6), - PCMCIA_DEVICE_PROD_ID2("Flash Card", 0x5a362506), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, ide_ids); - -static struct pcmcia_driver ide_cs_driver = { - .owner = THIS_MODULE, - .name = "ide-cs", - .probe = ide_probe, - .remove = ide_detach, - .id_table = ide_ids, -}; - -static int __init init_ide_cs(void) -{ - return pcmcia_register_driver(&ide_cs_driver); -} - -static void __exit exit_ide_cs(void) -{ - pcmcia_unregister_driver(&ide_cs_driver); -} - -late_initcall(init_ide_cs); -module_exit(exit_ide_cs); diff --git a/drivers/ide/ide-devsets.c b/drivers/ide/ide-devsets.c deleted file mode 100644 index ca1d4b3d3878..000000000000 --- a/drivers/ide/ide-devsets.c +++ /dev/null @@ -1,192 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include - -DEFINE_MUTEX(ide_setting_mtx); - -ide_devset_get(io_32bit, io_32bit); - -static int set_io_32bit(ide_drive_t *drive, int arg) -{ - if (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT) - return -EPERM; - - if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1)) - return -EINVAL; - - drive->io_32bit = arg; - - return 0; -} - -ide_devset_get_flag(ksettings, IDE_DFLAG_KEEP_SETTINGS); - -static int set_ksettings(ide_drive_t *drive, int arg) -{ - if (arg < 0 || arg > 1) - return -EINVAL; - - if (arg) - drive->dev_flags |= IDE_DFLAG_KEEP_SETTINGS; - else - drive->dev_flags &= ~IDE_DFLAG_KEEP_SETTINGS; - - return 0; -} - -ide_devset_get_flag(using_dma, IDE_DFLAG_USING_DMA); - -static int set_using_dma(ide_drive_t *drive, int arg) -{ -#ifdef CONFIG_BLK_DEV_IDEDMA - int err = -EPERM; - - if (arg < 0 || arg > 1) - return -EINVAL; - - if (ata_id_has_dma(drive->id) == 0) - goto out; - - if (drive->hwif->dma_ops == NULL) - goto out; - - err = 0; - - if (arg) { - if (ide_set_dma(drive)) - err = -EIO; - } else - ide_dma_off(drive); - -out: - return err; -#else - if (arg < 0 || arg > 1) - return -EINVAL; - - return -EPERM; -#endif -} - -/* - * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away - */ -static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio) -{ - switch (req_pio) { - case 202: - case 201: - case 200: - case 102: - case 101: - case 100: - return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0; - case 9: - case 8: - return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0; - case 7: - case 6: - return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0; - default: - return 0; - } -} - -static int set_pio_mode(ide_drive_t *drive, int arg) -{ - ide_hwif_t *hwif = drive->hwif; - const struct ide_port_ops *port_ops = hwif->port_ops; - - if (arg < 0 || arg > 255) - return -EINVAL; - - if (port_ops == NULL || port_ops->set_pio_mode == NULL || - (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)) - return -ENOSYS; - - if (set_pio_mode_abuse(drive->hwif, arg)) { - drive->pio_mode = arg + XFER_PIO_0; - - if (arg == 8 || arg == 9) { - unsigned long flags; - - /* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */ - spin_lock_irqsave(&hwif->lock, flags); - port_ops->set_pio_mode(hwif, drive); - spin_unlock_irqrestore(&hwif->lock, flags); - } else - port_ops->set_pio_mode(hwif, drive); - } else { - int keep_dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); - - ide_set_pio(drive, arg); - - if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) { - if (keep_dma) - ide_dma_on(drive); - } - } - - return 0; -} - -ide_devset_get_flag(unmaskirq, IDE_DFLAG_UNMASK); - -static int set_unmaskirq(ide_drive_t *drive, int arg) -{ - if (drive->dev_flags & IDE_DFLAG_NO_UNMASK) - return -EPERM; - - if (arg < 0 || arg > 1) - return -EINVAL; - - if (arg) - drive->dev_flags |= IDE_DFLAG_UNMASK; - else - drive->dev_flags &= ~IDE_DFLAG_UNMASK; - - return 0; -} - -ide_ext_devset_rw_sync(io_32bit, io_32bit); -ide_ext_devset_rw_sync(keepsettings, ksettings); -ide_ext_devset_rw_sync(unmaskirq, unmaskirq); -ide_ext_devset_rw_sync(using_dma, using_dma); -__IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode); - -int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting, - int arg) -{ - struct request_queue *q = drive->queue; - struct request *rq; - int ret = 0; - - if (!(setting->flags & DS_SYNC)) - return setting->set(drive, arg); - - rq = blk_get_request(q, REQ_OP_DRV_IN, 0); - ide_req(rq)->type = ATA_PRIV_MISC; - scsi_req(rq)->cmd_len = 5; - scsi_req(rq)->cmd[0] = REQ_DEVSET_EXEC; - *(int *)&scsi_req(rq)->cmd[1] = arg; - ide_req(rq)->special = setting->set; - - blk_execute_rq(NULL, rq, 0); - ret = scsi_req(rq)->result; - blk_put_request(rq); - - return ret; -} - -ide_startstop_t ide_do_devset(ide_drive_t *drive, struct request *rq) -{ - int err, (*setfunc)(ide_drive_t *, int) = ide_req(rq)->special; - - err = setfunc(drive, *(int *)&scsi_req(rq)->cmd[1]); - if (err) - scsi_req(rq)->result = err; - ide_complete_rq(drive, 0, blk_rq_bytes(rq)); - return ide_stopped; -} diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c deleted file mode 100644 index 8413731c6259..000000000000 --- a/drivers/ide/ide-disk.c +++ /dev/null @@ -1,795 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) - * Copyright (C) 1998-2002 Linux ATA Development - * Andre Hedrick - * Copyright (C) 2003 Red Hat - * Copyright (C) 2003-2005, 2007 Bartlomiej Zolnierkiewicz - */ - -/* - * Mostly written by Mark Lord - * and Gadi Oxman - * and Andre Hedrick - * - * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "ide-disk.h" - -static const u8 ide_rw_cmds[] = { - ATA_CMD_READ_MULTI, - ATA_CMD_WRITE_MULTI, - ATA_CMD_READ_MULTI_EXT, - ATA_CMD_WRITE_MULTI_EXT, - ATA_CMD_PIO_READ, - ATA_CMD_PIO_WRITE, - ATA_CMD_PIO_READ_EXT, - ATA_CMD_PIO_WRITE_EXT, - ATA_CMD_READ, - ATA_CMD_WRITE, - ATA_CMD_READ_EXT, - ATA_CMD_WRITE_EXT, -}; - -static void ide_tf_set_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 dma) -{ - u8 index, lba48, write; - - lba48 = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0; - write = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0; - - if (dma) { - cmd->protocol = ATA_PROT_DMA; - index = 8; - } else { - cmd->protocol = ATA_PROT_PIO; - if (drive->mult_count) { - cmd->tf_flags |= IDE_TFLAG_MULTI_PIO; - index = 0; - } else - index = 4; - } - - cmd->tf.command = ide_rw_cmds[index + lba48 + write]; -} - -/* - * __ide_do_rw_disk() issues READ and WRITE commands to a disk, - * using LBA if supported, or CHS otherwise, to address sectors. - */ -static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, - sector_t block) -{ - ide_hwif_t *hwif = drive->hwif; - u16 nsectors = (u16)blk_rq_sectors(rq); - u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48); - u8 dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); - struct ide_cmd cmd; - struct ide_taskfile *tf = &cmd.tf; - ide_startstop_t rc; - - if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) { - if (block + blk_rq_sectors(rq) > 1ULL << 28) - dma = 0; - else - lba48 = 0; - } - - memset(&cmd, 0, sizeof(cmd)); - cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - - if (drive->dev_flags & IDE_DFLAG_LBA) { - if (lba48) { - pr_debug("%s: LBA=0x%012llx\n", drive->name, - (unsigned long long)block); - - tf->nsect = nsectors & 0xff; - tf->lbal = (u8) block; - tf->lbam = (u8)(block >> 8); - tf->lbah = (u8)(block >> 16); - tf->device = ATA_LBA; - - tf = &cmd.hob; - tf->nsect = (nsectors >> 8) & 0xff; - tf->lbal = (u8)(block >> 24); - if (sizeof(block) != 4) { - tf->lbam = (u8)((u64)block >> 32); - tf->lbah = (u8)((u64)block >> 40); - } - - cmd.valid.out.hob = IDE_VALID_OUT_HOB; - cmd.valid.in.hob = IDE_VALID_IN_HOB; - cmd.tf_flags |= IDE_TFLAG_LBA48; - } else { - tf->nsect = nsectors & 0xff; - tf->lbal = block; - tf->lbam = block >>= 8; - tf->lbah = block >>= 8; - tf->device = ((block >> 8) & 0xf) | ATA_LBA; - } - } else { - unsigned int sect, head, cyl, track; - - track = (int)block / drive->sect; - sect = (int)block % drive->sect + 1; - head = track % drive->head; - cyl = track / drive->head; - - pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect); - - tf->nsect = nsectors & 0xff; - tf->lbal = sect; - tf->lbam = cyl; - tf->lbah = cyl >> 8; - tf->device = head; - } - - cmd.tf_flags |= IDE_TFLAG_FS; - - if (rq_data_dir(rq)) - cmd.tf_flags |= IDE_TFLAG_WRITE; - - ide_tf_set_cmd(drive, &cmd, dma); - cmd.rq = rq; - - if (dma == 0) { - ide_init_sg_cmd(&cmd, nsectors << 9); - ide_map_sg(drive, &cmd); - } - - rc = do_rw_taskfile(drive, &cmd); - - if (rc == ide_stopped && dma) { - /* fallback to PIO */ - cmd.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK; - ide_tf_set_cmd(drive, &cmd, 0); - ide_init_sg_cmd(&cmd, nsectors << 9); - rc = do_rw_taskfile(drive, &cmd); - } - - return rc; -} - -/* - * 268435455 == 137439 MB or 28bit limit - * 320173056 == 163929 MB or 48bit addressing - * 1073741822 == 549756 MB or 48bit addressing fake drive - */ - -static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq, - sector_t block) -{ - ide_hwif_t *hwif = drive->hwif; - - BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED); - BUG_ON(blk_rq_is_passthrough(rq)); - - ledtrig_disk_activity(rq_data_dir(rq) == WRITE); - - pr_debug("%s: %sing: block=%llu, sectors=%u\n", - drive->name, rq_data_dir(rq) == READ ? "read" : "writ", - (unsigned long long)block, blk_rq_sectors(rq)); - - if (hwif->rw_disk) - hwif->rw_disk(drive, rq); - - return __ide_do_rw_disk(drive, rq, block); -} - -/* - * Queries for true maximum capacity of the drive. - * Returns maximum LBA address (> 0) of the drive, 0 if failed. - */ -static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48) -{ - struct ide_cmd cmd; - struct ide_taskfile *tf = &cmd.tf; - u64 addr = 0; - - memset(&cmd, 0, sizeof(cmd)); - if (lba48) - tf->command = ATA_CMD_READ_NATIVE_MAX_EXT; - else - tf->command = ATA_CMD_READ_NATIVE_MAX; - tf->device = ATA_LBA; - - cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - if (lba48) { - cmd.valid.out.hob = IDE_VALID_OUT_HOB; - cmd.valid.in.hob = IDE_VALID_IN_HOB; - cmd.tf_flags = IDE_TFLAG_LBA48; - } - - ide_no_data_taskfile(drive, &cmd); - - /* if OK, compute maximum address value */ - if (!(tf->status & ATA_ERR)) - addr = ide_get_lba_addr(&cmd, lba48) + 1; - - return addr; -} - -/* - * Sets maximum virtual LBA address of the drive. - * Returns new maximum virtual LBA address (> 0) or 0 on failure. - */ -static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48) -{ - struct ide_cmd cmd; - struct ide_taskfile *tf = &cmd.tf; - u64 addr_set = 0; - - addr_req--; - - memset(&cmd, 0, sizeof(cmd)); - tf->lbal = (addr_req >> 0) & 0xff; - tf->lbam = (addr_req >>= 8) & 0xff; - tf->lbah = (addr_req >>= 8) & 0xff; - if (lba48) { - cmd.hob.lbal = (addr_req >>= 8) & 0xff; - cmd.hob.lbam = (addr_req >>= 8) & 0xff; - cmd.hob.lbah = (addr_req >>= 8) & 0xff; - tf->command = ATA_CMD_SET_MAX_EXT; - } else { - tf->device = (addr_req >>= 8) & 0x0f; - tf->command = ATA_CMD_SET_MAX; - } - tf->device |= ATA_LBA; - - cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - if (lba48) { - cmd.valid.out.hob = IDE_VALID_OUT_HOB; - cmd.valid.in.hob = IDE_VALID_IN_HOB; - cmd.tf_flags = IDE_TFLAG_LBA48; - } - - ide_no_data_taskfile(drive, &cmd); - - /* if OK, compute maximum address value */ - if (!(tf->status & ATA_ERR)) - addr_set = ide_get_lba_addr(&cmd, lba48) + 1; - - return addr_set; -} - -static unsigned long long sectors_to_MB(unsigned long long n) -{ - n <<= 9; /* make it bytes */ - do_div(n, 1000000); /* make it MB */ - return n; -} - -/* - * Some disks report total number of sectors instead of - * maximum sector address. We list them here. - */ -static const struct drive_list_entry hpa_list[] = { - { "ST340823A", NULL }, - { "ST320413A", NULL }, - { "ST310211A", NULL }, - { NULL, NULL } -}; - -static u64 ide_disk_hpa_get_native_capacity(ide_drive_t *drive, int lba48) -{ - u64 capacity, set_max; - - capacity = drive->capacity64; - set_max = idedisk_read_native_max_address(drive, lba48); - - if (ide_in_drive_list(drive->id, hpa_list)) { - /* - * Since we are inclusive wrt to firmware revisions do this - * extra check and apply the workaround only when needed. - */ - if (set_max == capacity + 1) - set_max--; - } - - return set_max; -} - -static u64 ide_disk_hpa_set_capacity(ide_drive_t *drive, u64 set_max, int lba48) -{ - set_max = idedisk_set_max_address(drive, set_max, lba48); - if (set_max) - drive->capacity64 = set_max; - - return set_max; -} - -static void idedisk_check_hpa(ide_drive_t *drive) -{ - u64 capacity, set_max; - int lba48 = ata_id_lba48_enabled(drive->id); - - capacity = drive->capacity64; - set_max = ide_disk_hpa_get_native_capacity(drive, lba48); - - if (set_max <= capacity) - return; - - drive->probed_capacity = set_max; - - printk(KERN_INFO "%s: Host Protected Area detected.\n" - "\tcurrent capacity is %llu sectors (%llu MB)\n" - "\tnative capacity is %llu sectors (%llu MB)\n", - drive->name, - capacity, sectors_to_MB(capacity), - set_max, sectors_to_MB(set_max)); - - if ((drive->dev_flags & IDE_DFLAG_NOHPA) == 0) - return; - - set_max = ide_disk_hpa_set_capacity(drive, set_max, lba48); - if (set_max) - printk(KERN_INFO "%s: Host Protected Area disabled.\n", - drive->name); -} - -static int ide_disk_get_capacity(ide_drive_t *drive) -{ - u16 *id = drive->id; - int lba; - - if (ata_id_lba48_enabled(id)) { - /* drive speaks 48-bit LBA */ - lba = 1; - drive->capacity64 = ata_id_u64(id, ATA_ID_LBA_CAPACITY_2); - } else if (ata_id_has_lba(id) && ata_id_is_lba_capacity_ok(id)) { - /* drive speaks 28-bit LBA */ - lba = 1; - drive->capacity64 = ata_id_u32(id, ATA_ID_LBA_CAPACITY); - } else { - /* drive speaks boring old 28-bit CHS */ - lba = 0; - drive->capacity64 = drive->cyl * drive->head * drive->sect; - } - - drive->probed_capacity = drive->capacity64; - - if (lba) { - drive->dev_flags |= IDE_DFLAG_LBA; - - /* - * If this device supports the Host Protected Area feature set, - * then we may need to change our opinion about its capacity. - */ - if (ata_id_hpa_enabled(id)) - idedisk_check_hpa(drive); - } - - /* limit drive capacity to 137GB if LBA48 cannot be used */ - if ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 && - drive->capacity64 > 1ULL << 28) { - printk(KERN_WARNING "%s: cannot use LBA48 - full capacity " - "%llu sectors (%llu MB)\n", - drive->name, (unsigned long long)drive->capacity64, - sectors_to_MB(drive->capacity64)); - drive->probed_capacity = drive->capacity64 = 1ULL << 28; - } - - if ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && - (drive->dev_flags & IDE_DFLAG_LBA48)) { - if (drive->capacity64 > 1ULL << 28) { - printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode" - " will be used for accessing sectors " - "> %u\n", drive->name, 1 << 28); - } else - drive->dev_flags &= ~IDE_DFLAG_LBA48; - } - - return 0; -} - -static void ide_disk_unlock_native_capacity(ide_drive_t *drive) -{ - u16 *id = drive->id; - int lba48 = ata_id_lba48_enabled(id); - - if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 || - ata_id_hpa_enabled(id) == 0) - return; - - /* - * according to the spec the SET MAX ADDRESS command shall be - * immediately preceded by a READ NATIVE MAX ADDRESS command - */ - if (!ide_disk_hpa_get_native_capacity(drive, lba48)) - return; - - if (ide_disk_hpa_set_capacity(drive, drive->probed_capacity, lba48)) - drive->dev_flags |= IDE_DFLAG_NOHPA; /* disable HPA on resume */ -} - -static bool idedisk_prep_rq(ide_drive_t *drive, struct request *rq) -{ - struct ide_cmd *cmd; - - if (req_op(rq) != REQ_OP_FLUSH) - return true; - - if (ide_req(rq)->special) { - cmd = ide_req(rq)->special; - memset(cmd, 0, sizeof(*cmd)); - } else { - cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); - } - - /* FIXME: map struct ide_taskfile on rq->cmd[] */ - BUG_ON(cmd == NULL); - - if (ata_id_flush_ext_enabled(drive->id) && - (drive->capacity64 >= (1UL << 28))) - cmd->tf.command = ATA_CMD_FLUSH_EXT; - else - cmd->tf.command = ATA_CMD_FLUSH; - cmd->valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd->tf_flags = IDE_TFLAG_DYN; - cmd->protocol = ATA_PROT_NODATA; - rq->cmd_flags &= ~REQ_OP_MASK; - rq->cmd_flags |= REQ_OP_DRV_OUT; - ide_req(rq)->type = ATA_PRIV_TASKFILE; - ide_req(rq)->special = cmd; - cmd->rq = rq; - - return true; -} - -ide_devset_get(multcount, mult_count); - -/* - * This is tightly woven into the driver->do_special can not touch. - * DON'T do it again until a total personality rewrite is committed. - */ -static int set_multcount(ide_drive_t *drive, int arg) -{ - struct request *rq; - - if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff)) - return -EINVAL; - - if (drive->special_flags & IDE_SFLAG_SET_MULTMODE) - return -EBUSY; - - rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); - ide_req(rq)->type = ATA_PRIV_TASKFILE; - - drive->mult_req = arg; - drive->special_flags |= IDE_SFLAG_SET_MULTMODE; - blk_execute_rq(NULL, rq, 0); - blk_put_request(rq); - - return (drive->mult_count == arg) ? 0 : -EIO; -} - -ide_devset_get_flag(nowerr, IDE_DFLAG_NOWERR); - -static int set_nowerr(ide_drive_t *drive, int arg) -{ - if (arg < 0 || arg > 1) - return -EINVAL; - - if (arg) - drive->dev_flags |= IDE_DFLAG_NOWERR; - else - drive->dev_flags &= ~IDE_DFLAG_NOWERR; - - drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; - - return 0; -} - -static int ide_do_setfeature(ide_drive_t *drive, u8 feature, u8 nsect) -{ - struct ide_cmd cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.tf.feature = feature; - cmd.tf.nsect = nsect; - cmd.tf.command = ATA_CMD_SET_FEATURES; - cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - - return ide_no_data_taskfile(drive, &cmd); -} - -static void update_flush(ide_drive_t *drive) -{ - u16 *id = drive->id; - bool wc = false; - - if (drive->dev_flags & IDE_DFLAG_WCACHE) { - unsigned long long capacity; - int barrier; - /* - * We must avoid issuing commands a drive does not - * understand or we may crash it. We check flush cache - * is supported. We also check we have the LBA48 flush - * cache if the drive capacity is too large. By this - * time we have trimmed the drive capacity if LBA48 is - * not available so we don't need to recheck that. - */ - capacity = ide_gd_capacity(drive); - barrier = ata_id_flush_enabled(id) && - (drive->dev_flags & IDE_DFLAG_NOFLUSH) == 0 && - ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 || - capacity <= (1ULL << 28) || - ata_id_flush_ext_enabled(id)); - - printk(KERN_INFO "%s: cache flushes %ssupported\n", - drive->name, barrier ? "" : "not "); - - if (barrier) { - wc = true; - drive->prep_rq = idedisk_prep_rq; - } - } - - blk_queue_write_cache(drive->queue, wc, false); -} - -ide_devset_get_flag(wcache, IDE_DFLAG_WCACHE); - -static int set_wcache(ide_drive_t *drive, int arg) -{ - int err = 1; - - if (arg < 0 || arg > 1) - return -EINVAL; - - if (ata_id_flush_enabled(drive->id)) { - err = ide_do_setfeature(drive, - arg ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF, 0); - if (err == 0) { - if (arg) - drive->dev_flags |= IDE_DFLAG_WCACHE; - else - drive->dev_flags &= ~IDE_DFLAG_WCACHE; - } - } - - update_flush(drive); - - return err; -} - -static int do_idedisk_flushcache(ide_drive_t *drive) -{ - struct ide_cmd cmd; - - memset(&cmd, 0, sizeof(cmd)); - if (ata_id_flush_ext_enabled(drive->id)) - cmd.tf.command = ATA_CMD_FLUSH_EXT; - else - cmd.tf.command = ATA_CMD_FLUSH; - cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - - return ide_no_data_taskfile(drive, &cmd); -} - -ide_devset_get(acoustic, acoustic); - -static int set_acoustic(ide_drive_t *drive, int arg) -{ - if (arg < 0 || arg > 254) - return -EINVAL; - - ide_do_setfeature(drive, - arg ? SETFEATURES_AAM_ON : SETFEATURES_AAM_OFF, arg); - - drive->acoustic = arg; - - return 0; -} - -ide_devset_get_flag(addressing, IDE_DFLAG_LBA48); - -/* - * drive->addressing: - * 0: 28-bit - * 1: 48-bit - * 2: 48-bit capable doing 28-bit - */ -static int set_addressing(ide_drive_t *drive, int arg) -{ - if (arg < 0 || arg > 2) - return -EINVAL; - - if (arg && ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48) || - ata_id_lba48_enabled(drive->id) == 0)) - return -EIO; - - if (arg == 2) - arg = 0; - - if (arg) - drive->dev_flags |= IDE_DFLAG_LBA48; - else - drive->dev_flags &= ~IDE_DFLAG_LBA48; - - return 0; -} - -ide_ext_devset_rw(acoustic, acoustic); -ide_ext_devset_rw(address, addressing); -ide_ext_devset_rw(multcount, multcount); -ide_ext_devset_rw(wcache, wcache); - -ide_ext_devset_rw_sync(nowerr, nowerr); - -static int ide_disk_check(ide_drive_t *drive, const char *s) -{ - return 1; -} - -static void ide_disk_setup(ide_drive_t *drive) -{ - struct ide_disk_obj *idkp = drive->driver_data; - struct request_queue *q = drive->queue; - ide_hwif_t *hwif = drive->hwif; - u16 *id = drive->id; - char *m = (char *)&id[ATA_ID_PROD]; - unsigned long long capacity; - - ide_proc_register_driver(drive, idkp->driver); - - if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) - return; - - if (drive->dev_flags & IDE_DFLAG_REMOVABLE) { - /* - * Removable disks (eg. SYQUEST); ignore 'WD' drives - */ - if (m[0] != 'W' || m[1] != 'D') - drive->dev_flags |= IDE_DFLAG_DOORLOCKING; - } - - (void)set_addressing(drive, 1); - - if (drive->dev_flags & IDE_DFLAG_LBA48) { - int max_s = 2048; - - if (max_s > hwif->rqsize) - max_s = hwif->rqsize; - - blk_queue_max_hw_sectors(q, max_s); - } - - printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name, - queue_max_sectors(q) / 2); - - if (ata_id_is_ssd(id)) { - blk_queue_flag_set(QUEUE_FLAG_NONROT, q); - blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q); - } - - /* calculate drive capacity, and select LBA if possible */ - ide_disk_get_capacity(drive); - - /* - * if possible, give fdisk access to more of the drive, - * by correcting bios_cyls: - */ - capacity = ide_gd_capacity(drive); - - if ((drive->dev_flags & IDE_DFLAG_FORCED_GEOM) == 0) { - if (ata_id_lba48_enabled(drive->id)) { - /* compatibility */ - drive->bios_sect = 63; - drive->bios_head = 255; - } - - if (drive->bios_sect && drive->bios_head) { - unsigned int cap0 = capacity; /* truncate to 32 bits */ - unsigned int cylsz, cyl; - - if (cap0 != capacity) - drive->bios_cyl = 65535; - else { - cylsz = drive->bios_sect * drive->bios_head; - cyl = cap0 / cylsz; - if (cyl > 65535) - cyl = 65535; - if (cyl > drive->bios_cyl) - drive->bios_cyl = cyl; - } - } - } - printk(KERN_INFO "%s: %llu sectors (%llu MB)", - drive->name, capacity, sectors_to_MB(capacity)); - - /* Only print cache size when it was specified */ - if (id[ATA_ID_BUF_SIZE]) - printk(KERN_CONT " w/%dKiB Cache", id[ATA_ID_BUF_SIZE] / 2); - - printk(KERN_CONT ", CHS=%d/%d/%d\n", - drive->bios_cyl, drive->bios_head, drive->bios_sect); - - /* write cache enabled? */ - if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id)) - drive->dev_flags |= IDE_DFLAG_WCACHE; - - set_wcache(drive, 1); - - if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 && - (drive->head == 0 || drive->head > 16)) - printk(KERN_ERR "%s: invalid geometry: %d physical heads?\n", - drive->name, drive->head); -} - -static void ide_disk_flush(ide_drive_t *drive) -{ - if (ata_id_flush_enabled(drive->id) == 0 || - (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) - return; - - if (do_idedisk_flushcache(drive)) - printk(KERN_INFO "%s: wcache flush failed!\n", drive->name); -} - -static int ide_disk_init_media(ide_drive_t *drive, struct gendisk *disk) -{ - return 0; -} - -static int ide_disk_set_doorlock(ide_drive_t *drive, struct gendisk *disk, - int on) -{ - struct ide_cmd cmd; - int ret; - - if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0) - return 0; - - memset(&cmd, 0, sizeof(cmd)); - cmd.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK; - cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - - ret = ide_no_data_taskfile(drive, &cmd); - - if (ret) - drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING; - - return ret; -} - -const struct ide_disk_ops ide_ata_disk_ops = { - .check = ide_disk_check, - .unlock_native_capacity = ide_disk_unlock_native_capacity, - .get_capacity = ide_disk_get_capacity, - .setup = ide_disk_setup, - .flush = ide_disk_flush, - .init_media = ide_disk_init_media, - .set_doorlock = ide_disk_set_doorlock, - .do_request = ide_do_rw_disk, - .ioctl = ide_disk_ioctl, - .compat_ioctl = ide_disk_ioctl, -}; diff --git a/drivers/ide/ide-disk.h b/drivers/ide/ide-disk.h deleted file mode 100644 index 0e8cc18bfda6..000000000000 --- a/drivers/ide/ide-disk.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __IDE_DISK_H -#define __IDE_DISK_H - -#include "ide-gd.h" - -#ifdef CONFIG_IDE_GD_ATA -/* ide-disk.c */ -extern const struct ide_disk_ops ide_ata_disk_ops; -ide_decl_devset(address); -ide_decl_devset(multcount); -ide_decl_devset(nowerr); -ide_decl_devset(wcache); -ide_decl_devset(acoustic); - -/* ide-disk_ioctl.c */ -int ide_disk_ioctl(ide_drive_t *, struct block_device *, fmode_t, unsigned int, - unsigned long); - -#ifdef CONFIG_IDE_PROC_FS -/* ide-disk_proc.c */ -extern ide_proc_entry_t ide_disk_proc[]; -extern const struct ide_proc_devset ide_disk_settings[]; -#endif -#else -#define ide_disk_proc NULL -#define ide_disk_settings NULL -#endif - -#endif /* __IDE_DISK_H */ diff --git a/drivers/ide/ide-disk_ioctl.c b/drivers/ide/ide-disk_ioctl.c deleted file mode 100644 index 2c45616cff4f..000000000000 --- a/drivers/ide/ide-disk_ioctl.c +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include - -#include "ide-disk.h" - -static DEFINE_MUTEX(ide_disk_ioctl_mutex); -static const struct ide_ioctl_devset ide_disk_ioctl_settings[] = { -{ HDIO_GET_ADDRESS, HDIO_SET_ADDRESS, &ide_devset_address }, -{ HDIO_GET_MULTCOUNT, HDIO_SET_MULTCOUNT, &ide_devset_multcount }, -{ HDIO_GET_NOWERR, HDIO_SET_NOWERR, &ide_devset_nowerr }, -{ HDIO_GET_WCACHE, HDIO_SET_WCACHE, &ide_devset_wcache }, -{ HDIO_GET_ACOUSTIC, HDIO_SET_ACOUSTIC, &ide_devset_acoustic }, -{ 0 } -}; - -int ide_disk_ioctl(ide_drive_t *drive, struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - int err; - - mutex_lock(&ide_disk_ioctl_mutex); - err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings); - if (err != -EOPNOTSUPP) - goto out; - - err = generic_ide_ioctl(drive, bdev, cmd, arg); -out: - mutex_unlock(&ide_disk_ioctl_mutex); - return err; -} diff --git a/drivers/ide/ide-disk_proc.c b/drivers/ide/ide-disk_proc.c deleted file mode 100644 index 95d239b2f646..000000000000 --- a/drivers/ide/ide-disk_proc.c +++ /dev/null @@ -1,125 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include - -#include "ide-disk.h" - -static int smart_enable(ide_drive_t *drive) -{ - struct ide_cmd cmd; - struct ide_taskfile *tf = &cmd.tf; - - memset(&cmd, 0, sizeof(cmd)); - tf->feature = ATA_SMART_ENABLE; - tf->lbam = ATA_SMART_LBAM_PASS; - tf->lbah = ATA_SMART_LBAH_PASS; - tf->command = ATA_CMD_SMART; - cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - - return ide_no_data_taskfile(drive, &cmd); -} - -static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd) -{ - struct ide_cmd cmd; - struct ide_taskfile *tf = &cmd.tf; - - memset(&cmd, 0, sizeof(cmd)); - tf->feature = sub_cmd; - tf->nsect = 0x01; - tf->lbam = ATA_SMART_LBAM_PASS; - tf->lbah = ATA_SMART_LBAH_PASS; - tf->command = ATA_CMD_SMART; - cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - cmd.protocol = ATA_PROT_PIO; - - return ide_raw_taskfile(drive, &cmd, buf, 1); -} - -static int idedisk_cache_proc_show(struct seq_file *m, void *v) -{ - ide_drive_t *drive = (ide_drive_t *) m->private; - - if (drive->dev_flags & IDE_DFLAG_ID_READ) - seq_printf(m, "%i\n", drive->id[ATA_ID_BUF_SIZE] / 2); - else - seq_printf(m, "(none)\n"); - return 0; -} - -static int idedisk_capacity_proc_show(struct seq_file *m, void *v) -{ - ide_drive_t*drive = (ide_drive_t *)m->private; - - seq_printf(m, "%llu\n", (long long)ide_gd_capacity(drive)); - return 0; -} - -static int __idedisk_proc_show(struct seq_file *m, ide_drive_t *drive, u8 sub_cmd) -{ - u8 *buf; - - buf = kmalloc(SECTOR_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - (void)smart_enable(drive); - - if (get_smart_data(drive, buf, sub_cmd) == 0) { - __le16 *val = (__le16 *)buf; - int i; - - for (i = 0; i < SECTOR_SIZE / 2; i++) { - seq_printf(m, "%04x%c", le16_to_cpu(val[i]), - (i % 8) == 7 ? '\n' : ' '); - } - } - kfree(buf); - return 0; -} - -static int idedisk_sv_proc_show(struct seq_file *m, void *v) -{ - return __idedisk_proc_show(m, m->private, ATA_SMART_READ_VALUES); -} - -static int idedisk_st_proc_show(struct seq_file *m, void *v) -{ - return __idedisk_proc_show(m, m->private, ATA_SMART_READ_THRESHOLDS); -} - -ide_proc_entry_t ide_disk_proc[] = { - { "cache", S_IFREG|S_IRUGO, idedisk_cache_proc_show }, - { "capacity", S_IFREG|S_IRUGO, idedisk_capacity_proc_show }, - { "geometry", S_IFREG|S_IRUGO, ide_geometry_proc_show }, - { "smart_values", S_IFREG|S_IRUSR, idedisk_sv_proc_show }, - { "smart_thresholds", S_IFREG|S_IRUSR, idedisk_st_proc_show }, - {} -}; - -ide_devset_rw_field(bios_cyl, bios_cyl); -ide_devset_rw_field(bios_head, bios_head); -ide_devset_rw_field(bios_sect, bios_sect); -ide_devset_rw_field(failures, failures); -ide_devset_rw_field(lun, lun); -ide_devset_rw_field(max_failures, max_failures); - -const struct ide_proc_devset ide_disk_settings[] = { - IDE_PROC_DEVSET(acoustic, 0, 254), - IDE_PROC_DEVSET(address, 0, 2), - IDE_PROC_DEVSET(bios_cyl, 0, 65535), - IDE_PROC_DEVSET(bios_head, 0, 255), - IDE_PROC_DEVSET(bios_sect, 0, 63), - IDE_PROC_DEVSET(failures, 0, 65535), - IDE_PROC_DEVSET(lun, 0, 7), - IDE_PROC_DEVSET(max_failures, 0, 65535), - IDE_PROC_DEVSET(multcount, 0, 16), - IDE_PROC_DEVSET(nowerr, 0, 1), - IDE_PROC_DEVSET(wcache, 0, 1), - { NULL }, -}; diff --git a/drivers/ide/ide-dma-sff.c b/drivers/ide/ide-dma-sff.c deleted file mode 100644 index b7c2c0bd18b5..000000000000 --- a/drivers/ide/ide-dma-sff.c +++ /dev/null @@ -1,336 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#include -#include -#include -#include -#include -#include -#include - -/** - * config_drive_for_dma - attempt to activate IDE DMA - * @drive: the drive to place in DMA mode - * - * If the drive supports at least mode 2 DMA or UDMA of any kind - * then attempt to place it into DMA mode. Drives that are known to - * support DMA but predate the DMA properties or that are known - * to have DMA handling bugs are also set up appropriately based - * on the good/bad drive lists. - */ - -int config_drive_for_dma(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u16 *id = drive->id; - - if (drive->media != ide_disk) { - if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA) - return 0; - } - - /* - * Enable DMA on any drive that has - * UltraDMA (mode 0/1/2/3/4/5/6) enabled - */ - if ((id[ATA_ID_FIELD_VALID] & 4) && - ((id[ATA_ID_UDMA_MODES] >> 8) & 0x7f)) - return 1; - - /* - * Enable DMA on any drive that has mode2 DMA - * (multi or single) enabled - */ - if ((id[ATA_ID_MWDMA_MODES] & 0x404) == 0x404 || - (id[ATA_ID_SWDMA_MODES] & 0x404) == 0x404) - return 1; - - /* Consult the list of known "good" drives */ - if (ide_dma_good_drive(drive)) - return 1; - - return 0; -} - -u8 ide_dma_sff_read_status(ide_hwif_t *hwif) -{ - unsigned long addr = hwif->dma_base + ATA_DMA_STATUS; - - if (hwif->host_flags & IDE_HFLAG_MMIO) - return readb((void __iomem *)addr); - else - return inb(addr); -} -EXPORT_SYMBOL_GPL(ide_dma_sff_read_status); - -static void ide_dma_sff_write_status(ide_hwif_t *hwif, u8 val) -{ - unsigned long addr = hwif->dma_base + ATA_DMA_STATUS; - - if (hwif->host_flags & IDE_HFLAG_MMIO) - writeb(val, (void __iomem *)addr); - else - outb(val, addr); -} - -/** - * ide_dma_host_set - Enable/disable DMA on a host - * @drive: drive to control - * - * Enable/disable DMA on an IDE controller following generic - * bus-mastering IDE controller behaviour. - */ - -void ide_dma_host_set(ide_drive_t *drive, int on) -{ - ide_hwif_t *hwif = drive->hwif; - u8 unit = drive->dn & 1; - u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); - - if (on) - dma_stat |= (1 << (5 + unit)); - else - dma_stat &= ~(1 << (5 + unit)); - - ide_dma_sff_write_status(hwif, dma_stat); -} -EXPORT_SYMBOL_GPL(ide_dma_host_set); - -/** - * ide_build_dmatable - build IDE DMA table - * - * ide_build_dmatable() prepares a dma request. We map the command - * to get the pci bus addresses of the buffers and then build up - * the PRD table that the IDE layer wants to be fed. - * - * Most chipsets correctly interpret a length of 0x0000 as 64KB, - * but at least one (e.g. CS5530) misinterprets it as zero (!). - * So we break the 64KB entry into two 32KB entries instead. - * - * Returns the number of built PRD entries if all went okay, - * returns 0 otherwise. - * - * May also be invoked from trm290.c - */ - -int ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) -{ - ide_hwif_t *hwif = drive->hwif; - __le32 *table = (__le32 *)hwif->dmatable_cpu; - unsigned int count = 0; - int i; - struct scatterlist *sg; - u8 is_trm290 = !!(hwif->host_flags & IDE_HFLAG_TRM290); - - for_each_sg(hwif->sg_table, sg, cmd->sg_nents, i) { - u32 cur_addr, cur_len, xcount, bcount; - - cur_addr = sg_dma_address(sg); - cur_len = sg_dma_len(sg); - - /* - * Fill in the dma table, without crossing any 64kB boundaries. - * Most hardware requires 16-bit alignment of all blocks, - * but the trm290 requires 32-bit alignment. - */ - - while (cur_len) { - if (count++ >= PRD_ENTRIES) - goto use_pio_instead; - - bcount = 0x10000 - (cur_addr & 0xffff); - if (bcount > cur_len) - bcount = cur_len; - *table++ = cpu_to_le32(cur_addr); - xcount = bcount & 0xffff; - if (is_trm290) - xcount = ((xcount >> 2) - 1) << 16; - else if (xcount == 0x0000) { - if (count++ >= PRD_ENTRIES) - goto use_pio_instead; - *table++ = cpu_to_le32(0x8000); - *table++ = cpu_to_le32(cur_addr + 0x8000); - xcount = 0x8000; - } - *table++ = cpu_to_le32(xcount); - cur_addr += bcount; - cur_len -= bcount; - } - } - - if (count) { - if (!is_trm290) - *--table |= cpu_to_le32(0x80000000); - return count; - } - -use_pio_instead: - printk(KERN_ERR "%s: %s\n", drive->name, - count ? "DMA table too small" : "empty DMA table?"); - - return 0; /* revert to PIO for this request */ -} -EXPORT_SYMBOL_GPL(ide_build_dmatable); - -/** - * ide_dma_setup - begin a DMA phase - * @drive: target device - * @cmd: command - * - * Build an IDE DMA PRD (IDE speak for scatter gather table) - * and then set up the DMA transfer registers for a device - * that follows generic IDE PCI DMA behaviour. Controllers can - * override this function if they need to - * - * Returns 0 on success. If a PIO fallback is required then 1 - * is returned. - */ - -int ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) -{ - ide_hwif_t *hwif = drive->hwif; - u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; - u8 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR; - u8 dma_stat; - - /* fall back to pio! */ - if (ide_build_dmatable(drive, cmd) == 0) { - ide_map_sg(drive, cmd); - return 1; - } - - /* PRD table */ - if (mmio) - writel(hwif->dmatable_dma, - (void __iomem *)(hwif->dma_base + ATA_DMA_TABLE_OFS)); - else - outl(hwif->dmatable_dma, hwif->dma_base + ATA_DMA_TABLE_OFS); - - /* specify r/w */ - if (mmio) - writeb(rw, (void __iomem *)(hwif->dma_base + ATA_DMA_CMD)); - else - outb(rw, hwif->dma_base + ATA_DMA_CMD); - - /* read DMA status for INTR & ERROR flags */ - dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); - - /* clear INTR & ERROR flags */ - ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR); - - return 0; -} -EXPORT_SYMBOL_GPL(ide_dma_setup); - -/** - * ide_dma_sff_timer_expiry - handle a DMA timeout - * @drive: Drive that timed out - * - * An IDE DMA transfer timed out. In the event of an error we ask - * the driver to resolve the problem, if a DMA transfer is still - * in progress we continue to wait (arguably we need to add a - * secondary 'I don't care what the drive thinks' timeout here) - * Finally if we have an interrupt we let it complete the I/O. - * But only one time - we clear expiry and if it's still not - * completed after WAIT_CMD, we error and retry in PIO. - * This can occur if an interrupt is lost or due to hang or bugs. - */ - -int ide_dma_sff_timer_expiry(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); - - printk(KERN_WARNING "%s: %s: DMA status (0x%02x)\n", - drive->name, __func__, dma_stat); - - if ((dma_stat & 0x18) == 0x18) /* BUSY Stupid Early Timer !! */ - return WAIT_CMD; - - hwif->expiry = NULL; /* one free ride for now */ - - if (dma_stat & ATA_DMA_ERR) /* ERROR */ - return -1; - - if (dma_stat & ATA_DMA_ACTIVE) /* DMAing */ - return WAIT_CMD; - - if (dma_stat & ATA_DMA_INTR) /* Got an Interrupt */ - return WAIT_CMD; - - return 0; /* Status is unknown -- reset the bus */ -} -EXPORT_SYMBOL_GPL(ide_dma_sff_timer_expiry); - -void ide_dma_start(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u8 dma_cmd; - - /* Note that this is done *after* the cmd has - * been issued to the drive, as per the BM-IDE spec. - * The Promise Ultra33 doesn't work correctly when - * we do this part before issuing the drive cmd. - */ - if (hwif->host_flags & IDE_HFLAG_MMIO) { - dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD)); - writeb(dma_cmd | ATA_DMA_START, - (void __iomem *)(hwif->dma_base + ATA_DMA_CMD)); - } else { - dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); - outb(dma_cmd | ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD); - } -} -EXPORT_SYMBOL_GPL(ide_dma_start); - -/* returns 1 on error, 0 otherwise */ -int ide_dma_end(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u8 dma_stat = 0, dma_cmd = 0; - - /* stop DMA */ - if (hwif->host_flags & IDE_HFLAG_MMIO) { - dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD)); - writeb(dma_cmd & ~ATA_DMA_START, - (void __iomem *)(hwif->dma_base + ATA_DMA_CMD)); - } else { - dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); - outb(dma_cmd & ~ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD); - } - - /* get DMA status */ - dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); - - /* clear INTR & ERROR bits */ - ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR); - -#define CHECK_DMA_MASK (ATA_DMA_ACTIVE | ATA_DMA_ERR | ATA_DMA_INTR) - - /* verify good DMA status */ - if ((dma_stat & CHECK_DMA_MASK) != ATA_DMA_INTR) - return 0x10 | dma_stat; - return 0; -} -EXPORT_SYMBOL_GPL(ide_dma_end); - -/* returns 1 if dma irq issued, 0 otherwise */ -int ide_dma_test_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); - - return (dma_stat & ATA_DMA_INTR) ? 1 : 0; -} -EXPORT_SYMBOL_GPL(ide_dma_test_irq); - -const struct ide_dma_ops sff_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = ide_dma_start, - .dma_end = ide_dma_end, - .dma_test_irq = ide_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = ide_dma_sff_read_status, -}; -EXPORT_SYMBOL_GPL(sff_dma_ops); diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c deleted file mode 100644 index 6f344654ef22..000000000000 --- a/drivers/ide/ide-dma.c +++ /dev/null @@ -1,551 +0,0 @@ -/* - * IDE DMA support (including IDE PCI BM-DMA). - * - * Copyright (C) 1995-1998 Mark Lord - * Copyright (C) 1999-2000 Andre Hedrick - * Copyright (C) 2004, 2007 Bartlomiej Zolnierkiewicz - * - * May be copied or modified under the terms of the GNU General Public License - * - * DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies). - */ - -/* - * Special Thanks to Mark for his Six years of work. - */ - -/* - * Thanks to "Christopher J. Reimer" for - * fixing the problem with the BIOS on some Acer motherboards. - * - * Thanks to "Benoit Poulot-Cazajous" for testing - * "TX" chipset compatibility and for providing patches for the "TX" chipset. - * - * Thanks to Christian Brunner for taking a good first crack - * at generic DMA -- his patches were referred to when preparing this code. - * - * Most importantly, thanks to Robert Bringman - * for supplying a Promise UDMA board & WD UDMA drive for this work! - */ - -#include -#include -#include -#include -#include -#include -#include - -static const struct drive_list_entry drive_whitelist[] = { - { "Micropolis 2112A" , NULL }, - { "CONNER CTMA 4000" , NULL }, - { "CONNER CTT8000-A" , NULL }, - { "ST34342A" , NULL }, - { NULL , NULL } -}; - -static const struct drive_list_entry drive_blacklist[] = { - { "WDC AC11000H" , NULL }, - { "WDC AC22100H" , NULL }, - { "WDC AC32500H" , NULL }, - { "WDC AC33100H" , NULL }, - { "WDC AC31600H" , NULL }, - { "WDC AC32100H" , "24.09P07" }, - { "WDC AC23200L" , "21.10N21" }, - { "Compaq CRD-8241B" , NULL }, - { "CRD-8400B" , NULL }, - { "CRD-8480B", NULL }, - { "CRD-8482B", NULL }, - { "CRD-84" , NULL }, - { "SanDisk SDP3B" , NULL }, - { "SanDisk SDP3B-64" , NULL }, - { "SANYO CD-ROM CRD" , NULL }, - { "HITACHI CDR-8" , NULL }, - { "HITACHI CDR-8335" , NULL }, - { "HITACHI CDR-8435" , NULL }, - { "Toshiba CD-ROM XM-6202B" , NULL }, - { "TOSHIBA CD-ROM XM-1702BC", NULL }, - { "CD-532E-A" , NULL }, - { "E-IDE CD-ROM CR-840", NULL }, - { "CD-ROM Drive/F5A", NULL }, - { "WPI CDD-820", NULL }, - { "SAMSUNG CD-ROM SC-148C", NULL }, - { "SAMSUNG CD-ROM SC", NULL }, - { "ATAPI CD-ROM DRIVE 40X MAXIMUM", NULL }, - { "_NEC DV5800A", NULL }, - { "SAMSUNG CD-ROM SN-124", "N001" }, - { "Seagate STT20000A", NULL }, - { "CD-ROM CDR_U200", "1.09" }, - { NULL , NULL } - -}; - -/** - * ide_dma_intr - IDE DMA interrupt handler - * @drive: the drive the interrupt is for - * - * Handle an interrupt completing a read/write DMA transfer on an - * IDE device - */ - -ide_startstop_t ide_dma_intr(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_cmd *cmd = &hwif->cmd; - u8 stat = 0, dma_stat = 0; - - drive->waiting_for_dma = 0; - dma_stat = hwif->dma_ops->dma_end(drive); - ide_dma_unmap_sg(drive, cmd); - stat = hwif->tp_ops->read_status(hwif); - - if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat | ATA_DRQ)) { - if (!dma_stat) { - if ((cmd->tf_flags & IDE_TFLAG_FS) == 0) - ide_finish_cmd(drive, cmd, stat); - else - ide_complete_rq(drive, BLK_STS_OK, - blk_rq_sectors(cmd->rq) << 9); - return ide_stopped; - } - printk(KERN_ERR "%s: %s: bad DMA status (0x%02x)\n", - drive->name, __func__, dma_stat); - } - return ide_error(drive, "dma_intr", stat); -} - -int ide_dma_good_drive(ide_drive_t *drive) -{ - return ide_in_drive_list(drive->id, drive_whitelist); -} - -/** - * ide_dma_map_sg - map IDE scatter gather for DMA I/O - * @drive: the drive to map the DMA table for - * @cmd: command - * - * Perform the DMA mapping magic necessary to access the source or - * target buffers of a request via DMA. The lower layers of the - * kernel provide the necessary cache management so that we can - * operate in a portable fashion. - */ - -static int ide_dma_map_sg(ide_drive_t *drive, struct ide_cmd *cmd) -{ - ide_hwif_t *hwif = drive->hwif; - struct scatterlist *sg = hwif->sg_table; - int i; - - if (cmd->tf_flags & IDE_TFLAG_WRITE) - cmd->sg_dma_direction = DMA_TO_DEVICE; - else - cmd->sg_dma_direction = DMA_FROM_DEVICE; - - i = dma_map_sg(hwif->dev, sg, cmd->sg_nents, cmd->sg_dma_direction); - if (i) { - cmd->orig_sg_nents = cmd->sg_nents; - cmd->sg_nents = i; - } - - return i; -} - -/** - * ide_dma_unmap_sg - clean up DMA mapping - * @drive: The drive to unmap - * - * Teardown mappings after DMA has completed. This must be called - * after the completion of each use of ide_build_dmatable and before - * the next use of ide_build_dmatable. Failure to do so will cause - * an oops as only one mapping can be live for each target at a given - * time. - */ - -void ide_dma_unmap_sg(ide_drive_t *drive, struct ide_cmd *cmd) -{ - ide_hwif_t *hwif = drive->hwif; - - dma_unmap_sg(hwif->dev, hwif->sg_table, cmd->orig_sg_nents, - cmd->sg_dma_direction); -} -EXPORT_SYMBOL_GPL(ide_dma_unmap_sg); - -/** - * ide_dma_off_quietly - Generic DMA kill - * @drive: drive to control - * - * Turn off the current DMA on this IDE controller. - */ - -void ide_dma_off_quietly(ide_drive_t *drive) -{ - drive->dev_flags &= ~IDE_DFLAG_USING_DMA; - - drive->hwif->dma_ops->dma_host_set(drive, 0); -} -EXPORT_SYMBOL(ide_dma_off_quietly); - -/** - * ide_dma_off - disable DMA on a device - * @drive: drive to disable DMA on - * - * Disable IDE DMA for a device on this IDE controller. - * Inform the user that DMA has been disabled. - */ - -void ide_dma_off(ide_drive_t *drive) -{ - printk(KERN_INFO "%s: DMA disabled\n", drive->name); - ide_dma_off_quietly(drive); -} -EXPORT_SYMBOL(ide_dma_off); - -/** - * ide_dma_on - Enable DMA on a device - * @drive: drive to enable DMA on - * - * Enable IDE DMA for a device on this IDE controller. - */ - -void ide_dma_on(ide_drive_t *drive) -{ - drive->dev_flags |= IDE_DFLAG_USING_DMA; - - drive->hwif->dma_ops->dma_host_set(drive, 1); -} - -int __ide_dma_bad_drive(ide_drive_t *drive) -{ - u16 *id = drive->id; - - int blacklist = ide_in_drive_list(id, drive_blacklist); - if (blacklist) { - printk(KERN_WARNING "%s: Disabling (U)DMA for %s (blacklisted)\n", - drive->name, (char *)&id[ATA_ID_PROD]); - return blacklist; - } - return 0; -} -EXPORT_SYMBOL(__ide_dma_bad_drive); - -static const u8 xfer_mode_bases[] = { - XFER_UDMA_0, - XFER_MW_DMA_0, - XFER_SW_DMA_0, -}; - -static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode) -{ - u16 *id = drive->id; - ide_hwif_t *hwif = drive->hwif; - const struct ide_port_ops *port_ops = hwif->port_ops; - unsigned int mask = 0; - - switch (base) { - case XFER_UDMA_0: - if ((id[ATA_ID_FIELD_VALID] & 4) == 0) - break; - mask = id[ATA_ID_UDMA_MODES]; - if (port_ops && port_ops->udma_filter) - mask &= port_ops->udma_filter(drive); - else - mask &= hwif->ultra_mask; - - /* - * avoid false cable warning from eighty_ninty_three() - */ - if (req_mode > XFER_UDMA_2) { - if ((mask & 0x78) && (eighty_ninty_three(drive) == 0)) - mask &= 0x07; - } - break; - case XFER_MW_DMA_0: - mask = id[ATA_ID_MWDMA_MODES]; - - /* Also look for the CF specific MWDMA modes... */ - if (ata_id_is_cfa(id) && (id[ATA_ID_CFA_MODES] & 0x38)) { - u8 mode = ((id[ATA_ID_CFA_MODES] & 0x38) >> 3) - 1; - - mask |= ((2 << mode) - 1) << 3; - } - - if (port_ops && port_ops->mdma_filter) - mask &= port_ops->mdma_filter(drive); - else - mask &= hwif->mwdma_mask; - break; - case XFER_SW_DMA_0: - mask = id[ATA_ID_SWDMA_MODES]; - if (!(mask & ATA_SWDMA2) && (id[ATA_ID_OLD_DMA_MODES] >> 8)) { - u8 mode = id[ATA_ID_OLD_DMA_MODES] >> 8; - - /* - * if the mode is valid convert it to the mask - * (the maximum allowed mode is XFER_SW_DMA_2) - */ - if (mode <= 2) - mask = (2 << mode) - 1; - } - mask &= hwif->swdma_mask; - break; - default: - BUG(); - break; - } - - return mask; -} - -/** - * ide_find_dma_mode - compute DMA speed - * @drive: IDE device - * @req_mode: requested mode - * - * Checks the drive/host capabilities and finds the speed to use for - * the DMA transfer. The speed is then limited by the requested mode. - * - * Returns 0 if the drive/host combination is incapable of DMA transfers - * or if the requested mode is not a DMA mode. - */ - -u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode) -{ - ide_hwif_t *hwif = drive->hwif; - unsigned int mask; - int x, i; - u8 mode = 0; - - if (drive->media != ide_disk) { - if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA) - return 0; - } - - for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) { - if (req_mode < xfer_mode_bases[i]) - continue; - mask = ide_get_mode_mask(drive, xfer_mode_bases[i], req_mode); - x = fls(mask) - 1; - if (x >= 0) { - mode = xfer_mode_bases[i] + x; - break; - } - } - - if (hwif->chipset == ide_acorn && mode == 0) { - /* - * is this correct? - */ - if (ide_dma_good_drive(drive) && - drive->id[ATA_ID_EIDE_DMA_TIME] < 150) - mode = XFER_MW_DMA_1; - } - - mode = min(mode, req_mode); - - printk(KERN_INFO "%s: %s mode selected\n", drive->name, - mode ? ide_xfer_verbose(mode) : "no DMA"); - - return mode; -} - -static int ide_tune_dma(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u8 speed; - - if (ata_id_has_dma(drive->id) == 0 || - (drive->dev_flags & IDE_DFLAG_NODMA)) - return 0; - - /* consult the list of known "bad" drives */ - if (__ide_dma_bad_drive(drive)) - return 0; - - if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA) - return config_drive_for_dma(drive); - - speed = ide_max_dma_mode(drive); - - if (!speed) - return 0; - - if (ide_set_dma_mode(drive, speed)) - return 0; - - return 1; -} - -static int ide_dma_check(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - - if (ide_tune_dma(drive)) - return 0; - - /* TODO: always do PIO fallback */ - if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA) - return -1; - - ide_set_max_pio(drive); - - return -1; -} - -int ide_set_dma(ide_drive_t *drive) -{ - int rc; - - /* - * Force DMAing for the beginning of the check. - * Some chipsets appear to do interesting - * things, if not checked and cleared. - * PARANOIA!!! - */ - ide_dma_off_quietly(drive); - - rc = ide_dma_check(drive); - if (rc) - return rc; - - ide_dma_on(drive); - - return 0; -} - -void ide_check_dma_crc(ide_drive_t *drive) -{ - u8 mode; - - ide_dma_off_quietly(drive); - drive->crc_count = 0; - mode = drive->current_speed; - /* - * Don't try non Ultra-DMA modes without iCRC's. Force the - * device to PIO and make the user enable SWDMA/MWDMA modes. - */ - if (mode > XFER_UDMA_0 && mode <= XFER_UDMA_7) - mode--; - else - mode = XFER_PIO_4; - ide_set_xfer_rate(drive, mode); - if (drive->current_speed >= XFER_SW_DMA_0) - ide_dma_on(drive); -} - -void ide_dma_lost_irq(ide_drive_t *drive) -{ - printk(KERN_ERR "%s: DMA interrupt recovery\n", drive->name); -} -EXPORT_SYMBOL_GPL(ide_dma_lost_irq); - -/* - * un-busy the port etc, and clear any pending DMA status. we want to - * retry the current request in pio mode instead of risking tossing it - * all away - */ -ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) -{ - ide_hwif_t *hwif = drive->hwif; - const struct ide_dma_ops *dma_ops = hwif->dma_ops; - struct ide_cmd *cmd = &hwif->cmd; - ide_startstop_t ret = ide_stopped; - - /* - * end current dma transaction - */ - - if (error < 0) { - printk(KERN_WARNING "%s: DMA timeout error\n", drive->name); - drive->waiting_for_dma = 0; - (void)dma_ops->dma_end(drive); - ide_dma_unmap_sg(drive, cmd); - ret = ide_error(drive, "dma timeout error", - hwif->tp_ops->read_status(hwif)); - } else { - printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name); - if (dma_ops->dma_clear) - dma_ops->dma_clear(drive); - printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name); - if (dma_ops->dma_test_irq(drive) == 0) { - ide_dump_status(drive, "DMA timeout", - hwif->tp_ops->read_status(hwif)); - drive->waiting_for_dma = 0; - (void)dma_ops->dma_end(drive); - ide_dma_unmap_sg(drive, cmd); - } - } - - /* - * disable dma for now, but remember that we did so because of - * a timeout -- we'll reenable after we finish this next request - * (or rather the first chunk of it) in pio. - */ - drive->dev_flags |= IDE_DFLAG_DMA_PIO_RETRY; - drive->retry_pio++; - ide_dma_off_quietly(drive); - - /* - * make sure request is sane - */ - if (hwif->rq) - scsi_req(hwif->rq)->result = 0; - return ret; -} - -void ide_release_dma_engine(ide_hwif_t *hwif) -{ - if (hwif->dmatable_cpu) { - int prd_size = hwif->prd_max_nents * hwif->prd_ent_size; - - dma_free_coherent(hwif->dev, prd_size, - hwif->dmatable_cpu, hwif->dmatable_dma); - hwif->dmatable_cpu = NULL; - } -} -EXPORT_SYMBOL_GPL(ide_release_dma_engine); - -int ide_allocate_dma_engine(ide_hwif_t *hwif) -{ - int prd_size; - - if (hwif->prd_max_nents == 0) - hwif->prd_max_nents = PRD_ENTRIES; - if (hwif->prd_ent_size == 0) - hwif->prd_ent_size = PRD_BYTES; - - prd_size = hwif->prd_max_nents * hwif->prd_ent_size; - - hwif->dmatable_cpu = dma_alloc_coherent(hwif->dev, prd_size, - &hwif->dmatable_dma, - GFP_ATOMIC); - if (hwif->dmatable_cpu == NULL) { - printk(KERN_ERR "%s: unable to allocate PRD table\n", - hwif->name); - return -ENOMEM; - } - - return 0; -} -EXPORT_SYMBOL_GPL(ide_allocate_dma_engine); - -int ide_dma_prepare(ide_drive_t *drive, struct ide_cmd *cmd) -{ - const struct ide_dma_ops *dma_ops = drive->hwif->dma_ops; - - if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 || - (dma_ops->dma_check && dma_ops->dma_check(drive, cmd))) - goto out; - ide_map_sg(drive, cmd); - if (ide_dma_map_sg(drive, cmd) == 0) - goto out_map; - if (dma_ops->dma_setup(drive, cmd)) - goto out_dma_unmap; - drive->waiting_for_dma = 1; - return 0; -out_dma_unmap: - ide_dma_unmap_sg(drive, cmd); -out_map: - ide_map_sg(drive, cmd); -out: - return 1; -} diff --git a/drivers/ide/ide-eh.c b/drivers/ide/ide-eh.c deleted file mode 100644 index 2f378213e9b5..000000000000 --- a/drivers/ide/ide-eh.c +++ /dev/null @@ -1,443 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -#include -#include -#include -#include - -static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, - u8 stat, u8 err) -{ - ide_hwif_t *hwif = drive->hwif; - - if ((stat & ATA_BUSY) || - ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) { - /* other bits are useless when BUSY */ - scsi_req(rq)->result |= ERROR_RESET; - } else if (stat & ATA_ERR) { - /* err has different meaning on cdrom and tape */ - if (err == ATA_ABORTED) { - if ((drive->dev_flags & IDE_DFLAG_LBA) && - /* some newer drives don't support ATA_CMD_INIT_DEV_PARAMS */ - hwif->tp_ops->read_status(hwif) == ATA_CMD_INIT_DEV_PARAMS) - return ide_stopped; - } else if ((err & BAD_CRC) == BAD_CRC) { - /* UDMA crc error, just retry the operation */ - drive->crc_count++; - } else if (err & (ATA_BBK | ATA_UNC)) { - /* retries won't help these */ - scsi_req(rq)->result = ERROR_MAX; - } else if (err & ATA_TRK0NF) { - /* help it find track zero */ - scsi_req(rq)->result |= ERROR_RECAL; - } - } - - if ((stat & ATA_DRQ) && rq_data_dir(rq) == READ && - (hwif->host_flags & IDE_HFLAG_ERROR_STOPS_FIFO) == 0) { - int nsect = drive->mult_count ? drive->mult_count : 1; - - ide_pad_transfer(drive, READ, nsect * SECTOR_SIZE); - } - - if (scsi_req(rq)->result >= ERROR_MAX || blk_noretry_request(rq)) { - ide_kill_rq(drive, rq); - return ide_stopped; - } - - if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ)) - scsi_req(rq)->result |= ERROR_RESET; - - if ((scsi_req(rq)->result & ERROR_RESET) == ERROR_RESET) { - ++scsi_req(rq)->result; - return ide_do_reset(drive); - } - - if ((scsi_req(rq)->result & ERROR_RECAL) == ERROR_RECAL) - drive->special_flags |= IDE_SFLAG_RECALIBRATE; - - ++scsi_req(rq)->result; - - return ide_stopped; -} - -static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, - u8 stat, u8 err) -{ - ide_hwif_t *hwif = drive->hwif; - - if ((stat & ATA_BUSY) || - ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) { - /* other bits are useless when BUSY */ - scsi_req(rq)->result |= ERROR_RESET; - } else { - /* add decoding error stuff */ - } - - if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ)) - /* force an abort */ - hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE); - - if (scsi_req(rq)->result >= ERROR_MAX) { - ide_kill_rq(drive, rq); - } else { - if ((scsi_req(rq)->result & ERROR_RESET) == ERROR_RESET) { - ++scsi_req(rq)->result; - return ide_do_reset(drive); - } - ++scsi_req(rq)->result; - } - - return ide_stopped; -} - -static ide_startstop_t __ide_error(ide_drive_t *drive, struct request *rq, - u8 stat, u8 err) -{ - if (drive->media == ide_disk) - return ide_ata_error(drive, rq, stat, err); - return ide_atapi_error(drive, rq, stat, err); -} - -/** - * ide_error - handle an error on the IDE - * @drive: drive the error occurred on - * @msg: message to report - * @stat: status bits - * - * ide_error() takes action based on the error returned by the drive. - * For normal I/O that may well include retries. We deal with - * both new-style (taskfile) and old style command handling here. - * In the case of taskfile command handling there is work left to - * do - */ - -ide_startstop_t ide_error(ide_drive_t *drive, const char *msg, u8 stat) -{ - struct request *rq; - u8 err; - - err = ide_dump_status(drive, msg, stat); - - rq = drive->hwif->rq; - if (rq == NULL) - return ide_stopped; - - /* retry only "normal" I/O: */ - if (blk_rq_is_passthrough(rq)) { - if (ata_taskfile_request(rq)) { - struct ide_cmd *cmd = ide_req(rq)->special; - - if (cmd) - ide_complete_cmd(drive, cmd, stat, err); - } else if (ata_pm_request(rq)) { - scsi_req(rq)->result = 1; - ide_complete_pm_rq(drive, rq); - return ide_stopped; - } - scsi_req(rq)->result = err; - ide_complete_rq(drive, err ? BLK_STS_IOERR : BLK_STS_OK, blk_rq_bytes(rq)); - return ide_stopped; - } - - return __ide_error(drive, rq, stat, err); -} -EXPORT_SYMBOL_GPL(ide_error); - -static inline void ide_complete_drive_reset(ide_drive_t *drive, blk_status_t err) -{ - struct request *rq = drive->hwif->rq; - - if (rq && ata_misc_request(rq) && - scsi_req(rq)->cmd[0] == REQ_DRIVE_RESET) { - if (err <= 0 && scsi_req(rq)->result == 0) - scsi_req(rq)->result = -EIO; - ide_complete_rq(drive, err, blk_rq_bytes(rq)); - } -} - -/* needed below */ -static ide_startstop_t do_reset1(ide_drive_t *, int); - -/* - * atapi_reset_pollfunc() gets invoked to poll the interface for completion - * every 50ms during an atapi drive reset operation. If the drive has not yet - * responded, and we have not yet hit our maximum waiting time, then the timer - * is restarted for another 50ms. - */ -static ide_startstop_t atapi_reset_pollfunc(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - const struct ide_tp_ops *tp_ops = hwif->tp_ops; - u8 stat; - - tp_ops->dev_select(drive); - udelay(10); - stat = tp_ops->read_status(hwif); - - if (OK_STAT(stat, 0, ATA_BUSY)) - printk(KERN_INFO "%s: ATAPI reset complete\n", drive->name); - else { - if (time_before(jiffies, hwif->poll_timeout)) { - ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20); - /* continue polling */ - return ide_started; - } - /* end of polling */ - hwif->polling = 0; - printk(KERN_ERR "%s: ATAPI reset timed-out, status=0x%02x\n", - drive->name, stat); - /* do it the old fashioned way */ - return do_reset1(drive, 1); - } - /* done polling */ - hwif->polling = 0; - ide_complete_drive_reset(drive, BLK_STS_OK); - return ide_stopped; -} - -static void ide_reset_report_error(ide_hwif_t *hwif, u8 err) -{ - static const char *err_master_vals[] = - { NULL, "passed", "formatter device error", - "sector buffer error", "ECC circuitry error", - "controlling MPU error" }; - - u8 err_master = err & 0x7f; - - printk(KERN_ERR "%s: reset: master: ", hwif->name); - if (err_master && err_master < 6) - printk(KERN_CONT "%s", err_master_vals[err_master]); - else - printk(KERN_CONT "error (0x%02x?)", err); - if (err & 0x80) - printk(KERN_CONT "; slave: failed"); - printk(KERN_CONT "\n"); -} - -/* - * reset_pollfunc() gets invoked to poll the interface for completion every 50ms - * during an ide reset operation. If the drives have not yet responded, - * and we have not yet hit our maximum waiting time, then the timer is restarted - * for another 50ms. - */ -static ide_startstop_t reset_pollfunc(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - const struct ide_port_ops *port_ops = hwif->port_ops; - u8 tmp; - blk_status_t err = BLK_STS_OK; - - if (port_ops && port_ops->reset_poll) { - err = port_ops->reset_poll(drive); - if (err) { - printk(KERN_ERR "%s: host reset_poll failure for %s.\n", - hwif->name, drive->name); - goto out; - } - } - - tmp = hwif->tp_ops->read_status(hwif); - - if (!OK_STAT(tmp, 0, ATA_BUSY)) { - if (time_before(jiffies, hwif->poll_timeout)) { - ide_set_handler(drive, &reset_pollfunc, HZ/20); - /* continue polling */ - return ide_started; - } - printk(KERN_ERR "%s: reset timed-out, status=0x%02x\n", - hwif->name, tmp); - drive->failures++; - err = BLK_STS_IOERR; - } else { - tmp = ide_read_error(drive); - - if (tmp == 1) { - printk(KERN_INFO "%s: reset: success\n", hwif->name); - drive->failures = 0; - } else { - ide_reset_report_error(hwif, tmp); - drive->failures++; - err = BLK_STS_IOERR; - } - } -out: - hwif->polling = 0; /* done polling */ - ide_complete_drive_reset(drive, err); - return ide_stopped; -} - -static void ide_disk_pre_reset(ide_drive_t *drive) -{ - int legacy = (drive->id[ATA_ID_CFS_ENABLE_2] & 0x0400) ? 0 : 1; - - drive->special_flags = - legacy ? (IDE_SFLAG_SET_GEOMETRY | IDE_SFLAG_RECALIBRATE) : 0; - - drive->mult_count = 0; - drive->dev_flags &= ~IDE_DFLAG_PARKED; - - if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0 && - (drive->dev_flags & IDE_DFLAG_USING_DMA) == 0) - drive->mult_req = 0; - - if (drive->mult_req != drive->mult_count) - drive->special_flags |= IDE_SFLAG_SET_MULTMODE; -} - -static void pre_reset(ide_drive_t *drive) -{ - const struct ide_port_ops *port_ops = drive->hwif->port_ops; - - if (drive->media == ide_disk) - ide_disk_pre_reset(drive); - else - drive->dev_flags |= IDE_DFLAG_POST_RESET; - - if (drive->dev_flags & IDE_DFLAG_USING_DMA) { - if (drive->crc_count) - ide_check_dma_crc(drive); - else - ide_dma_off(drive); - } - - if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0) { - if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0) { - drive->dev_flags &= ~IDE_DFLAG_UNMASK; - drive->io_32bit = 0; - } - return; - } - - if (port_ops && port_ops->pre_reset) - port_ops->pre_reset(drive); - - if (drive->current_speed != 0xff) - drive->desired_speed = drive->current_speed; - drive->current_speed = 0xff; -} - -/* - * do_reset1() attempts to recover a confused drive by resetting it. - * Unfortunately, resetting a disk drive actually resets all devices on - * the same interface, so it can really be thought of as resetting the - * interface rather than resetting the drive. - * - * ATAPI devices have their own reset mechanism which allows them to be - * individually reset without clobbering other devices on the same interface. - * - * Unfortunately, the IDE interface does not generate an interrupt to let - * us know when the reset operation has finished, so we must poll for this. - * Equally poor, though, is the fact that this may a very long time to complete, - * (up to 30 seconds worstcase). So, instead of busy-waiting here for it, - * we set a timer to poll at 50ms intervals. - */ -static ide_startstop_t do_reset1(ide_drive_t *drive, int do_not_try_atapi) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_io_ports *io_ports = &hwif->io_ports; - const struct ide_tp_ops *tp_ops = hwif->tp_ops; - const struct ide_port_ops *port_ops; - ide_drive_t *tdrive; - unsigned long flags, timeout; - int i; - DEFINE_WAIT(wait); - - spin_lock_irqsave(&hwif->lock, flags); - - /* We must not reset with running handlers */ - BUG_ON(hwif->handler != NULL); - - /* For an ATAPI device, first try an ATAPI SRST. */ - if (drive->media != ide_disk && !do_not_try_atapi) { - pre_reset(drive); - tp_ops->dev_select(drive); - udelay(20); - tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET); - ndelay(400); - hwif->poll_timeout = jiffies + WAIT_WORSTCASE; - hwif->polling = 1; - __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20); - spin_unlock_irqrestore(&hwif->lock, flags); - return ide_started; - } - - /* We must not disturb devices in the IDE_DFLAG_PARKED state. */ - do { - unsigned long now; - - prepare_to_wait(&ide_park_wq, &wait, TASK_UNINTERRUPTIBLE); - timeout = jiffies; - ide_port_for_each_present_dev(i, tdrive, hwif) { - if ((tdrive->dev_flags & IDE_DFLAG_PARKED) && - time_after(tdrive->sleep, timeout)) - timeout = tdrive->sleep; - } - - now = jiffies; - if (time_before_eq(timeout, now)) - break; - - spin_unlock_irqrestore(&hwif->lock, flags); - timeout = schedule_timeout_uninterruptible(timeout - now); - spin_lock_irqsave(&hwif->lock, flags); - } while (timeout); - finish_wait(&ide_park_wq, &wait); - - /* - * First, reset any device state data we were maintaining - * for any of the drives on this interface. - */ - ide_port_for_each_dev(i, tdrive, hwif) - pre_reset(tdrive); - - if (io_ports->ctl_addr == 0) { - spin_unlock_irqrestore(&hwif->lock, flags); - ide_complete_drive_reset(drive, BLK_STS_IOERR); - return ide_stopped; - } - - /* - * Note that we also set nIEN while resetting the device, - * to mask unwanted interrupts from the interface during the reset. - * However, due to the design of PC hardware, this will cause an - * immediate interrupt due to the edge transition it produces. - * This single interrupt gives us a "fast poll" for drives that - * recover from reset very quickly, saving us the first 50ms wait time. - */ - /* set SRST and nIEN */ - tp_ops->write_devctl(hwif, ATA_SRST | ATA_NIEN | ATA_DEVCTL_OBS); - /* more than enough time */ - udelay(10); - /* clear SRST, leave nIEN (unless device is on the quirk list) */ - tp_ops->write_devctl(hwif, - ((drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) ? 0 : ATA_NIEN) | - ATA_DEVCTL_OBS); - /* more than enough time */ - udelay(10); - hwif->poll_timeout = jiffies + WAIT_WORSTCASE; - hwif->polling = 1; - __ide_set_handler(drive, &reset_pollfunc, HZ/20); - - /* - * Some weird controller like resetting themselves to a strange - * state when the disks are reset this way. At least, the Winbond - * 553 documentation says that - */ - port_ops = hwif->port_ops; - if (port_ops && port_ops->resetproc) - port_ops->resetproc(drive); - - spin_unlock_irqrestore(&hwif->lock, flags); - return ide_started; -} - -/* - * ide_do_reset() is the entry point to the drive/interface reset code. - */ - -ide_startstop_t ide_do_reset(ide_drive_t *drive) -{ - return do_reset1(drive, 0); -} -EXPORT_SYMBOL(ide_do_reset); diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c deleted file mode 100644 index f5a2870aaf54..000000000000 --- a/drivers/ide/ide-floppy.c +++ /dev/null @@ -1,551 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * IDE ATAPI floppy driver. - * - * Copyright (C) 1996-1999 Gadi Oxman - * Copyright (C) 2000-2002 Paul Bristow - * Copyright (C) 2005 Bartlomiej Zolnierkiewicz - * - * This driver supports the following IDE floppy drives: - * - * LS-120/240 SuperDisk - * Iomega Zip 100/250 - * Iomega PC Card Clik!/PocketZip - * - * For a historical changelog see - * Documentation/ide/ChangeLog.ide-floppy.1996-2002 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "ide-floppy.h" - -/* - * After each failed packet command we issue a request sense command and retry - * the packet command IDEFLOPPY_MAX_PC_RETRIES times. - */ -#define IDEFLOPPY_MAX_PC_RETRIES 3 - -/* format capacities descriptor codes */ -#define CAPACITY_INVALID 0x00 -#define CAPACITY_UNFORMATTED 0x01 -#define CAPACITY_CURRENT 0x02 -#define CAPACITY_NO_CARTRIDGE 0x03 - -/* - * The following delay solves a problem with ATAPI Zip 100 drive where BSY bit - * was apparently being deasserted before the unit was ready to receive data. - */ -#define IDEFLOPPY_PC_DELAY (HZ/20) /* default delay for ZIP 100 (50ms) */ - -static int ide_floppy_callback(ide_drive_t *drive, int dsc) -{ - struct ide_disk_obj *floppy = drive->driver_data; - struct ide_atapi_pc *pc = drive->pc; - struct request *rq = pc->rq; - int uptodate = pc->error ? 0 : 1; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - if (drive->failed_pc == pc) - drive->failed_pc = NULL; - - if (pc->c[0] == GPCMD_READ_10 || pc->c[0] == GPCMD_WRITE_10 || - blk_rq_is_scsi(rq)) - uptodate = 1; /* FIXME */ - else if (pc->c[0] == GPCMD_REQUEST_SENSE) { - - u8 *buf = bio_data(rq->bio); - - if (!pc->error) { - floppy->sense_key = buf[2] & 0x0F; - floppy->asc = buf[12]; - floppy->ascq = buf[13]; - floppy->progress_indication = buf[15] & 0x80 ? - (u16)get_unaligned((u16 *)&buf[16]) : 0x10000; - - if (drive->failed_pc) - ide_debug_log(IDE_DBG_PC, "pc = %x", - drive->failed_pc->c[0]); - - ide_debug_log(IDE_DBG_SENSE, "sense key = %x, asc = %x," - "ascq = %x", floppy->sense_key, - floppy->asc, floppy->ascq); - } else - printk(KERN_ERR PFX "Error in REQUEST SENSE itself - " - "Aborting request!\n"); - } - - if (ata_misc_request(rq)) - scsi_req(rq)->result = uptodate ? 0 : IDE_DRV_ERROR_GENERAL; - - return uptodate; -} - -static void ide_floppy_report_error(struct ide_disk_obj *floppy, - struct ide_atapi_pc *pc) -{ - /* suppress error messages resulting from Medium not present */ - if (floppy->sense_key == 0x02 && - floppy->asc == 0x3a && - floppy->ascq == 0x00) - return; - - printk(KERN_ERR PFX "%s: I/O error, pc = %2x, key = %2x, " - "asc = %2x, ascq = %2x\n", - floppy->drive->name, pc->c[0], floppy->sense_key, - floppy->asc, floppy->ascq); - -} - -static ide_startstop_t ide_floppy_issue_pc(ide_drive_t *drive, - struct ide_cmd *cmd, - struct ide_atapi_pc *pc) -{ - struct ide_disk_obj *floppy = drive->driver_data; - - if (drive->failed_pc == NULL && - pc->c[0] != GPCMD_REQUEST_SENSE) - drive->failed_pc = pc; - - /* Set the current packet command */ - drive->pc = pc; - - if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES) { - unsigned int done = blk_rq_bytes(drive->hwif->rq); - - if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR)) - ide_floppy_report_error(floppy, pc); - - /* Giving up */ - pc->error = IDE_DRV_ERROR_GENERAL; - - drive->failed_pc = NULL; - drive->pc_callback(drive, 0); - ide_complete_rq(drive, BLK_STS_IOERR, done); - return ide_stopped; - } - - ide_debug_log(IDE_DBG_FUNC, "retry #%d", pc->retries); - - pc->retries++; - - return ide_issue_pc(drive, cmd); -} - -void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *pc) -{ - ide_init_pc(pc); - pc->c[0] = GPCMD_READ_FORMAT_CAPACITIES; - pc->c[7] = 255; - pc->c[8] = 255; - pc->req_xfer = 255; -} - -/* A mode sense command is used to "sense" floppy parameters. */ -void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code) -{ - u16 length = 8; /* sizeof(Mode Parameter Header) = 8 Bytes */ - - ide_init_pc(pc); - pc->c[0] = GPCMD_MODE_SENSE_10; - pc->c[1] = 0; - pc->c[2] = page_code; - - switch (page_code) { - case IDEFLOPPY_CAPABILITIES_PAGE: - length += 12; - break; - case IDEFLOPPY_FLEXIBLE_DISK_PAGE: - length += 32; - break; - default: - printk(KERN_ERR PFX "unsupported page code in %s\n", __func__); - } - put_unaligned(cpu_to_be16(length), (u16 *) &pc->c[7]); - pc->req_xfer = length; -} - -static void idefloppy_create_rw_cmd(ide_drive_t *drive, - struct ide_atapi_pc *pc, struct request *rq, - unsigned long sector) -{ - struct ide_disk_obj *floppy = drive->driver_data; - int block = sector / floppy->bs_factor; - int blocks = blk_rq_sectors(rq) / floppy->bs_factor; - int cmd = rq_data_dir(rq); - - ide_debug_log(IDE_DBG_FUNC, "block: %d, blocks: %d", block, blocks); - - ide_init_pc(pc); - pc->c[0] = cmd == READ ? GPCMD_READ_10 : GPCMD_WRITE_10; - put_unaligned(cpu_to_be16(blocks), (unsigned short *)&pc->c[7]); - put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[2]); - - memcpy(scsi_req(rq)->cmd, pc->c, 12); - - pc->rq = rq; - if (cmd == WRITE) - pc->flags |= PC_FLAG_WRITING; - - pc->flags |= PC_FLAG_DMA_OK; -} - -static void idefloppy_blockpc_cmd(struct ide_disk_obj *floppy, - struct ide_atapi_pc *pc, struct request *rq) -{ - ide_init_pc(pc); - memcpy(pc->c, scsi_req(rq)->cmd, sizeof(pc->c)); - pc->rq = rq; - if (blk_rq_bytes(rq)) { - pc->flags |= PC_FLAG_DMA_OK; - if (rq_data_dir(rq) == WRITE) - pc->flags |= PC_FLAG_WRITING; - } -} - -static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, - struct request *rq, sector_t block) -{ - struct ide_disk_obj *floppy = drive->driver_data; - struct ide_cmd cmd; - struct ide_atapi_pc *pc; - - ide_debug_log(IDE_DBG_FUNC, "enter, cmd: 0x%x\n", rq->cmd[0]); - - if (drive->debug_mask & IDE_DBG_RQ) - blk_dump_rq_flags(rq, (rq->rq_disk - ? rq->rq_disk->disk_name - : "dev?")); - - if (scsi_req(rq)->result >= ERROR_MAX) { - if (drive->failed_pc) { - ide_floppy_report_error(floppy, drive->failed_pc); - drive->failed_pc = NULL; - } else - printk(KERN_ERR PFX "%s: I/O error\n", drive->name); - - if (ata_misc_request(rq)) { - scsi_req(rq)->result = 0; - ide_complete_rq(drive, BLK_STS_OK, blk_rq_bytes(rq)); - return ide_stopped; - } else - goto out_end; - } - - switch (req_op(rq)) { - default: - if (((long)blk_rq_pos(rq) % floppy->bs_factor) || - (blk_rq_sectors(rq) % floppy->bs_factor)) { - printk(KERN_ERR PFX "%s: unsupported r/w rq size\n", - drive->name); - goto out_end; - } - pc = &floppy->queued_pc; - idefloppy_create_rw_cmd(drive, pc, rq, (unsigned long)block); - break; - case REQ_OP_SCSI_IN: - case REQ_OP_SCSI_OUT: - pc = &floppy->queued_pc; - idefloppy_blockpc_cmd(floppy, pc, rq); - break; - case REQ_OP_DRV_IN: - case REQ_OP_DRV_OUT: - switch (ide_req(rq)->type) { - case ATA_PRIV_MISC: - case ATA_PRIV_SENSE: - pc = (struct ide_atapi_pc *)ide_req(rq)->special; - break; - default: - BUG(); - } - } - - ide_prep_sense(drive, rq); - - memset(&cmd, 0, sizeof(cmd)); - - if (rq_data_dir(rq)) - cmd.tf_flags |= IDE_TFLAG_WRITE; - - cmd.rq = rq; - - if (!blk_rq_is_passthrough(rq) || blk_rq_bytes(rq)) { - ide_init_sg_cmd(&cmd, blk_rq_bytes(rq)); - ide_map_sg(drive, &cmd); - } - - pc->rq = rq; - - return ide_floppy_issue_pc(drive, &cmd, pc); -out_end: - drive->failed_pc = NULL; - if (blk_rq_is_passthrough(rq) && scsi_req(rq)->result == 0) - scsi_req(rq)->result = -EIO; - ide_complete_rq(drive, BLK_STS_IOERR, blk_rq_bytes(rq)); - return ide_stopped; -} - -/* - * Look at the flexible disk page parameters. We ignore the CHS capacity - * parameters and use the LBA parameters instead. - */ -static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive, - struct ide_atapi_pc *pc) -{ - struct ide_disk_obj *floppy = drive->driver_data; - struct gendisk *disk = floppy->disk; - u8 *page, buf[40]; - int capacity, lba_capacity; - u16 transfer_rate, sector_size, cyls, rpm; - u8 heads, sectors; - - ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE); - - if (ide_queue_pc_tail(drive, disk, pc, buf, pc->req_xfer)) { - printk(KERN_ERR PFX "Can't get flexible disk page params\n"); - return 1; - } - - if (buf[3] & 0x80) - drive->dev_flags |= IDE_DFLAG_WP; - else - drive->dev_flags &= ~IDE_DFLAG_WP; - - set_disk_ro(disk, !!(drive->dev_flags & IDE_DFLAG_WP)); - - page = &buf[8]; - - transfer_rate = be16_to_cpup((__be16 *)&buf[8 + 2]); - sector_size = be16_to_cpup((__be16 *)&buf[8 + 6]); - cyls = be16_to_cpup((__be16 *)&buf[8 + 8]); - rpm = be16_to_cpup((__be16 *)&buf[8 + 28]); - heads = buf[8 + 4]; - sectors = buf[8 + 5]; - - capacity = cyls * heads * sectors * sector_size; - - if (memcmp(page, &floppy->flexible_disk_page, 32)) - printk(KERN_INFO PFX "%s: %dkB, %d/%d/%d CHS, %d kBps, " - "%d sector size, %d rpm\n", - drive->name, capacity / 1024, cyls, heads, - sectors, transfer_rate / 8, sector_size, rpm); - - memcpy(&floppy->flexible_disk_page, page, 32); - drive->bios_cyl = cyls; - drive->bios_head = heads; - drive->bios_sect = sectors; - lba_capacity = floppy->blocks * floppy->block_size; - - if (capacity < lba_capacity) { - printk(KERN_NOTICE PFX "%s: The disk reports a capacity of %d " - "bytes, but the drive only handles %d\n", - drive->name, lba_capacity, capacity); - floppy->blocks = floppy->block_size ? - capacity / floppy->block_size : 0; - drive->capacity64 = floppy->blocks * floppy->bs_factor; - } - - return 0; -} - -/* - * Determine if a media is present in the floppy drive, and if so, its LBA - * capacity. - */ -static int ide_floppy_get_capacity(ide_drive_t *drive) -{ - struct ide_disk_obj *floppy = drive->driver_data; - struct gendisk *disk = floppy->disk; - struct ide_atapi_pc pc; - u8 *cap_desc; - u8 pc_buf[256], header_len, desc_cnt; - int i, rc = 1, blocks, length; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - drive->bios_cyl = 0; - drive->bios_head = drive->bios_sect = 0; - floppy->blocks = 0; - floppy->bs_factor = 1; - drive->capacity64 = 0; - - ide_floppy_create_read_capacity_cmd(&pc); - if (ide_queue_pc_tail(drive, disk, &pc, pc_buf, pc.req_xfer)) { - printk(KERN_ERR PFX "Can't get floppy parameters\n"); - return 1; - } - header_len = pc_buf[3]; - cap_desc = &pc_buf[4]; - desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */ - - for (i = 0; i < desc_cnt; i++) { - unsigned int desc_start = 4 + i*8; - - blocks = be32_to_cpup((__be32 *)&pc_buf[desc_start]); - length = be16_to_cpup((__be16 *)&pc_buf[desc_start + 6]); - - ide_debug_log(IDE_DBG_PROBE, "Descriptor %d: %dkB, %d blocks, " - "%d sector size", - i, blocks * length / 1024, - blocks, length); - - if (i) - continue; - /* - * the code below is valid only for the 1st descriptor, ie i=0 - */ - - switch (pc_buf[desc_start + 4] & 0x03) { - /* Clik! drive returns this instead of CAPACITY_CURRENT */ - case CAPACITY_UNFORMATTED: - if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) - /* - * If it is not a clik drive, break out - * (maintains previous driver behaviour) - */ - break; - fallthrough; - case CAPACITY_CURRENT: - /* Normal Zip/LS-120 disks */ - if (memcmp(cap_desc, &floppy->cap_desc, 8)) - printk(KERN_INFO PFX "%s: %dkB, %d blocks, %d " - "sector size\n", - drive->name, blocks * length / 1024, - blocks, length); - memcpy(&floppy->cap_desc, cap_desc, 8); - - if (!length || length % 512) { - printk(KERN_NOTICE PFX "%s: %d bytes block size" - " not supported\n", drive->name, length); - } else { - floppy->blocks = blocks; - floppy->block_size = length; - floppy->bs_factor = length / 512; - if (floppy->bs_factor != 1) - printk(KERN_NOTICE PFX "%s: Warning: " - "non 512 bytes block size not " - "fully supported\n", - drive->name); - drive->capacity64 = - floppy->blocks * floppy->bs_factor; - rc = 0; - } - break; - case CAPACITY_NO_CARTRIDGE: - /* - * This is a KERN_ERR so it appears on screen - * for the user to see - */ - printk(KERN_ERR PFX "%s: No disk in drive\n", - drive->name); - break; - case CAPACITY_INVALID: - printk(KERN_ERR PFX "%s: Invalid capacity for disk " - "in drive\n", drive->name); - break; - } - ide_debug_log(IDE_DBG_PROBE, "Descriptor 0 Code: %d", - pc_buf[desc_start + 4] & 0x03); - } - - /* Clik! disk does not support get_flexible_disk_page */ - if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) - (void) ide_floppy_get_flexible_disk_page(drive, &pc); - - return rc; -} - -static void ide_floppy_setup(ide_drive_t *drive) -{ - struct ide_disk_obj *floppy = drive->driver_data; - u16 *id = drive->id; - - drive->pc_callback = ide_floppy_callback; - - /* - * We used to check revisions here. At this point however I'm giving up. - * Just assume they are all broken, its easier. - * - * The actual reason for the workarounds was likely a driver bug after - * all rather than a firmware bug, and the workaround below used to hide - * it. It should be fixed as of version 1.9, but to be on the safe side - * we'll leave the limitation below for the 2.2.x tree. - */ - if (strstarts((char *)&id[ATA_ID_PROD], "IOMEGA ZIP 100 ATAPI")) { - drive->atapi_flags |= IDE_AFLAG_ZIP_DRIVE; - /* This value will be visible in the /proc/ide/hdx/settings */ - drive->pc_delay = IDEFLOPPY_PC_DELAY; - blk_queue_max_hw_sectors(drive->queue, 64); - } - - /* - * Guess what? The IOMEGA Clik! drive also needs the above fix. It makes - * nasty clicking noises without it, so please don't remove this. - */ - if (strstarts((char *)&id[ATA_ID_PROD], "IOMEGA Clik!")) { - blk_queue_max_hw_sectors(drive->queue, 64); - drive->atapi_flags |= IDE_AFLAG_CLIK_DRIVE; - /* IOMEGA Clik! drives do not support lock/unlock commands */ - drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING; - } - - (void) ide_floppy_get_capacity(drive); - - ide_proc_register_driver(drive, floppy->driver); -} - -static void ide_floppy_flush(ide_drive_t *drive) -{ -} - -static int ide_floppy_init_media(ide_drive_t *drive, struct gendisk *disk) -{ - int ret = 0; - - if (ide_do_test_unit_ready(drive, disk)) - ide_do_start_stop(drive, disk, 1); - - ret = ide_floppy_get_capacity(drive); - - set_capacity(disk, ide_gd_capacity(drive)); - - return ret; -} - -const struct ide_disk_ops ide_atapi_disk_ops = { - .check = ide_check_atapi_device, - .get_capacity = ide_floppy_get_capacity, - .setup = ide_floppy_setup, - .flush = ide_floppy_flush, - .init_media = ide_floppy_init_media, - .set_doorlock = ide_set_media_lock, - .do_request = ide_floppy_do_request, - .ioctl = ide_floppy_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ide_floppy_compat_ioctl, -#endif -}; diff --git a/drivers/ide/ide-floppy.h b/drivers/ide/ide-floppy.h deleted file mode 100644 index 8505a5f58f4e..000000000000 --- a/drivers/ide/ide-floppy.h +++ /dev/null @@ -1,42 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __IDE_FLOPPY_H -#define __IDE_FLOPPY_H - -#include "ide-gd.h" - -#ifdef CONFIG_IDE_GD_ATAPI -/* - * Pages of the SELECT SENSE / MODE SENSE packet commands. - * See SFF-8070i spec. - */ -#define IDEFLOPPY_CAPABILITIES_PAGE 0x1b -#define IDEFLOPPY_FLEXIBLE_DISK_PAGE 0x05 - -/* IOCTLs used in low-level formatting. */ -#define IDEFLOPPY_IOCTL_FORMAT_SUPPORTED 0x4600 -#define IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY 0x4601 -#define IDEFLOPPY_IOCTL_FORMAT_START 0x4602 -#define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS 0x4603 - -/* ide-floppy.c */ -extern const struct ide_disk_ops ide_atapi_disk_ops; -void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *, u8); -void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *); - -/* ide-floppy_ioctl.c */ -int ide_floppy_ioctl(ide_drive_t *, struct block_device *, fmode_t, - unsigned int, unsigned long); -int ide_floppy_compat_ioctl(ide_drive_t *, struct block_device *, fmode_t, - unsigned int, unsigned long); - -#ifdef CONFIG_IDE_PROC_FS -/* ide-floppy_proc.c */ -extern ide_proc_entry_t ide_floppy_proc[]; -extern const struct ide_proc_devset ide_floppy_settings[]; -#endif -#else -#define ide_floppy_proc NULL -#define ide_floppy_settings NULL -#endif - -#endif /*__IDE_FLOPPY_H */ diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c deleted file mode 100644 index 39a790ac6cc3..000000000000 --- a/drivers/ide/ide-floppy_ioctl.c +++ /dev/null @@ -1,339 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * ide-floppy IOCTLs handling. - */ - -#include -#include -#include -#include -#include - -#include - -#include - -#include "ide-floppy.h" - -/* - * Obtain the list of formattable capacities. - * Very similar to ide_floppy_get_capacity, except that we push the capacity - * descriptors to userland, instead of our own structures. - * - * Userland gives us the following structure: - * - * struct idefloppy_format_capacities { - * int nformats; - * struct { - * int nblocks; - * int blocksize; - * } formats[]; - * }; - * - * userland initializes nformats to the number of allocated formats[] records. - * On exit we set nformats to the number of records we've actually initialized. - */ - -static DEFINE_MUTEX(ide_floppy_ioctl_mutex); -static int ide_floppy_get_format_capacities(ide_drive_t *drive, - struct ide_atapi_pc *pc, - int __user *arg) -{ - struct ide_disk_obj *floppy = drive->driver_data; - int i, blocks, length, u_array_size, u_index; - int __user *argp; - u8 pc_buf[256], header_len, desc_cnt; - - if (get_user(u_array_size, arg)) - return -EFAULT; - - if (u_array_size <= 0) - return -EINVAL; - - ide_floppy_create_read_capacity_cmd(pc); - - if (ide_queue_pc_tail(drive, floppy->disk, pc, pc_buf, pc->req_xfer)) { - printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n"); - return -EIO; - } - - header_len = pc_buf[3]; - desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */ - - u_index = 0; - argp = arg + 1; - - /* - * We always skip the first capacity descriptor. That's the current - * capacity. We are interested in the remaining descriptors, the - * formattable capacities. - */ - for (i = 1; i < desc_cnt; i++) { - unsigned int desc_start = 4 + i*8; - - if (u_index >= u_array_size) - break; /* User-supplied buffer too small */ - - blocks = be32_to_cpup((__be32 *)&pc_buf[desc_start]); - length = be16_to_cpup((__be16 *)&pc_buf[desc_start + 6]); - - if (put_user(blocks, argp)) - return -EFAULT; - - ++argp; - - if (put_user(length, argp)) - return -EFAULT; - - ++argp; - - ++u_index; - } - - if (put_user(u_index, arg)) - return -EFAULT; - - return 0; -} - -static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc, - u8 *buf, int b, int l, - int flags) -{ - ide_init_pc(pc); - pc->c[0] = GPCMD_FORMAT_UNIT; - pc->c[1] = 0x17; - - memset(buf, 0, 12); - buf[1] = 0xA2; - /* Default format list header, u8 1: FOV/DCRT/IMM bits set */ - - if (flags & 1) /* Verify bit on... */ - buf[1] ^= 0x20; /* ... turn off DCRT bit */ - buf[3] = 8; - - put_unaligned(cpu_to_be32(b), (unsigned int *)(&buf[4])); - put_unaligned(cpu_to_be32(l), (unsigned int *)(&buf[8])); - pc->req_xfer = 12; - pc->flags |= PC_FLAG_WRITING; -} - -static int ide_floppy_get_sfrp_bit(ide_drive_t *drive, struct ide_atapi_pc *pc) -{ - struct ide_disk_obj *floppy = drive->driver_data; - u8 buf[20]; - - drive->atapi_flags &= ~IDE_AFLAG_SRFP; - - ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_CAPABILITIES_PAGE); - pc->flags |= PC_FLAG_SUPPRESS_ERROR; - - if (ide_queue_pc_tail(drive, floppy->disk, pc, buf, pc->req_xfer)) - return 1; - - if (buf[8 + 2] & 0x40) - drive->atapi_flags |= IDE_AFLAG_SRFP; - - return 0; -} - -static int ide_floppy_format_unit(ide_drive_t *drive, struct ide_atapi_pc *pc, - int __user *arg) -{ - struct ide_disk_obj *floppy = drive->driver_data; - u8 buf[12]; - int blocks, length, flags, err = 0; - - if (floppy->openers > 1) { - /* Don't format if someone is using the disk */ - drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS; - return -EBUSY; - } - - drive->dev_flags |= IDE_DFLAG_FORMAT_IN_PROGRESS; - - /* - * Send ATAPI_FORMAT_UNIT to the drive. - * - * Userland gives us the following structure: - * - * struct idefloppy_format_command { - * int nblocks; - * int blocksize; - * int flags; - * } ; - * - * flags is a bitmask, currently, the only defined flag is: - * - * 0x01 - verify media after format. - */ - if (get_user(blocks, arg) || - get_user(length, arg+1) || - get_user(flags, arg+2)) { - err = -EFAULT; - goto out; - } - - ide_floppy_get_sfrp_bit(drive, pc); - ide_floppy_create_format_unit_cmd(pc, buf, blocks, length, flags); - - if (ide_queue_pc_tail(drive, floppy->disk, pc, buf, pc->req_xfer)) - err = -EIO; - -out: - if (err) - drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS; - return err; -} - -/* - * Get ATAPI_FORMAT_UNIT progress indication. - * - * Userland gives a pointer to an int. The int is set to a progress - * indicator 0-65536, with 65536=100%. - * - * If the drive does not support format progress indication, we just check - * the dsc bit, and return either 0 or 65536. - */ - -static int ide_floppy_get_format_progress(ide_drive_t *drive, - struct ide_atapi_pc *pc, - int __user *arg) -{ - struct ide_disk_obj *floppy = drive->driver_data; - u8 sense_buf[18]; - int progress_indication = 0x10000; - - if (drive->atapi_flags & IDE_AFLAG_SRFP) { - ide_create_request_sense_cmd(drive, pc); - if (ide_queue_pc_tail(drive, floppy->disk, pc, sense_buf, - pc->req_xfer)) - return -EIO; - - if (floppy->sense_key == 2 && - floppy->asc == 4 && - floppy->ascq == 4) - progress_indication = floppy->progress_indication; - - /* Else assume format_unit has finished, and we're at 0x10000 */ - } else { - ide_hwif_t *hwif = drive->hwif; - unsigned long flags; - u8 stat; - - local_irq_save(flags); - stat = hwif->tp_ops->read_status(hwif); - local_irq_restore(flags); - - progress_indication = ((stat & ATA_DSC) == 0) ? 0 : 0x10000; - } - - if (put_user(progress_indication, arg)) - return -EFAULT; - - return 0; -} - -static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc, - unsigned long arg, unsigned int cmd) -{ - struct ide_disk_obj *floppy = drive->driver_data; - struct gendisk *disk = floppy->disk; - int prevent = (arg && cmd != CDROMEJECT) ? 1 : 0; - - if (floppy->openers > 1) - return -EBUSY; - - ide_set_media_lock(drive, disk, prevent); - - if (cmd == CDROMEJECT) - ide_do_start_stop(drive, disk, 2); - - return 0; -} - -static int ide_floppy_format_ioctl(ide_drive_t *drive, struct ide_atapi_pc *pc, - fmode_t mode, unsigned int cmd, - void __user *argp) -{ - switch (cmd) { - case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED: - return 0; - case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY: - return ide_floppy_get_format_capacities(drive, pc, argp); - case IDEFLOPPY_IOCTL_FORMAT_START: - if (!(mode & FMODE_WRITE)) - return -EPERM; - return ide_floppy_format_unit(drive, pc, (int __user *)argp); - case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS: - return ide_floppy_get_format_progress(drive, pc, argp); - default: - return -ENOTTY; - } -} - -int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev, - fmode_t mode, unsigned int cmd, unsigned long arg) -{ - struct ide_atapi_pc pc; - void __user *argp = (void __user *)arg; - int err; - - mutex_lock(&ide_floppy_ioctl_mutex); - if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR) { - err = ide_floppy_lockdoor(drive, &pc, arg, cmd); - goto out; - } - - err = ide_floppy_format_ioctl(drive, &pc, mode, cmd, argp); - if (err != -ENOTTY) - goto out; - - /* - * skip SCSI_IOCTL_SEND_COMMAND (deprecated) - * and CDROM_SEND_PACKET (legacy) ioctls - */ - if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND) - err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); - - if (err == -ENOTTY) - err = generic_ide_ioctl(drive, bdev, cmd, arg); - -out: - mutex_unlock(&ide_floppy_ioctl_mutex); - return err; -} - -#ifdef CONFIG_COMPAT -int ide_floppy_compat_ioctl(ide_drive_t *drive, struct block_device *bdev, - fmode_t mode, unsigned int cmd, unsigned long arg) -{ - struct ide_atapi_pc pc; - void __user *argp = compat_ptr(arg); - int err; - - mutex_lock(&ide_floppy_ioctl_mutex); - if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR) { - err = ide_floppy_lockdoor(drive, &pc, arg, cmd); - goto out; - } - - err = ide_floppy_format_ioctl(drive, &pc, mode, cmd, argp); - if (err != -ENOTTY) - goto out; - - /* - * skip SCSI_IOCTL_SEND_COMMAND (deprecated) - * and CDROM_SEND_PACKET (legacy) ioctls - */ - if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND) - err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); - - if (err == -ENOTTY) - err = generic_ide_ioctl(drive, bdev, cmd, arg); - -out: - mutex_unlock(&ide_floppy_ioctl_mutex); - return err; -} -#endif diff --git a/drivers/ide/ide-floppy_proc.c b/drivers/ide/ide-floppy_proc.c deleted file mode 100644 index 7f697ddb5fe5..000000000000 --- a/drivers/ide/ide-floppy_proc.c +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include - -#include "ide-floppy.h" - -static int idefloppy_capacity_proc_show(struct seq_file *m, void *v) -{ - ide_drive_t*drive = (ide_drive_t *)m->private; - - seq_printf(m, "%llu\n", (long long)ide_gd_capacity(drive)); - return 0; -} - -ide_proc_entry_t ide_floppy_proc[] = { - { "capacity", S_IFREG|S_IRUGO, idefloppy_capacity_proc_show }, - { "geometry", S_IFREG|S_IRUGO, ide_geometry_proc_show }, - {} -}; - -ide_devset_rw_field(bios_cyl, bios_cyl); -ide_devset_rw_field(bios_head, bios_head); -ide_devset_rw_field(bios_sect, bios_sect); -ide_devset_rw_field(ticks, pc_delay); - -const struct ide_proc_devset ide_floppy_settings[] = { - IDE_PROC_DEVSET(bios_cyl, 0, 1023), - IDE_PROC_DEVSET(bios_head, 0, 255), - IDE_PROC_DEVSET(bios_sect, 0, 63), - IDE_PROC_DEVSET(ticks, 0, 255), - { NULL }, -}; diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c deleted file mode 100644 index e2b6c82586ce..000000000000 --- a/drivers/ide/ide-gd.c +++ /dev/null @@ -1,432 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT) -#define IDE_DISK_MINORS (1 << PARTN_BITS) -#else -#define IDE_DISK_MINORS 0 -#endif - -#include "ide-disk.h" -#include "ide-floppy.h" - -#define IDE_GD_VERSION "1.18" - -/* module parameters */ -static DEFINE_MUTEX(ide_gd_mutex); -static unsigned long debug_mask; -module_param(debug_mask, ulong, 0644); - -static DEFINE_MUTEX(ide_disk_ref_mutex); - -static void ide_disk_release(struct device *); - -static struct ide_disk_obj *ide_disk_get(struct gendisk *disk) -{ - struct ide_disk_obj *idkp = NULL; - - mutex_lock(&ide_disk_ref_mutex); - idkp = ide_drv_g(disk, ide_disk_obj); - if (idkp) { - if (ide_device_get(idkp->drive)) - idkp = NULL; - else - get_device(&idkp->dev); - } - mutex_unlock(&ide_disk_ref_mutex); - return idkp; -} - -static void ide_disk_put(struct ide_disk_obj *idkp) -{ - ide_drive_t *drive = idkp->drive; - - mutex_lock(&ide_disk_ref_mutex); - put_device(&idkp->dev); - ide_device_put(drive); - mutex_unlock(&ide_disk_ref_mutex); -} - -sector_t ide_gd_capacity(ide_drive_t *drive) -{ - return drive->capacity64; -} - -static int ide_gd_probe(ide_drive_t *); - -static void ide_gd_remove(ide_drive_t *drive) -{ - struct ide_disk_obj *idkp = drive->driver_data; - struct gendisk *g = idkp->disk; - - ide_proc_unregister_driver(drive, idkp->driver); - device_del(&idkp->dev); - del_gendisk(g); - drive->disk_ops->flush(drive); - - mutex_lock(&ide_disk_ref_mutex); - put_device(&idkp->dev); - mutex_unlock(&ide_disk_ref_mutex); -} - -static void ide_disk_release(struct device *dev) -{ - struct ide_disk_obj *idkp = to_ide_drv(dev, ide_disk_obj); - ide_drive_t *drive = idkp->drive; - struct gendisk *g = idkp->disk; - - drive->disk_ops = NULL; - drive->driver_data = NULL; - g->private_data = NULL; - put_disk(g); - kfree(idkp); -} - -/* - * On HPA drives the capacity needs to be - * reinitialized on resume otherwise the disk - * can not be used and a hard reset is required - */ -static void ide_gd_resume(ide_drive_t *drive) -{ - if (ata_id_hpa_enabled(drive->id)) - (void)drive->disk_ops->get_capacity(drive); -} - -static const struct dmi_system_id ide_coldreboot_table[] = { - { - /* Acer TravelMate 66x cuts power during reboot */ - .ident = "Acer TravelMate 660", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"), - }, - }, - - { } /* terminate list */ -}; - -static void ide_gd_shutdown(ide_drive_t *drive) -{ -#ifdef CONFIG_ALPHA - /* On Alpha, halt(8) doesn't actually turn the machine off, - it puts you into the sort of firmware monitor. Typically, - it's used to boot another kernel image, so it's not much - different from reboot(8). Therefore, we don't need to - spin down the disk in this case, especially since Alpha - firmware doesn't handle disks in standby mode properly. - On the other hand, it's reasonably safe to turn the power - off when the shutdown process reaches the firmware prompt, - as the firmware initialization takes rather long time - - at least 10 seconds, which should be sufficient for - the disk to expire its write cache. */ - if (system_state != SYSTEM_POWER_OFF) { -#else - if (system_state == SYSTEM_RESTART && - !dmi_check_system(ide_coldreboot_table)) { -#endif - drive->disk_ops->flush(drive); - return; - } - - printk(KERN_INFO "Shutdown: %s\n", drive->name); - - drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND); -} - -#ifdef CONFIG_IDE_PROC_FS -static ide_proc_entry_t *ide_disk_proc_entries(ide_drive_t *drive) -{ - return (drive->media == ide_disk) ? ide_disk_proc : ide_floppy_proc; -} - -static const struct ide_proc_devset *ide_disk_proc_devsets(ide_drive_t *drive) -{ - return (drive->media == ide_disk) ? ide_disk_settings - : ide_floppy_settings; -} -#endif - -static ide_startstop_t ide_gd_do_request(ide_drive_t *drive, - struct request *rq, sector_t sector) -{ - return drive->disk_ops->do_request(drive, rq, sector); -} - -static struct ide_driver ide_gd_driver = { - .gen_driver = { - .owner = THIS_MODULE, - .name = "ide-gd", - .bus = &ide_bus_type, - }, - .probe = ide_gd_probe, - .remove = ide_gd_remove, - .resume = ide_gd_resume, - .shutdown = ide_gd_shutdown, - .version = IDE_GD_VERSION, - .do_request = ide_gd_do_request, -#ifdef CONFIG_IDE_PROC_FS - .proc_entries = ide_disk_proc_entries, - .proc_devsets = ide_disk_proc_devsets, -#endif -}; - -static int ide_gd_open(struct block_device *bdev, fmode_t mode) -{ - struct gendisk *disk = bdev->bd_disk; - struct ide_disk_obj *idkp; - ide_drive_t *drive; - int ret = 0; - - idkp = ide_disk_get(disk); - if (idkp == NULL) - return -ENXIO; - - drive = idkp->drive; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - idkp->openers++; - - if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) { - drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS; - /* Just in case */ - - ret = drive->disk_ops->init_media(drive, disk); - - /* - * Allow O_NDELAY to open a drive without a disk, or with an - * unreadable disk, so that we can get the format capacity - * of the drive or begin the format - Sam - */ - if (ret && (mode & FMODE_NDELAY) == 0) { - ret = -EIO; - goto out_put_idkp; - } - - if ((drive->dev_flags & IDE_DFLAG_WP) && (mode & FMODE_WRITE)) { - ret = -EROFS; - goto out_put_idkp; - } - - /* - * Ignore the return code from door_lock, - * since the open() has already succeeded, - * and the door_lock is irrelevant at this point. - */ - drive->disk_ops->set_doorlock(drive, disk, 1); - if (__invalidate_device(bdev, true)) - pr_warn("VFS: busy inodes on changed media %s\n", - bdev->bd_disk->disk_name); - drive->disk_ops->get_capacity(drive); - set_capacity(disk, ide_gd_capacity(drive)); - set_bit(GD_NEED_PART_SCAN, &disk->state); - } else if (drive->dev_flags & IDE_DFLAG_FORMAT_IN_PROGRESS) { - ret = -EBUSY; - goto out_put_idkp; - } - return 0; - -out_put_idkp: - idkp->openers--; - ide_disk_put(idkp); - return ret; -} - -static int ide_gd_unlocked_open(struct block_device *bdev, fmode_t mode) -{ - int ret; - - mutex_lock(&ide_gd_mutex); - ret = ide_gd_open(bdev, mode); - mutex_unlock(&ide_gd_mutex); - - return ret; -} - - -static void ide_gd_release(struct gendisk *disk, fmode_t mode) -{ - struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); - ide_drive_t *drive = idkp->drive; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - mutex_lock(&ide_gd_mutex); - if (idkp->openers == 1) - drive->disk_ops->flush(drive); - - if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) { - drive->disk_ops->set_doorlock(drive, disk, 0); - drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS; - } - - idkp->openers--; - - ide_disk_put(idkp); - mutex_unlock(&ide_gd_mutex); -} - -static int ide_gd_getgeo(struct block_device *bdev, struct hd_geometry *geo) -{ - struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj); - ide_drive_t *drive = idkp->drive; - - geo->heads = drive->bios_head; - geo->sectors = drive->bios_sect; - geo->cylinders = (u16)drive->bios_cyl; /* truncate */ - return 0; -} - -static void ide_gd_unlock_native_capacity(struct gendisk *disk) -{ - struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); - ide_drive_t *drive = idkp->drive; - const struct ide_disk_ops *disk_ops = drive->disk_ops; - - if (disk_ops->unlock_native_capacity) - disk_ops->unlock_native_capacity(drive); -} - -static int ide_gd_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj); - ide_drive_t *drive = idkp->drive; - - return drive->disk_ops->ioctl(drive, bdev, mode, cmd, arg); -} - -#ifdef CONFIG_COMPAT -static int ide_gd_compat_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj); - ide_drive_t *drive = idkp->drive; - - if (!drive->disk_ops->compat_ioctl) - return -ENOIOCTLCMD; - - return drive->disk_ops->compat_ioctl(drive, bdev, mode, cmd, arg); -} -#endif - -static const struct block_device_operations ide_gd_ops = { - .owner = THIS_MODULE, - .open = ide_gd_unlocked_open, - .release = ide_gd_release, - .ioctl = ide_gd_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ide_gd_compat_ioctl, -#endif - .getgeo = ide_gd_getgeo, - .unlock_native_capacity = ide_gd_unlock_native_capacity, -}; - -static int ide_gd_probe(ide_drive_t *drive) -{ - const struct ide_disk_ops *disk_ops = NULL; - struct ide_disk_obj *idkp; - struct gendisk *g; - - /* strstr("foo", "") is non-NULL */ - if (!strstr("ide-gd", drive->driver_req)) - goto failed; - -#ifdef CONFIG_IDE_GD_ATA - if (drive->media == ide_disk) - disk_ops = &ide_ata_disk_ops; -#endif -#ifdef CONFIG_IDE_GD_ATAPI - if (drive->media == ide_floppy) - disk_ops = &ide_atapi_disk_ops; -#endif - if (disk_ops == NULL) - goto failed; - - if (disk_ops->check(drive, DRV_NAME) == 0) { - printk(KERN_ERR PFX "%s: not supported by this driver\n", - drive->name); - goto failed; - } - - idkp = kzalloc(sizeof(*idkp), GFP_KERNEL); - if (!idkp) { - printk(KERN_ERR PFX "%s: can't allocate a disk structure\n", - drive->name); - goto failed; - } - - g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif)); - if (!g) - goto out_free_idkp; - - ide_init_disk(g, drive); - - idkp->dev.parent = &drive->gendev; - idkp->dev.release = ide_disk_release; - dev_set_name(&idkp->dev, "%s", dev_name(&drive->gendev)); - - if (device_register(&idkp->dev)) - goto out_free_disk; - - idkp->drive = drive; - idkp->driver = &ide_gd_driver; - idkp->disk = g; - - g->private_data = &idkp->driver; - - drive->driver_data = idkp; - drive->debug_mask = debug_mask; - drive->disk_ops = disk_ops; - - disk_ops->setup(drive); - - set_capacity(g, ide_gd_capacity(drive)); - - g->minors = IDE_DISK_MINORS; - g->flags |= GENHD_FL_EXT_DEVT; - if (drive->dev_flags & IDE_DFLAG_REMOVABLE) - g->flags = GENHD_FL_REMOVABLE; - g->fops = &ide_gd_ops; - g->events = DISK_EVENT_MEDIA_CHANGE; - device_add_disk(&drive->gendev, g, NULL); - return 0; - -out_free_disk: - put_disk(g); -out_free_idkp: - kfree(idkp); -failed: - return -ENODEV; -} - -static int __init ide_gd_init(void) -{ - printk(KERN_INFO DRV_NAME " driver " IDE_GD_VERSION "\n"); - return driver_register(&ide_gd_driver.gen_driver); -} - -static void __exit ide_gd_exit(void) -{ - driver_unregister(&ide_gd_driver.gen_driver); -} - -MODULE_ALIAS("ide:*m-disk*"); -MODULE_ALIAS("ide-disk"); -MODULE_ALIAS("ide:*m-floppy*"); -MODULE_ALIAS("ide-floppy"); -module_init(ide_gd_init); -module_exit(ide_gd_exit); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("generic ATA/ATAPI disk driver"); diff --git a/drivers/ide/ide-gd.h b/drivers/ide/ide-gd.h deleted file mode 100644 index af3fe1880e9e..000000000000 --- a/drivers/ide/ide-gd.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __IDE_GD_H -#define __IDE_GD_H - -#define DRV_NAME "ide-gd" -#define PFX DRV_NAME ": " - -/* define to see debug info */ -#define IDE_GD_DEBUG_LOG 0 - -#if IDE_GD_DEBUG_LOG -#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, ## args) -#else -#define ide_debug_log(lvl, fmt, args...) do {} while (0) -#endif - -struct ide_disk_obj { - ide_drive_t *drive; - struct ide_driver *driver; - struct gendisk *disk; - struct device dev; - unsigned int openers; /* protected by BKL for now */ - - /* used for blk_{fs,pc}_request() requests */ - struct ide_atapi_pc queued_pc; - - /* Last error information */ - u8 sense_key, asc, ascq; - - int progress_indication; - - /* Device information */ - /* Current format */ - int blocks, block_size, bs_factor; - /* Last format capacity descriptor */ - u8 cap_desc[8]; - /* Copy of the flexible disk page */ - u8 flexible_disk_page[32]; -}; - -sector_t ide_gd_capacity(ide_drive_t *); - -#endif /* __IDE_GD_H */ diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c deleted file mode 100644 index 80c0d69b83ac..000000000000 --- a/drivers/ide/ide-generic.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * generic/default IDE host driver - * - * Copyright (C) 2004, 2008-2009 Bartlomiej Zolnierkiewicz - * This code was split off from ide.c. See it for original copyrights. - * - * May be copied or modified under the terms of the GNU General Public License. - */ - -#include -#include -#include -#include -#include - -/* FIXME: convert arm to use ide_platform host driver */ -#ifdef CONFIG_ARM -#include -#endif - -#define DRV_NAME "ide_generic" - -static int probe_mask; -module_param(probe_mask, int, 0); -MODULE_PARM_DESC(probe_mask, "probe mask for legacy ISA IDE ports"); - -static const struct ide_port_info ide_generic_port_info = { - .host_flags = IDE_HFLAG_NO_DMA, - .chipset = ide_generic, -}; - -#ifdef CONFIG_ARM -static const u16 legacy_bases[] = { 0x1f0 }; -static const int legacy_irqs[] = { IRQ_HARDDISK }; -#elif defined(CONFIG_ALPHA) -static const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168 }; -static const int legacy_irqs[] = { 14, 15, 11, 10 }; -#else -static const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 }; -static const int legacy_irqs[] = { 14, 15, 11, 10, 8, 12 }; -#endif - -static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary) -{ -#ifdef CONFIG_PCI - struct pci_dev *p = NULL; - u16 val; - - for_each_pci_dev(p) { - if (pci_resource_start(p, 0) == 0x1f0) - *primary = 1; - if (pci_resource_start(p, 2) == 0x170) - *secondary = 1; - - /* Cyrix CS55{1,2}0 pre SFF MWDMA ATA on the bridge */ - if (p->vendor == PCI_VENDOR_ID_CYRIX && - (p->device == PCI_DEVICE_ID_CYRIX_5510 || - p->device == PCI_DEVICE_ID_CYRIX_5520)) - *primary = *secondary = 1; - - /* Intel MPIIX - PIO ATA on non PCI side of bridge */ - if (p->vendor == PCI_VENDOR_ID_INTEL && - p->device == PCI_DEVICE_ID_INTEL_82371MX) { - pci_read_config_word(p, 0x6C, &val); - if (val & 0x8000) { - /* ATA port enabled */ - if (val & 0x4000) - *secondary = 1; - else - *primary = 1; - } - } - } -#endif -} - -static int __init ide_generic_init(void) -{ - struct ide_hw hw, *hws[] = { &hw }; - unsigned long io_addr; - int i, rc = 0, primary = 0, secondary = 0; - - ide_generic_check_pci_legacy_iobases(&primary, &secondary); - - if (!probe_mask) { - printk(KERN_INFO DRV_NAME ": please use \"probe_mask=0x3f\" " - "module parameter for probing all legacy ISA IDE ports\n"); - - if (primary == 0) - probe_mask |= 0x1; - - if (secondary == 0) - probe_mask |= 0x2; - } else - printk(KERN_INFO DRV_NAME ": enforcing probing of I/O ports " - "upon user request\n"); - - for (i = 0; i < ARRAY_SIZE(legacy_bases); i++) { - io_addr = legacy_bases[i]; - - if ((probe_mask & (1 << i)) && io_addr) { - if (!request_region(io_addr, 8, DRV_NAME)) { - printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX " - "not free.\n", - DRV_NAME, io_addr, io_addr + 7); - rc = -EBUSY; - continue; - } - - if (!request_region(io_addr + 0x206, 1, DRV_NAME)) { - printk(KERN_ERR "%s: I/O resource 0x%lX " - "not free.\n", - DRV_NAME, io_addr + 0x206); - release_region(io_addr, 8); - rc = -EBUSY; - continue; - } - - memset(&hw, 0, sizeof(hw)); - ide_std_init_ports(&hw, io_addr, io_addr + 0x206); -#ifdef CONFIG_IA64 - hw.irq = isa_irq_to_vector(legacy_irqs[i]); -#else - hw.irq = legacy_irqs[i]; -#endif - rc = ide_host_add(&ide_generic_port_info, hws, 1, NULL); - if (rc) { - release_region(io_addr + 0x206, 1); - release_region(io_addr, 8); - } - } - } - - return rc; -} - -module_init(ide_generic_init); - -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ide-io-std.c b/drivers/ide/ide-io-std.c deleted file mode 100644 index 94bdcf1ea186..000000000000 --- a/drivers/ide/ide-io-std.c +++ /dev/null @@ -1,262 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -#include -#include -#include - -#if defined(CONFIG_ARM) || defined(CONFIG_M68K) || defined(CONFIG_MIPS) || \ - defined(CONFIG_PARISC) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) -#include -#else -#include -#endif - -/* - * Conventional PIO operations for ATA devices - */ - -static u8 ide_inb(unsigned long port) -{ - return (u8) inb(port); -} - -static void ide_outb(u8 val, unsigned long port) -{ - outb(val, port); -} - -/* - * MMIO operations, typically used for SATA controllers - */ - -static u8 ide_mm_inb(unsigned long port) -{ - return (u8) readb((void __iomem *) port); -} - -static void ide_mm_outb(u8 value, unsigned long port) -{ - writeb(value, (void __iomem *) port); -} - -void ide_exec_command(ide_hwif_t *hwif, u8 cmd) -{ - if (hwif->host_flags & IDE_HFLAG_MMIO) - writeb(cmd, (void __iomem *)hwif->io_ports.command_addr); - else - outb(cmd, hwif->io_ports.command_addr); -} -EXPORT_SYMBOL_GPL(ide_exec_command); - -u8 ide_read_status(ide_hwif_t *hwif) -{ - if (hwif->host_flags & IDE_HFLAG_MMIO) - return readb((void __iomem *)hwif->io_ports.status_addr); - else - return inb(hwif->io_ports.status_addr); -} -EXPORT_SYMBOL_GPL(ide_read_status); - -u8 ide_read_altstatus(ide_hwif_t *hwif) -{ - if (hwif->host_flags & IDE_HFLAG_MMIO) - return readb((void __iomem *)hwif->io_ports.ctl_addr); - else - return inb(hwif->io_ports.ctl_addr); -} -EXPORT_SYMBOL_GPL(ide_read_altstatus); - -void ide_write_devctl(ide_hwif_t *hwif, u8 ctl) -{ - if (hwif->host_flags & IDE_HFLAG_MMIO) - writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr); - else - outb(ctl, hwif->io_ports.ctl_addr); -} -EXPORT_SYMBOL_GPL(ide_write_devctl); - -void ide_dev_select(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u8 select = drive->select | ATA_DEVICE_OBS; - - if (hwif->host_flags & IDE_HFLAG_MMIO) - writeb(select, (void __iomem *)hwif->io_ports.device_addr); - else - outb(select, hwif->io_ports.device_addr); -} -EXPORT_SYMBOL_GPL(ide_dev_select); - -void ide_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_io_ports *io_ports = &hwif->io_ports; - void (*tf_outb)(u8 addr, unsigned long port); - u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; - - if (mmio) - tf_outb = ide_mm_outb; - else - tf_outb = ide_outb; - - if (valid & IDE_VALID_FEATURE) - tf_outb(tf->feature, io_ports->feature_addr); - if (valid & IDE_VALID_NSECT) - tf_outb(tf->nsect, io_ports->nsect_addr); - if (valid & IDE_VALID_LBAL) - tf_outb(tf->lbal, io_ports->lbal_addr); - if (valid & IDE_VALID_LBAM) - tf_outb(tf->lbam, io_ports->lbam_addr); - if (valid & IDE_VALID_LBAH) - tf_outb(tf->lbah, io_ports->lbah_addr); - if (valid & IDE_VALID_DEVICE) - tf_outb(tf->device, io_ports->device_addr); -} -EXPORT_SYMBOL_GPL(ide_tf_load); - -void ide_tf_read(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_io_ports *io_ports = &hwif->io_ports; - u8 (*tf_inb)(unsigned long port); - u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; - - if (mmio) - tf_inb = ide_mm_inb; - else - tf_inb = ide_inb; - - if (valid & IDE_VALID_ERROR) - tf->error = tf_inb(io_ports->feature_addr); - if (valid & IDE_VALID_NSECT) - tf->nsect = tf_inb(io_ports->nsect_addr); - if (valid & IDE_VALID_LBAL) - tf->lbal = tf_inb(io_ports->lbal_addr); - if (valid & IDE_VALID_LBAM) - tf->lbam = tf_inb(io_ports->lbam_addr); - if (valid & IDE_VALID_LBAH) - tf->lbah = tf_inb(io_ports->lbah_addr); - if (valid & IDE_VALID_DEVICE) - tf->device = tf_inb(io_ports->device_addr); -} -EXPORT_SYMBOL_GPL(ide_tf_read); - -/* - * Some localbus EIDE interfaces require a special access sequence - * when using 32-bit I/O instructions to transfer data. We call this - * the "vlb_sync" sequence, which consists of three successive reads - * of the sector count register location, with interrupts disabled - * to ensure that the reads all happen together. - */ -static void ata_vlb_sync(unsigned long port) -{ - (void)inb(port); - (void)inb(port); - (void)inb(port); -} - -/* - * This is used for most PIO data transfers *from* the IDE interface - * - * These routines will round up any request for an odd number of bytes, - * so if an odd len is specified, be sure that there's at least one - * extra byte allocated for the buffer. - */ -void ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf, - unsigned int len) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_io_ports *io_ports = &hwif->io_ports; - unsigned long data_addr = io_ports->data_addr; - unsigned int words = (len + 1) >> 1; - u8 io_32bit = drive->io_32bit; - u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; - - if (io_32bit) { - unsigned long flags; - - if ((io_32bit & 2) && !mmio) { - local_irq_save(flags); - ata_vlb_sync(io_ports->nsect_addr); - } - - words >>= 1; - if (mmio) - __ide_mm_insl((void __iomem *)data_addr, buf, words); - else - insl(data_addr, buf, words); - - if ((io_32bit & 2) && !mmio) - local_irq_restore(flags); - - if (((len + 1) & 3) < 2) - return; - - buf += len & ~3; - words = 1; - } - - if (mmio) - __ide_mm_insw((void __iomem *)data_addr, buf, words); - else - insw(data_addr, buf, words); -} -EXPORT_SYMBOL_GPL(ide_input_data); - -/* - * This is used for most PIO data transfers *to* the IDE interface - */ -void ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf, - unsigned int len) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_io_ports *io_ports = &hwif->io_ports; - unsigned long data_addr = io_ports->data_addr; - unsigned int words = (len + 1) >> 1; - u8 io_32bit = drive->io_32bit; - u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; - - if (io_32bit) { - unsigned long flags; - - if ((io_32bit & 2) && !mmio) { - local_irq_save(flags); - ata_vlb_sync(io_ports->nsect_addr); - } - - words >>= 1; - if (mmio) - __ide_mm_outsl((void __iomem *)data_addr, buf, words); - else - outsl(data_addr, buf, words); - - if ((io_32bit & 2) && !mmio) - local_irq_restore(flags); - - if (((len + 1) & 3) < 2) - return; - - buf += len & ~3; - words = 1; - } - - if (mmio) - __ide_mm_outsw((void __iomem *)data_addr, buf, words); - else - outsw(data_addr, buf, words); -} -EXPORT_SYMBOL_GPL(ide_output_data); - -const struct ide_tp_ops default_tp_ops = { - .exec_command = ide_exec_command, - .read_status = ide_read_status, - .read_altstatus = ide_read_altstatus, - .write_devctl = ide_write_devctl, - - .dev_select = ide_dev_select, - .tf_load = ide_tf_load, - .tf_read = ide_tf_read, - - .input_data = ide_input_data, - .output_data = ide_output_data, -}; diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c deleted file mode 100644 index 4867b67b60d6..000000000000 --- a/drivers/ide/ide-io.c +++ /dev/null @@ -1,904 +0,0 @@ -/* - * IDE I/O functions - * - * Basic PIO and command management functionality. - * - * This code was split off from ide.c. See ide.c for history and original - * copyrights. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * For the avoidance of doubt the "preferred form" of this code is one which - * is in an open non patent encumbered format. Where cryptographic key signing - * forms part of the process of creating an executable the information - * including keys needed to generate an equivalently functional executable - * are deemed to be part of the source code. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -int ide_end_rq(ide_drive_t *drive, struct request *rq, blk_status_t error, - unsigned int nr_bytes) -{ - /* - * decide whether to reenable DMA -- 3 is a random magic for now, - * if we DMA timeout more than 3 times, just stay in PIO - */ - if ((drive->dev_flags & IDE_DFLAG_DMA_PIO_RETRY) && - drive->retry_pio <= 3) { - drive->dev_flags &= ~IDE_DFLAG_DMA_PIO_RETRY; - ide_dma_on(drive); - } - - if (!blk_update_request(rq, error, nr_bytes)) { - if (rq == drive->sense_rq) { - drive->sense_rq = NULL; - drive->sense_rq_active = false; - } - - __blk_mq_end_request(rq, error); - return 0; - } - - return 1; -} -EXPORT_SYMBOL_GPL(ide_end_rq); - -void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err) -{ - const struct ide_tp_ops *tp_ops = drive->hwif->tp_ops; - struct ide_taskfile *tf = &cmd->tf; - struct request *rq = cmd->rq; - u8 tf_cmd = tf->command; - - tf->error = err; - tf->status = stat; - - if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) { - u8 data[2]; - - tp_ops->input_data(drive, cmd, data, 2); - - cmd->tf.data = data[0]; - cmd->hob.data = data[1]; - } - - ide_tf_readback(drive, cmd); - - if ((cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) && - tf_cmd == ATA_CMD_IDLEIMMEDIATE) { - if (tf->lbal != 0xc4) { - printk(KERN_ERR "%s: head unload failed!\n", - drive->name); - ide_tf_dump(drive->name, cmd); - } else - drive->dev_flags |= IDE_DFLAG_PARKED; - } - - if (rq && ata_taskfile_request(rq)) { - struct ide_cmd *orig_cmd = ide_req(rq)->special; - - if (cmd->tf_flags & IDE_TFLAG_DYN) - kfree(orig_cmd); - else if (cmd != orig_cmd) - memcpy(orig_cmd, cmd, sizeof(*cmd)); - } -} - -int ide_complete_rq(ide_drive_t *drive, blk_status_t error, unsigned int nr_bytes) -{ - ide_hwif_t *hwif = drive->hwif; - struct request *rq = hwif->rq; - int rc; - - /* - * if failfast is set on a request, override number of sectors - * and complete the whole request right now - */ - if (blk_noretry_request(rq) && error) - nr_bytes = blk_rq_sectors(rq) << 9; - - rc = ide_end_rq(drive, rq, error, nr_bytes); - if (rc == 0) - hwif->rq = NULL; - - return rc; -} -EXPORT_SYMBOL(ide_complete_rq); - -void ide_kill_rq(ide_drive_t *drive, struct request *rq) -{ - u8 drv_req = ata_misc_request(rq) && rq->rq_disk; - u8 media = drive->media; - - drive->failed_pc = NULL; - - if ((media == ide_floppy || media == ide_tape) && drv_req) { - scsi_req(rq)->result = 0; - } else { - if (media == ide_tape) - scsi_req(rq)->result = IDE_DRV_ERROR_GENERAL; - else if (blk_rq_is_passthrough(rq) && scsi_req(rq)->result == 0) - scsi_req(rq)->result = -EIO; - } - - ide_complete_rq(drive, BLK_STS_IOERR, blk_rq_bytes(rq)); -} - -static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf) -{ - tf->nsect = drive->sect; - tf->lbal = drive->sect; - tf->lbam = drive->cyl; - tf->lbah = drive->cyl >> 8; - tf->device = (drive->head - 1) | drive->select; - tf->command = ATA_CMD_INIT_DEV_PARAMS; -} - -static void ide_tf_set_restore_cmd(ide_drive_t *drive, struct ide_taskfile *tf) -{ - tf->nsect = drive->sect; - tf->command = ATA_CMD_RESTORE; -} - -static void ide_tf_set_setmult_cmd(ide_drive_t *drive, struct ide_taskfile *tf) -{ - tf->nsect = drive->mult_req; - tf->command = ATA_CMD_SET_MULTI; -} - -/** - * do_special - issue some special commands - * @drive: drive the command is for - * - * do_special() is used to issue ATA_CMD_INIT_DEV_PARAMS, - * ATA_CMD_RESTORE and ATA_CMD_SET_MULTI commands to a drive. - */ - -static ide_startstop_t do_special(ide_drive_t *drive) -{ - struct ide_cmd cmd; - -#ifdef DEBUG - printk(KERN_DEBUG "%s: %s: 0x%02x\n", drive->name, __func__, - drive->special_flags); -#endif - if (drive->media != ide_disk) { - drive->special_flags = 0; - drive->mult_req = 0; - return ide_stopped; - } - - memset(&cmd, 0, sizeof(cmd)); - cmd.protocol = ATA_PROT_NODATA; - - if (drive->special_flags & IDE_SFLAG_SET_GEOMETRY) { - drive->special_flags &= ~IDE_SFLAG_SET_GEOMETRY; - ide_tf_set_specify_cmd(drive, &cmd.tf); - } else if (drive->special_flags & IDE_SFLAG_RECALIBRATE) { - drive->special_flags &= ~IDE_SFLAG_RECALIBRATE; - ide_tf_set_restore_cmd(drive, &cmd.tf); - } else if (drive->special_flags & IDE_SFLAG_SET_MULTMODE) { - drive->special_flags &= ~IDE_SFLAG_SET_MULTMODE; - ide_tf_set_setmult_cmd(drive, &cmd.tf); - } else - BUG(); - - cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - cmd.tf_flags = IDE_TFLAG_CUSTOM_HANDLER; - - do_rw_taskfile(drive, &cmd); - - return ide_started; -} - -void ide_map_sg(ide_drive_t *drive, struct ide_cmd *cmd) -{ - ide_hwif_t *hwif = drive->hwif; - struct scatterlist *sg = hwif->sg_table, *last_sg = NULL; - struct request *rq = cmd->rq; - - cmd->sg_nents = __blk_rq_map_sg(drive->queue, rq, sg, &last_sg); - if (blk_rq_bytes(rq) && (blk_rq_bytes(rq) & rq->q->dma_pad_mask)) - last_sg->length += - (rq->q->dma_pad_mask & ~blk_rq_bytes(rq)) + 1; -} -EXPORT_SYMBOL_GPL(ide_map_sg); - -void ide_init_sg_cmd(struct ide_cmd *cmd, unsigned int nr_bytes) -{ - cmd->nbytes = cmd->nleft = nr_bytes; - cmd->cursg_ofs = 0; - cmd->cursg = NULL; -} -EXPORT_SYMBOL_GPL(ide_init_sg_cmd); - -/** - * execute_drive_command - issue special drive command - * @drive: the drive to issue the command on - * @rq: the request structure holding the command - * - * execute_drive_cmd() issues a special drive command, usually - * initiated by ioctl() from the external hdparm program. The - * command can be a drive command, drive task or taskfile - * operation. Weirdly you can call it with NULL to wait for - * all commands to finish. Don't do this as that is due to change - */ - -static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, - struct request *rq) -{ - struct ide_cmd *cmd = ide_req(rq)->special; - - if (cmd) { - if (cmd->protocol == ATA_PROT_PIO) { - ide_init_sg_cmd(cmd, blk_rq_sectors(rq) << 9); - ide_map_sg(drive, cmd); - } - - return do_rw_taskfile(drive, cmd); - } - - /* - * NULL is actually a valid way of waiting for - * all current requests to be flushed from the queue. - */ -#ifdef DEBUG - printk("%s: DRIVE_CMD (null)\n", drive->name); -#endif - scsi_req(rq)->result = 0; - ide_complete_rq(drive, BLK_STS_OK, blk_rq_bytes(rq)); - - return ide_stopped; -} - -static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq) -{ - u8 cmd = scsi_req(rq)->cmd[0]; - - switch (cmd) { - case REQ_PARK_HEADS: - case REQ_UNPARK_HEADS: - return ide_do_park_unpark(drive, rq); - case REQ_DEVSET_EXEC: - return ide_do_devset(drive, rq); - case REQ_DRIVE_RESET: - return ide_do_reset(drive); - default: - BUG(); - } -} - -/** - * start_request - start of I/O and command issuing for IDE - * - * start_request() initiates handling of a new I/O request. It - * accepts commands and I/O (read/write) requests. - * - * FIXME: this function needs a rename - */ - -static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) -{ - ide_startstop_t startstop; - -#ifdef DEBUG - printk("%s: start_request: current=0x%08lx\n", - drive->hwif->name, (unsigned long) rq); -#endif - - /* bail early if we've exceeded max_failures */ - if (drive->max_failures && (drive->failures > drive->max_failures)) { - rq->rq_flags |= RQF_FAILED; - goto kill_rq; - } - - if (drive->prep_rq && !drive->prep_rq(drive, rq)) - return ide_stopped; - - if (ata_pm_request(rq)) - ide_check_pm_state(drive, rq); - - drive->hwif->tp_ops->dev_select(drive); - if (ide_wait_stat(&startstop, drive, drive->ready_stat, - ATA_BUSY | ATA_DRQ, WAIT_READY)) { - printk(KERN_ERR "%s: drive not ready for command\n", drive->name); - return startstop; - } - - if (drive->special_flags == 0) { - struct ide_driver *drv; - - /* - * We reset the drive so we need to issue a SETFEATURES. - * Do it _after_ do_special() restored device parameters. - */ - if (drive->current_speed == 0xff) - ide_config_drive_speed(drive, drive->desired_speed); - - if (ata_taskfile_request(rq)) - return execute_drive_cmd(drive, rq); - else if (ata_pm_request(rq)) { - struct ide_pm_state *pm = ide_req(rq)->special; -#ifdef DEBUG_PM - printk("%s: start_power_step(step: %d)\n", - drive->name, pm->pm_step); -#endif - startstop = ide_start_power_step(drive, rq); - if (startstop == ide_stopped && - pm->pm_step == IDE_PM_COMPLETED) - ide_complete_pm_rq(drive, rq); - return startstop; - } else if (!rq->rq_disk && ata_misc_request(rq)) - /* - * TODO: Once all ULDs have been modified to - * check for specific op codes rather than - * blindly accepting any special request, the - * check for ->rq_disk above may be replaced - * by a more suitable mechanism or even - * dropped entirely. - */ - return ide_special_rq(drive, rq); - - drv = *(struct ide_driver **)rq->rq_disk->private_data; - - return drv->do_request(drive, rq, blk_rq_pos(rq)); - } - return do_special(drive); -kill_rq: - ide_kill_rq(drive, rq); - return ide_stopped; -} - -/** - * ide_stall_queue - pause an IDE device - * @drive: drive to stall - * @timeout: time to stall for (jiffies) - * - * ide_stall_queue() can be used by a drive to give excess bandwidth back - * to the port by sleeping for timeout jiffies. - */ - -void ide_stall_queue (ide_drive_t *drive, unsigned long timeout) -{ - if (timeout > WAIT_WORSTCASE) - timeout = WAIT_WORSTCASE; - drive->sleep = timeout + jiffies; - drive->dev_flags |= IDE_DFLAG_SLEEPING; -} -EXPORT_SYMBOL(ide_stall_queue); - -static inline int ide_lock_port(ide_hwif_t *hwif) -{ - if (hwif->busy) - return 1; - - hwif->busy = 1; - - return 0; -} - -static inline void ide_unlock_port(ide_hwif_t *hwif) -{ - hwif->busy = 0; -} - -static inline int ide_lock_host(struct ide_host *host, ide_hwif_t *hwif) -{ - int rc = 0; - - if (host->host_flags & IDE_HFLAG_SERIALIZE) { - rc = test_and_set_bit_lock(IDE_HOST_BUSY, &host->host_busy); - if (rc == 0) { - if (host->get_lock) - host->get_lock(ide_intr, hwif); - } - } - return rc; -} - -static inline void ide_unlock_host(struct ide_host *host) -{ - if (host->host_flags & IDE_HFLAG_SERIALIZE) { - if (host->release_lock) - host->release_lock(); - clear_bit_unlock(IDE_HOST_BUSY, &host->host_busy); - } -} - -void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq) -{ - struct request_queue *q = drive->queue; - - /* Use 3ms as that was the old plug delay */ - if (rq) { - blk_mq_requeue_request(rq, false); - blk_mq_delay_kick_requeue_list(q, 3); - } else - blk_mq_delay_run_hw_queue(q->queue_hw_ctx[0], 3); -} - -blk_status_t ide_issue_rq(ide_drive_t *drive, struct request *rq, - bool local_requeue) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_host *host = hwif->host; - ide_startstop_t startstop; - - if (!blk_rq_is_passthrough(rq) && !(rq->rq_flags & RQF_DONTPREP)) { - rq->rq_flags |= RQF_DONTPREP; - ide_req(rq)->special = NULL; - } - - /* HLD do_request() callback might sleep, make sure it's okay */ - might_sleep(); - - if (ide_lock_host(host, hwif)) - return BLK_STS_DEV_RESOURCE; - - spin_lock_irq(&hwif->lock); - - if (!ide_lock_port(hwif)) { - ide_hwif_t *prev_port; - - WARN_ON_ONCE(hwif->rq); -repeat: - prev_port = hwif->host->cur_port; - if (drive->dev_flags & IDE_DFLAG_SLEEPING && - time_after(drive->sleep, jiffies)) { - ide_unlock_port(hwif); - goto plug_device; - } - - if ((hwif->host->host_flags & IDE_HFLAG_SERIALIZE) && - hwif != prev_port) { - ide_drive_t *cur_dev = - prev_port ? prev_port->cur_dev : NULL; - - /* - * set nIEN for previous port, drives in the - * quirk list may not like intr setups/cleanups - */ - if (cur_dev && - (cur_dev->dev_flags & IDE_DFLAG_NIEN_QUIRK) == 0) - prev_port->tp_ops->write_devctl(prev_port, - ATA_NIEN | - ATA_DEVCTL_OBS); - - hwif->host->cur_port = hwif; - } - hwif->cur_dev = drive; - drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED); - - /* - * Sanity: don't accept a request that isn't a PM request - * if we are currently power managed. This is very important as - * blk_stop_queue() doesn't prevent the blk_fetch_request() - * above to return us whatever is in the queue. Since we call - * ide_do_request() ourselves, we end up taking requests while - * the queue is blocked... - */ - if ((drive->dev_flags & IDE_DFLAG_BLOCKED) && - ata_pm_request(rq) == 0 && - (rq->rq_flags & RQF_PM) == 0) { - /* there should be no pending command at this point */ - ide_unlock_port(hwif); - goto plug_device; - } - - scsi_req(rq)->resid_len = blk_rq_bytes(rq); - hwif->rq = rq; - - spin_unlock_irq(&hwif->lock); - startstop = start_request(drive, rq); - spin_lock_irq(&hwif->lock); - - if (startstop == ide_stopped) { - rq = hwif->rq; - hwif->rq = NULL; - if (rq) - goto repeat; - ide_unlock_port(hwif); - goto out; - } - } else { -plug_device: - if (local_requeue) - list_add(&rq->queuelist, &drive->rq_list); - spin_unlock_irq(&hwif->lock); - ide_unlock_host(host); - if (!local_requeue) - ide_requeue_and_plug(drive, rq); - return BLK_STS_OK; - } - -out: - spin_unlock_irq(&hwif->lock); - if (rq == NULL) - ide_unlock_host(host); - return BLK_STS_OK; -} - -/* - * Issue a new request to a device. - */ -blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx, - const struct blk_mq_queue_data *bd) -{ - ide_drive_t *drive = hctx->queue->queuedata; - ide_hwif_t *hwif = drive->hwif; - - spin_lock_irq(&hwif->lock); - if (drive->sense_rq_active) { - spin_unlock_irq(&hwif->lock); - return BLK_STS_DEV_RESOURCE; - } - spin_unlock_irq(&hwif->lock); - - blk_mq_start_request(bd->rq); - return ide_issue_rq(drive, bd->rq, false); -} - -static int drive_is_ready(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u8 stat = 0; - - if (drive->waiting_for_dma) - return hwif->dma_ops->dma_test_irq(drive); - - if (hwif->io_ports.ctl_addr && - (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0) - stat = hwif->tp_ops->read_altstatus(hwif); - else - /* Note: this may clear a pending IRQ!! */ - stat = hwif->tp_ops->read_status(hwif); - - if (stat & ATA_BUSY) - /* drive busy: definitely not interrupting */ - return 0; - - /* drive ready: *might* be interrupting */ - return 1; -} - -/** - * ide_timer_expiry - handle lack of an IDE interrupt - * @data: timer callback magic (hwif) - * - * An IDE command has timed out before the expected drive return - * occurred. At this point we attempt to clean up the current - * mess. If the current handler includes an expiry handler then - * we invoke the expiry handler, and providing it is happy the - * work is done. If that fails we apply generic recovery rules - * invoking the handler and checking the drive DMA status. We - * have an excessively incestuous relationship with the DMA - * logic that wants cleaning up. - */ - -void ide_timer_expiry (struct timer_list *t) -{ - ide_hwif_t *hwif = from_timer(hwif, t, timer); - ide_drive_t *drive; - ide_handler_t *handler; - unsigned long flags; - int wait = -1; - int plug_device = 0; - struct request *rq_in_flight; - - spin_lock_irqsave(&hwif->lock, flags); - - handler = hwif->handler; - - if (handler == NULL || hwif->req_gen != hwif->req_gen_timer) { - /* - * Either a marginal timeout occurred - * (got the interrupt just as timer expired), - * or we were "sleeping" to give other devices a chance. - * Either way, we don't really want to complain about anything. - */ - } else { - ide_expiry_t *expiry = hwif->expiry; - ide_startstop_t startstop = ide_stopped; - - drive = hwif->cur_dev; - - if (expiry) { - wait = expiry(drive); - if (wait > 0) { /* continue */ - /* reset timer */ - hwif->timer.expires = jiffies + wait; - hwif->req_gen_timer = hwif->req_gen; - add_timer(&hwif->timer); - spin_unlock_irqrestore(&hwif->lock, flags); - return; - } - } - hwif->handler = NULL; - hwif->expiry = NULL; - /* - * We need to simulate a real interrupt when invoking - * the handler() function, which means we need to - * globally mask the specific IRQ: - */ - spin_unlock(&hwif->lock); - /* disable_irq_nosync ?? */ - disable_irq(hwif->irq); - - if (hwif->polling) { - startstop = handler(drive); - } else if (drive_is_ready(drive)) { - if (drive->waiting_for_dma) - hwif->dma_ops->dma_lost_irq(drive); - if (hwif->port_ops && hwif->port_ops->clear_irq) - hwif->port_ops->clear_irq(drive); - - printk(KERN_WARNING "%s: lost interrupt\n", - drive->name); - startstop = handler(drive); - } else { - if (drive->waiting_for_dma) - startstop = ide_dma_timeout_retry(drive, wait); - else - startstop = ide_error(drive, "irq timeout", - hwif->tp_ops->read_status(hwif)); - } - /* Disable interrupts again, `handler' might have enabled it */ - spin_lock_irq(&hwif->lock); - enable_irq(hwif->irq); - if (startstop == ide_stopped && hwif->polling == 0) { - rq_in_flight = hwif->rq; - hwif->rq = NULL; - ide_unlock_port(hwif); - plug_device = 1; - } - } - spin_unlock_irqrestore(&hwif->lock, flags); - - if (plug_device) { - ide_unlock_host(hwif->host); - ide_requeue_and_plug(drive, rq_in_flight); - } -} - -/** - * unexpected_intr - handle an unexpected IDE interrupt - * @irq: interrupt line - * @hwif: port being processed - * - * There's nothing really useful we can do with an unexpected interrupt, - * other than reading the status register (to clear it), and logging it. - * There should be no way that an irq can happen before we're ready for it, - * so we needn't worry much about losing an "important" interrupt here. - * - * On laptops (and "green" PCs), an unexpected interrupt occurs whenever - * the drive enters "idle", "standby", or "sleep" mode, so if the status - * looks "good", we just ignore the interrupt completely. - * - * This routine assumes __cli() is in effect when called. - * - * If an unexpected interrupt happens on irq15 while we are handling irq14 - * and if the two interfaces are "serialized" (CMD640), then it looks like - * we could screw up by interfering with a new request being set up for - * irq15. - * - * In reality, this is a non-issue. The new command is not sent unless - * the drive is ready to accept one, in which case we know the drive is - * not trying to interrupt us. And ide_set_handler() is always invoked - * before completing the issuance of any new drive command, so we will not - * be accidentally invoked as a result of any valid command completion - * interrupt. - */ - -static void unexpected_intr(int irq, ide_hwif_t *hwif) -{ - u8 stat = hwif->tp_ops->read_status(hwif); - - if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) { - /* Try to not flood the console with msgs */ - static unsigned long last_msgtime, count; - ++count; - - if (time_after(jiffies, last_msgtime + HZ)) { - last_msgtime = jiffies; - printk(KERN_ERR "%s: unexpected interrupt, " - "status=0x%02x, count=%ld\n", - hwif->name, stat, count); - } - } -} - -/** - * ide_intr - default IDE interrupt handler - * @irq: interrupt number - * @dev_id: hwif - * @regs: unused weirdness from the kernel irq layer - * - * This is the default IRQ handler for the IDE layer. You should - * not need to override it. If you do be aware it is subtle in - * places - * - * hwif is the interface in the group currently performing - * a command. hwif->cur_dev is the drive and hwif->handler is - * the IRQ handler to call. As we issue a command the handlers - * step through multiple states, reassigning the handler to the - * next step in the process. Unlike a smart SCSI controller IDE - * expects the main processor to sequence the various transfer - * stages. We also manage a poll timer to catch up with most - * timeout situations. There are still a few where the handlers - * don't ever decide to give up. - * - * The handler eventually returns ide_stopped to indicate the - * request completed. At this point we issue the next request - * on the port and the process begins again. - */ - -irqreturn_t ide_intr (int irq, void *dev_id) -{ - ide_hwif_t *hwif = (ide_hwif_t *)dev_id; - struct ide_host *host = hwif->host; - ide_drive_t *drive; - ide_handler_t *handler; - unsigned long flags; - ide_startstop_t startstop; - irqreturn_t irq_ret = IRQ_NONE; - int plug_device = 0; - struct request *rq_in_flight; - - if (host->host_flags & IDE_HFLAG_SERIALIZE) { - if (hwif != host->cur_port) - goto out_early; - } - - spin_lock_irqsave(&hwif->lock, flags); - - if (hwif->port_ops && hwif->port_ops->test_irq && - hwif->port_ops->test_irq(hwif) == 0) - goto out; - - handler = hwif->handler; - - if (handler == NULL || hwif->polling) { - /* - * Not expecting an interrupt from this drive. - * That means this could be: - * (1) an interrupt from another PCI device - * sharing the same PCI INT# as us. - * or (2) a drive just entered sleep or standby mode, - * and is interrupting to let us know. - * or (3) a spurious interrupt of unknown origin. - * - * For PCI, we cannot tell the difference, - * so in that case we just ignore it and hope it goes away. - */ - if ((host->irq_flags & IRQF_SHARED) == 0) { - /* - * Probably not a shared PCI interrupt, - * so we can safely try to do something about it: - */ - unexpected_intr(irq, hwif); - } else { - /* - * Whack the status register, just in case - * we have a leftover pending IRQ. - */ - (void)hwif->tp_ops->read_status(hwif); - } - goto out; - } - - drive = hwif->cur_dev; - - if (!drive_is_ready(drive)) - /* - * This happens regularly when we share a PCI IRQ with - * another device. Unfortunately, it can also happen - * with some buggy drives that trigger the IRQ before - * their status register is up to date. Hopefully we have - * enough advance overhead that the latter isn't a problem. - */ - goto out; - - hwif->handler = NULL; - hwif->expiry = NULL; - hwif->req_gen++; - del_timer(&hwif->timer); - spin_unlock(&hwif->lock); - - if (hwif->port_ops && hwif->port_ops->clear_irq) - hwif->port_ops->clear_irq(drive); - - if (drive->dev_flags & IDE_DFLAG_UNMASK) - local_irq_enable_in_hardirq(); - - /* service this interrupt, may set handler for next interrupt */ - startstop = handler(drive); - - spin_lock_irq(&hwif->lock); - /* - * Note that handler() may have set things up for another - * interrupt to occur soon, but it cannot happen until - * we exit from this routine, because it will be the - * same irq as is currently being serviced here, and Linux - * won't allow another of the same (on any CPU) until we return. - */ - if (startstop == ide_stopped && hwif->polling == 0) { - BUG_ON(hwif->handler); - rq_in_flight = hwif->rq; - hwif->rq = NULL; - ide_unlock_port(hwif); - plug_device = 1; - } - irq_ret = IRQ_HANDLED; -out: - spin_unlock_irqrestore(&hwif->lock, flags); -out_early: - if (plug_device) { - ide_unlock_host(hwif->host); - ide_requeue_and_plug(drive, rq_in_flight); - } - - return irq_ret; -} -EXPORT_SYMBOL_GPL(ide_intr); - -void ide_pad_transfer(ide_drive_t *drive, int write, int len) -{ - ide_hwif_t *hwif = drive->hwif; - u8 buf[4] = { 0 }; - - while (len > 0) { - if (write) - hwif->tp_ops->output_data(drive, NULL, buf, min(4, len)); - else - hwif->tp_ops->input_data(drive, NULL, buf, min(4, len)); - len -= 4; - } -} -EXPORT_SYMBOL_GPL(ide_pad_transfer); - -void ide_insert_request_head(ide_drive_t *drive, struct request *rq) -{ - drive->sense_rq_active = true; - list_add_tail(&rq->queuelist, &drive->rq_list); - kblockd_schedule_work(&drive->rq_work); -} -EXPORT_SYMBOL_GPL(ide_insert_request_head); diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c deleted file mode 100644 index 43fbc37d85c3..000000000000 --- a/drivers/ide/ide-ioctls.c +++ /dev/null @@ -1,306 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * IDE ioctls handling. - */ - -#include -#include -#include -#include -#include - -static int put_user_long(long val, unsigned long arg) -{ - if (in_compat_syscall()) - return put_user(val, (compat_long_t __user *)compat_ptr(arg)); - - return put_user(val, (long __user *)arg); -} - -static const struct ide_ioctl_devset ide_ioctl_settings[] = { -{ HDIO_GET_32BIT, HDIO_SET_32BIT, &ide_devset_io_32bit }, -{ HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, &ide_devset_keepsettings }, -{ HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, &ide_devset_unmaskirq }, -{ HDIO_GET_DMA, HDIO_SET_DMA, &ide_devset_using_dma }, -{ -1, HDIO_SET_PIO_MODE, &ide_devset_pio_mode }, -{ 0 } -}; - -int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev, - unsigned int cmd, unsigned long arg, - const struct ide_ioctl_devset *s) -{ - const struct ide_devset *ds; - int err = -EOPNOTSUPP; - - for (; (ds = s->setting); s++) { - if (ds->get && s->get_ioctl == cmd) - goto read_val; - else if (ds->set && s->set_ioctl == cmd) - goto set_val; - } - - return err; - -read_val: - mutex_lock(&ide_setting_mtx); - err = ds->get(drive); - mutex_unlock(&ide_setting_mtx); - return err >= 0 ? put_user_long(err, arg) : err; - -set_val: - if (bdev_is_partition(bdev)) - err = -EINVAL; - else { - if (!capable(CAP_SYS_ADMIN)) - err = -EACCES; - else { - mutex_lock(&ide_setting_mtx); - err = ide_devset_execute(drive, ds, arg); - mutex_unlock(&ide_setting_mtx); - } - } - return err; -} -EXPORT_SYMBOL_GPL(ide_setting_ioctl); - -static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd, - void __user *argp) -{ - u16 *id = NULL; - int size = (cmd == HDIO_GET_IDENTITY) ? (ATA_ID_WORDS * 2) : 142; - int rc = 0; - - if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) { - rc = -ENOMSG; - goto out; - } - - /* ata_id_to_hd_driveid() relies on 'id' to be fully allocated. */ - id = kmalloc(ATA_ID_WORDS * 2, GFP_KERNEL); - if (id == NULL) { - rc = -ENOMEM; - goto out; - } - - memcpy(id, drive->id, size); - ata_id_to_hd_driveid(id); - - if (copy_to_user(argp, id, size)) - rc = -EFAULT; - - kfree(id); -out: - return rc; -} - -static int ide_get_nice_ioctl(ide_drive_t *drive, unsigned long arg) -{ - return put_user_long((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) - << IDE_NICE_DSC_OVERLAP) | - (!!(drive->dev_flags & IDE_DFLAG_NICE1) - << IDE_NICE_1), arg); -} - -static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg) -{ - if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1)))) - return -EPERM; - - if (((arg >> IDE_NICE_DSC_OVERLAP) & 1) && - (drive->media != ide_tape)) - return -EPERM; - - if ((arg >> IDE_NICE_DSC_OVERLAP) & 1) - drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP; - else - drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP; - - if ((arg >> IDE_NICE_1) & 1) - drive->dev_flags |= IDE_DFLAG_NICE1; - else - drive->dev_flags &= ~IDE_DFLAG_NICE1; - - return 0; -} - -static int ide_cmd_ioctl(ide_drive_t *drive, void __user *argp) -{ - u8 *buf = NULL; - int bufsize = 0, err = 0; - u8 args[4], xfer_rate = 0; - struct ide_cmd cmd; - struct ide_taskfile *tf = &cmd.tf; - - if (NULL == argp) { - struct request *rq; - - rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); - ide_req(rq)->type = ATA_PRIV_TASKFILE; - blk_execute_rq(NULL, rq, 0); - err = scsi_req(rq)->result ? -EIO : 0; - blk_put_request(rq); - - return err; - } - - if (copy_from_user(args, argp, 4)) - return -EFAULT; - - memset(&cmd, 0, sizeof(cmd)); - tf->feature = args[2]; - if (args[0] == ATA_CMD_SMART) { - tf->nsect = args[3]; - tf->lbal = args[1]; - tf->lbam = ATA_SMART_LBAM_PASS; - tf->lbah = ATA_SMART_LBAH_PASS; - cmd.valid.out.tf = IDE_VALID_OUT_TF; - cmd.valid.in.tf = IDE_VALID_NSECT; - } else { - tf->nsect = args[1]; - cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT; - cmd.valid.in.tf = IDE_VALID_NSECT; - } - tf->command = args[0]; - cmd.protocol = args[3] ? ATA_PROT_PIO : ATA_PROT_NODATA; - - if (args[3]) { - cmd.tf_flags |= IDE_TFLAG_IO_16BIT; - bufsize = SECTOR_SIZE * args[3]; - buf = kzalloc(bufsize, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - } - - if (tf->command == ATA_CMD_SET_FEATURES && - tf->feature == SETFEATURES_XFER && - tf->nsect >= XFER_SW_DMA_0) { - xfer_rate = ide_find_dma_mode(drive, tf->nsect); - if (xfer_rate != tf->nsect) { - err = -EINVAL; - goto abort; - } - - cmd.tf_flags |= IDE_TFLAG_SET_XFER; - } - - err = ide_raw_taskfile(drive, &cmd, buf, args[3]); - - args[0] = tf->status; - args[1] = tf->error; - args[2] = tf->nsect; -abort: - if (copy_to_user(argp, &args, 4)) - err = -EFAULT; - if (buf) { - if (copy_to_user((argp + 4), buf, bufsize)) - err = -EFAULT; - kfree(buf); - } - return err; -} - -static int ide_task_ioctl(ide_drive_t *drive, void __user *p) -{ - int err = 0; - u8 args[7]; - struct ide_cmd cmd; - - if (copy_from_user(args, p, 7)) - return -EFAULT; - - memset(&cmd, 0, sizeof(cmd)); - memcpy(&cmd.tf.feature, &args[1], 6); - cmd.tf.command = args[0]; - cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - - err = ide_no_data_taskfile(drive, &cmd); - - args[0] = cmd.tf.command; - memcpy(&args[1], &cmd.tf.feature, 6); - - if (copy_to_user(p, args, 7)) - err = -EFAULT; - - return err; -} - -static int generic_drive_reset(ide_drive_t *drive) -{ - struct request *rq; - int ret = 0; - - rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); - ide_req(rq)->type = ATA_PRIV_MISC; - scsi_req(rq)->cmd_len = 1; - scsi_req(rq)->cmd[0] = REQ_DRIVE_RESET; - blk_execute_rq(NULL, rq, 1); - ret = scsi_req(rq)->result; - blk_put_request(rq); - return ret; -} - -int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev, - unsigned int cmd, unsigned long arg) -{ - int err; - void __user *argp = (void __user *)arg; - - if (in_compat_syscall()) - argp = compat_ptr(arg); - - err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_ioctl_settings); - if (err != -EOPNOTSUPP) - return err; - - switch (cmd) { - case HDIO_OBSOLETE_IDENTITY: - case HDIO_GET_IDENTITY: - if (bdev_is_partition(bdev)) - return -EINVAL; - return ide_get_identity_ioctl(drive, cmd, argp); - case HDIO_GET_NICE: - return ide_get_nice_ioctl(drive, arg); - case HDIO_SET_NICE: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - return ide_set_nice_ioctl(drive, arg); -#ifdef CONFIG_IDE_TASK_IOCTL - case HDIO_DRIVE_TASKFILE: - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) - return -EACCES; - /* missing compat handler for HDIO_DRIVE_TASKFILE */ - if (in_compat_syscall()) - return -ENOTTY; - if (drive->media == ide_disk) - return ide_taskfile_ioctl(drive, arg); - return -ENOMSG; -#endif - case HDIO_DRIVE_CMD: - if (!capable(CAP_SYS_RAWIO)) - return -EACCES; - return ide_cmd_ioctl(drive, argp); - case HDIO_DRIVE_TASK: - if (!capable(CAP_SYS_RAWIO)) - return -EACCES; - return ide_task_ioctl(drive, argp); - case HDIO_DRIVE_RESET: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - return generic_drive_reset(drive); - case HDIO_GET_BUSSTATE: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (put_user_long(BUSSTATE_ON, arg)) - return -EFAULT; - return 0; - case HDIO_SET_BUSSTATE: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - return -EOPNOTSUPP; - default: - return -EINVAL; - } -} -EXPORT_SYMBOL(generic_ide_ioctl); diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c deleted file mode 100644 index f2be127ee96e..000000000000 --- a/drivers/ide/ide-iops.c +++ /dev/null @@ -1,536 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2000-2002 Andre Hedrick - * Copyright (C) 2003 Red Hat - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -void SELECT_MASK(ide_drive_t *drive, int mask) -{ - const struct ide_port_ops *port_ops = drive->hwif->port_ops; - - if (port_ops && port_ops->maskproc) - port_ops->maskproc(drive, mask); -} - -u8 ide_read_error(ide_drive_t *drive) -{ - struct ide_taskfile tf; - - drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_ERROR); - - return tf.error; -} -EXPORT_SYMBOL_GPL(ide_read_error); - -void ide_fix_driveid(u16 *id) -{ -#ifndef __LITTLE_ENDIAN -# ifdef __BIG_ENDIAN - int i; - - for (i = 0; i < 256; i++) - id[i] = __le16_to_cpu(id[i]); -# else -# error "Please fix " -# endif -#endif -} - -/* - * ide_fixstring() cleans up and (optionally) byte-swaps a text string, - * removing leading/trailing blanks and compressing internal blanks. - * It is primarily used to tidy up the model name/number fields as - * returned by the ATA_CMD_ID_ATA[PI] commands. - */ - -void ide_fixstring(u8 *s, const int bytecount, const int byteswap) -{ - u8 *p, *end = &s[bytecount & ~1]; /* bytecount must be even */ - - if (byteswap) { - /* convert from big-endian to host byte order */ - for (p = s ; p != end ; p += 2) - be16_to_cpus((u16 *) p); - } - - /* strip leading blanks */ - p = s; - while (s != end && *s == ' ') - ++s; - /* compress internal blanks and strip trailing blanks */ - while (s != end && *s) { - if (*s++ != ' ' || (s != end && *s && *s != ' ')) - *p++ = *(s-1); - } - /* wipe out trailing garbage */ - while (p != end) - *p++ = '\0'; -} -EXPORT_SYMBOL(ide_fixstring); - -/* - * This routine busy-waits for the drive status to be not "busy". - * It then checks the status for all of the "good" bits and none - * of the "bad" bits, and if all is okay it returns 0. All other - * cases return error -- caller may then invoke ide_error(). - * - * This routine should get fixed to not hog the cpu during extra long waits.. - * That could be done by busy-waiting for the first jiffy or two, and then - * setting a timer to wake up at half second intervals thereafter, - * until timeout is achieved, before timing out. - */ -int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, - unsigned long timeout, u8 *rstat) -{ - ide_hwif_t *hwif = drive->hwif; - const struct ide_tp_ops *tp_ops = hwif->tp_ops; - unsigned long flags; - bool irqs_threaded = force_irqthreads; - int i; - u8 stat; - - udelay(1); /* spec allows drive 400ns to assert "BUSY" */ - stat = tp_ops->read_status(hwif); - - if (stat & ATA_BUSY) { - if (!irqs_threaded) { - local_save_flags(flags); - local_irq_enable_in_hardirq(); - } - timeout += jiffies; - while ((stat = tp_ops->read_status(hwif)) & ATA_BUSY) { - if (time_after(jiffies, timeout)) { - /* - * One last read after the timeout in case - * heavy interrupt load made us not make any - * progress during the timeout.. - */ - stat = tp_ops->read_status(hwif); - if ((stat & ATA_BUSY) == 0) - break; - - if (!irqs_threaded) - local_irq_restore(flags); - *rstat = stat; - return -EBUSY; - } - } - if (!irqs_threaded) - local_irq_restore(flags); - } - /* - * Allow status to settle, then read it again. - * A few rare drives vastly violate the 400ns spec here, - * so we'll wait up to 10usec for a "good" status - * rather than expensively fail things immediately. - * This fix courtesy of Matthew Faupel & Niccolo Rigacci. - */ - for (i = 0; i < 10; i++) { - udelay(1); - stat = tp_ops->read_status(hwif); - - if (OK_STAT(stat, good, bad)) { - *rstat = stat; - return 0; - } - } - *rstat = stat; - return -EFAULT; -} - -/* - * In case of error returns error value after doing "*startstop = ide_error()". - * The caller should return the updated value of "startstop" in this case, - * "startstop" is unchanged when the function returns 0. - */ -int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, u8 good, - u8 bad, unsigned long timeout) -{ - int err; - u8 stat; - - /* bail early if we've exceeded max_failures */ - if (drive->max_failures && (drive->failures > drive->max_failures)) { - *startstop = ide_stopped; - return 1; - } - - err = __ide_wait_stat(drive, good, bad, timeout, &stat); - - if (err) { - char *s = (err == -EBUSY) ? "status timeout" : "status error"; - *startstop = ide_error(drive, s, stat); - } - - return err; -} -EXPORT_SYMBOL(ide_wait_stat); - -/** - * ide_in_drive_list - look for drive in black/white list - * @id: drive identifier - * @table: list to inspect - * - * Look for a drive in the blacklist and the whitelist tables - * Returns 1 if the drive is found in the table. - */ - -int ide_in_drive_list(u16 *id, const struct drive_list_entry *table) -{ - for ( ; table->id_model; table++) - if ((!strcmp(table->id_model, (char *)&id[ATA_ID_PROD])) && - (!table->id_firmware || - strstr((char *)&id[ATA_ID_FW_REV], table->id_firmware))) - return 1; - return 0; -} -EXPORT_SYMBOL_GPL(ide_in_drive_list); - -/* - * Early UDMA66 devices don't set bit14 to 1, only bit13 is valid. - * Some optical devices with the buggy firmwares have the same problem. - */ -static const struct drive_list_entry ivb_list[] = { - { "QUANTUM FIREBALLlct10 05" , "A03.0900" }, - { "QUANTUM FIREBALLlct20 30" , "APL.0900" }, - { "TSSTcorp CDDVDW SH-S202J" , "SB00" }, - { "TSSTcorp CDDVDW SH-S202J" , "SB01" }, - { "TSSTcorp CDDVDW SH-S202N" , "SB00" }, - { "TSSTcorp CDDVDW SH-S202N" , "SB01" }, - { "TSSTcorp CDDVDW SH-S202H" , "SB00" }, - { "TSSTcorp CDDVDW SH-S202H" , "SB01" }, - { "SAMSUNG SP0822N" , "WA100-10" }, - { NULL , NULL } -}; - -/* - * All hosts that use the 80c ribbon must use! - * The name is derived from upper byte of word 93 and the 80c ribbon. - */ -u8 eighty_ninty_three(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u16 *id = drive->id; - int ivb = ide_in_drive_list(id, ivb_list); - - if (hwif->cbl == ATA_CBL_SATA || hwif->cbl == ATA_CBL_PATA40_SHORT) - return 1; - - if (ivb) - printk(KERN_DEBUG "%s: skipping word 93 validity check\n", - drive->name); - - if (ata_id_is_sata(id) && !ivb) - return 1; - - if (hwif->cbl != ATA_CBL_PATA80 && !ivb) - goto no_80w; - - /* - * FIXME: - * - change master/slave IDENTIFY order - * - force bit13 (80c cable present) check also for !ivb devices - * (unless the slave device is pre-ATA3) - */ - if (id[ATA_ID_HW_CONFIG] & 0x4000) - return 1; - - if (ivb) { - const char *model = (char *)&id[ATA_ID_PROD]; - - if (strstr(model, "TSSTcorp CDDVDW SH-S202")) { - /* - * These ATAPI devices always report 80c cable - * so we have to depend on the host in this case. - */ - if (hwif->cbl == ATA_CBL_PATA80) - return 1; - } else { - /* Depend on the device side cable detection. */ - if (id[ATA_ID_HW_CONFIG] & 0x2000) - return 1; - } - } -no_80w: - if (drive->dev_flags & IDE_DFLAG_UDMA33_WARNED) - return 0; - - printk(KERN_WARNING "%s: %s side 80-wire cable detection failed, " - "limiting max speed to UDMA33\n", - drive->name, - hwif->cbl == ATA_CBL_PATA80 ? "drive" : "host"); - - drive->dev_flags |= IDE_DFLAG_UDMA33_WARNED; - - return 0; -} - -static const char *nien_quirk_list[] = { - "QUANTUM FIREBALLlct08 08", - "QUANTUM FIREBALLP KA6.4", - "QUANTUM FIREBALLP KA9.1", - "QUANTUM FIREBALLP KX13.6", - "QUANTUM FIREBALLP KX20.5", - "QUANTUM FIREBALLP KX27.3", - "QUANTUM FIREBALLP LM20.4", - "QUANTUM FIREBALLP LM20.5", - "FUJITSU MHZ2160BH G2", - NULL -}; - -void ide_check_nien_quirk_list(ide_drive_t *drive) -{ - const char **list, *m = (char *)&drive->id[ATA_ID_PROD]; - - for (list = nien_quirk_list; *list != NULL; list++) - if (strstr(m, *list) != NULL) { - drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK; - return; - } -} - -int ide_driveid_update(ide_drive_t *drive) -{ - u16 *id; - int rc; - - id = kmalloc(SECTOR_SIZE, GFP_ATOMIC); - if (id == NULL) - return 0; - - SELECT_MASK(drive, 1); - rc = ide_dev_read_id(drive, ATA_CMD_ID_ATA, id, 1); - SELECT_MASK(drive, 0); - - if (rc) - goto out_err; - - drive->id[ATA_ID_UDMA_MODES] = id[ATA_ID_UDMA_MODES]; - drive->id[ATA_ID_MWDMA_MODES] = id[ATA_ID_MWDMA_MODES]; - drive->id[ATA_ID_SWDMA_MODES] = id[ATA_ID_SWDMA_MODES]; - drive->id[ATA_ID_CFA_MODES] = id[ATA_ID_CFA_MODES]; - /* anything more ? */ - - kfree(id); - - return 1; -out_err: - if (rc == 2) - printk(KERN_ERR "%s: %s: bad status\n", drive->name, __func__); - kfree(id); - return 0; -} - -int ide_config_drive_speed(ide_drive_t *drive, u8 speed) -{ - ide_hwif_t *hwif = drive->hwif; - const struct ide_tp_ops *tp_ops = hwif->tp_ops; - struct ide_taskfile tf; - u16 *id = drive->id, i; - int error = 0; - u8 stat; - -#ifdef CONFIG_BLK_DEV_IDEDMA - if (hwif->dma_ops) /* check if host supports DMA */ - hwif->dma_ops->dma_host_set(drive, 0); -#endif - - /* Skip setting PIO flow-control modes on pre-EIDE drives */ - if ((speed & 0xf8) == XFER_PIO_0 && ata_id_has_iordy(drive->id) == 0) - goto skip; - - /* - * Don't use ide_wait_cmd here - it will - * attempt to set_geometry and recalibrate, - * but for some reason these don't work at - * this point (lost interrupt). - */ - - udelay(1); - tp_ops->dev_select(drive); - SELECT_MASK(drive, 1); - udelay(1); - tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS); - - memset(&tf, 0, sizeof(tf)); - tf.feature = SETFEATURES_XFER; - tf.nsect = speed; - - tp_ops->tf_load(drive, &tf, IDE_VALID_FEATURE | IDE_VALID_NSECT); - - tp_ops->exec_command(hwif, ATA_CMD_SET_FEATURES); - - if (drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) - tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); - - error = __ide_wait_stat(drive, drive->ready_stat, - ATA_BUSY | ATA_DRQ | ATA_ERR, - WAIT_CMD, &stat); - - SELECT_MASK(drive, 0); - - if (error) { - (void) ide_dump_status(drive, "set_drive_speed_status", stat); - return error; - } - - if (speed >= XFER_SW_DMA_0) { - id[ATA_ID_UDMA_MODES] &= ~0xFF00; - id[ATA_ID_MWDMA_MODES] &= ~0x0700; - id[ATA_ID_SWDMA_MODES] &= ~0x0700; - if (ata_id_is_cfa(id)) - id[ATA_ID_CFA_MODES] &= ~0x0E00; - } else if (ata_id_is_cfa(id)) - id[ATA_ID_CFA_MODES] &= ~0x01C0; - - skip: -#ifdef CONFIG_BLK_DEV_IDEDMA - if (speed >= XFER_SW_DMA_0 && (drive->dev_flags & IDE_DFLAG_USING_DMA)) - hwif->dma_ops->dma_host_set(drive, 1); - else if (hwif->dma_ops) /* check if host supports DMA */ - ide_dma_off_quietly(drive); -#endif - - if (speed >= XFER_UDMA_0) { - i = 1 << (speed - XFER_UDMA_0); - id[ATA_ID_UDMA_MODES] |= (i << 8 | i); - } else if (ata_id_is_cfa(id) && speed >= XFER_MW_DMA_3) { - i = speed - XFER_MW_DMA_2; - id[ATA_ID_CFA_MODES] |= i << 9; - } else if (speed >= XFER_MW_DMA_0) { - i = 1 << (speed - XFER_MW_DMA_0); - id[ATA_ID_MWDMA_MODES] |= (i << 8 | i); - } else if (speed >= XFER_SW_DMA_0) { - i = 1 << (speed - XFER_SW_DMA_0); - id[ATA_ID_SWDMA_MODES] |= (i << 8 | i); - } else if (ata_id_is_cfa(id) && speed >= XFER_PIO_5) { - i = speed - XFER_PIO_4; - id[ATA_ID_CFA_MODES] |= i << 6; - } - - if (!drive->init_speed) - drive->init_speed = speed; - drive->current_speed = speed; - return error; -} - -/* - * This should get invoked any time we exit the driver to - * wait for an interrupt response from a drive. handler() points - * at the appropriate code to handle the next interrupt, and a - * timer is started to prevent us from waiting forever in case - * something goes wrong (see the ide_timer_expiry() handler later on). - * - * See also ide_execute_command - */ -void __ide_set_handler(ide_drive_t *drive, ide_handler_t *handler, - unsigned int timeout) -{ - ide_hwif_t *hwif = drive->hwif; - - BUG_ON(hwif->handler); - hwif->handler = handler; - hwif->timer.expires = jiffies + timeout; - hwif->req_gen_timer = hwif->req_gen; - add_timer(&hwif->timer); -} - -void ide_set_handler(ide_drive_t *drive, ide_handler_t *handler, - unsigned int timeout) -{ - ide_hwif_t *hwif = drive->hwif; - unsigned long flags; - - spin_lock_irqsave(&hwif->lock, flags); - __ide_set_handler(drive, handler, timeout); - spin_unlock_irqrestore(&hwif->lock, flags); -} -EXPORT_SYMBOL(ide_set_handler); - -/** - * ide_execute_command - execute an IDE command - * @drive: IDE drive to issue the command against - * @cmd: command - * @handler: handler for next phase - * @timeout: timeout for command - * - * Helper function to issue an IDE command. This handles the - * atomicity requirements, command timing and ensures that the - * handler and IRQ setup do not race. All IDE command kick off - * should go via this function or do equivalent locking. - */ - -void ide_execute_command(ide_drive_t *drive, struct ide_cmd *cmd, - ide_handler_t *handler, unsigned timeout) -{ - ide_hwif_t *hwif = drive->hwif; - unsigned long flags; - - spin_lock_irqsave(&hwif->lock, flags); - if ((cmd->protocol != ATAPI_PROT_DMA && - cmd->protocol != ATAPI_PROT_PIO) || - (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT)) - __ide_set_handler(drive, handler, timeout); - hwif->tp_ops->exec_command(hwif, cmd->tf.command); - /* - * Drive takes 400nS to respond, we must avoid the IRQ being - * serviced before that. - * - * FIXME: we could skip this delay with care on non shared devices - */ - ndelay(400); - spin_unlock_irqrestore(&hwif->lock, flags); -} - -/* - * ide_wait_not_busy() waits for the currently selected device on the hwif - * to report a non-busy status, see comments in ide_probe_port(). - */ -int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout) -{ - u8 stat = 0; - - while (timeout--) { - /* - * Turn this into a schedule() sleep once I'm sure - * about locking issues (2.5 work ?). - */ - mdelay(1); - stat = hwif->tp_ops->read_status(hwif); - if ((stat & ATA_BUSY) == 0) - return 0; - /* - * Assume a value of 0xff means nothing is connected to - * the interface and it doesn't implement the pull-down - * resistor on D7. - */ - if (stat == 0xff) - return -ENODEV; - touch_nmi_watchdog(); - } - return -EBUSY; -} diff --git a/drivers/ide/ide-legacy.c b/drivers/ide/ide-legacy.c deleted file mode 100644 index be65b411ab53..000000000000 --- a/drivers/ide/ide-legacy.c +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#include -#include -#include - -static void ide_legacy_init_one(struct ide_hw **hws, struct ide_hw *hw, - u8 port_no, const struct ide_port_info *d, - unsigned long config) -{ - unsigned long base, ctl; - int irq; - - if (port_no == 0) { - base = 0x1f0; - ctl = 0x3f6; - irq = 14; - } else { - base = 0x170; - ctl = 0x376; - irq = 15; - } - - if (!request_region(base, 8, d->name)) { - printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n", - d->name, base, base + 7); - return; - } - - if (!request_region(ctl, 1, d->name)) { - printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n", - d->name, ctl); - release_region(base, 8); - return; - } - - ide_std_init_ports(hw, base, ctl); - hw->irq = irq; - hw->config = config; - - hws[port_no] = hw; -} - -int ide_legacy_device_add(const struct ide_port_info *d, unsigned long config) -{ - struct ide_hw hw[2], *hws[] = { NULL, NULL }; - - memset(&hw, 0, sizeof(hw)); - - if ((d->host_flags & IDE_HFLAG_QD_2ND_PORT) == 0) - ide_legacy_init_one(hws, &hw[0], 0, d, config); - ide_legacy_init_one(hws, &hw[1], 1, d, config); - - if (hws[0] == NULL && hws[1] == NULL && - (d->host_flags & IDE_HFLAG_SINGLE)) - return -ENOENT; - - return ide_host_add(d, hws, 2, NULL); -} -EXPORT_SYMBOL_GPL(ide_legacy_device_add); diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c deleted file mode 100644 index 7b9f655adbc2..000000000000 --- a/drivers/ide/ide-lib.c +++ /dev/null @@ -1,146 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#include -#include -#include -#include -#include -#include -#include - -u64 ide_get_lba_addr(struct ide_cmd *cmd, int lba48) -{ - struct ide_taskfile *tf = &cmd->tf; - u32 high, low; - - low = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal; - if (lba48) { - tf = &cmd->hob; - high = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal; - } else - high = tf->device & 0xf; - - return ((u64)high << 24) | low; -} -EXPORT_SYMBOL_GPL(ide_get_lba_addr); - -static void ide_dump_sector(ide_drive_t *drive) -{ - struct ide_cmd cmd; - struct ide_taskfile *tf = &cmd.tf; - u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48); - - memset(&cmd, 0, sizeof(cmd)); - if (lba48) { - cmd.valid.in.tf = IDE_VALID_LBA; - cmd.valid.in.hob = IDE_VALID_LBA; - cmd.tf_flags = IDE_TFLAG_LBA48; - } else - cmd.valid.in.tf = IDE_VALID_LBA | IDE_VALID_DEVICE; - - ide_tf_readback(drive, &cmd); - - if (lba48 || (tf->device & ATA_LBA)) - printk(KERN_CONT ", LBAsect=%llu", - (unsigned long long)ide_get_lba_addr(&cmd, lba48)); - else - printk(KERN_CONT ", CHS=%d/%d/%d", (tf->lbah << 8) + tf->lbam, - tf->device & 0xf, tf->lbal); -} - -static void ide_dump_ata_error(ide_drive_t *drive, u8 err) -{ - printk(KERN_CONT "{ "); - if (err & ATA_ABORTED) - printk(KERN_CONT "DriveStatusError "); - if (err & ATA_ICRC) - printk(KERN_CONT "%s", - (err & ATA_ABORTED) ? "BadCRC " : "BadSector "); - if (err & ATA_UNC) - printk(KERN_CONT "UncorrectableError "); - if (err & ATA_IDNF) - printk(KERN_CONT "SectorIdNotFound "); - if (err & ATA_TRK0NF) - printk(KERN_CONT "TrackZeroNotFound "); - if (err & ATA_AMNF) - printk(KERN_CONT "AddrMarkNotFound "); - printk(KERN_CONT "}"); - if ((err & (ATA_BBK | ATA_ABORTED)) == ATA_BBK || - (err & (ATA_UNC | ATA_IDNF | ATA_AMNF))) { - struct request *rq = drive->hwif->rq; - - ide_dump_sector(drive); - - if (rq) - printk(KERN_CONT ", sector=%llu", - (unsigned long long)blk_rq_pos(rq)); - } - printk(KERN_CONT "\n"); -} - -static void ide_dump_atapi_error(ide_drive_t *drive, u8 err) -{ - printk(KERN_CONT "{ "); - if (err & ATAPI_ILI) - printk(KERN_CONT "IllegalLengthIndication "); - if (err & ATAPI_EOM) - printk(KERN_CONT "EndOfMedia "); - if (err & ATA_ABORTED) - printk(KERN_CONT "AbortedCommand "); - if (err & ATA_MCR) - printk(KERN_CONT "MediaChangeRequested "); - if (err & ATAPI_LFS) - printk(KERN_CONT "LastFailedSense=0x%02x ", - (err & ATAPI_LFS) >> 4); - printk(KERN_CONT "}\n"); -} - -/** - * ide_dump_status - translate ATA/ATAPI error - * @drive: drive that status applies to - * @msg: text message to print - * @stat: status byte to decode - * - * Error reporting, in human readable form (luxurious, but a memory hog). - * Combines the drive name, message and status byte to provide a - * user understandable explanation of the device error. - */ - -u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat) -{ - u8 err = 0; - - printk(KERN_ERR "%s: %s: status=0x%02x { ", drive->name, msg, stat); - if (stat & ATA_BUSY) - printk(KERN_CONT "Busy "); - else { - if (stat & ATA_DRDY) - printk(KERN_CONT "DriveReady "); - if (stat & ATA_DF) - printk(KERN_CONT "DeviceFault "); - if (stat & ATA_DSC) - printk(KERN_CONT "SeekComplete "); - if (stat & ATA_DRQ) - printk(KERN_CONT "DataRequest "); - if (stat & ATA_CORR) - printk(KERN_CONT "CorrectedError "); - if (stat & ATA_SENSE) - printk(KERN_CONT "Sense "); - if (stat & ATA_ERR) - printk(KERN_CONT "Error "); - } - printk(KERN_CONT "}\n"); - if ((stat & (ATA_BUSY | ATA_ERR)) == ATA_ERR) { - err = ide_read_error(drive); - printk(KERN_ERR "%s: %s: error=0x%02x ", drive->name, msg, err); - if (drive->media == ide_disk) - ide_dump_ata_error(drive, err); - else - ide_dump_atapi_error(drive, err); - } - - printk(KERN_ERR "%s: possibly failed opcode: 0x%02x\n", - drive->name, drive->hwif->cmd.tf.command); - - return err; -} -EXPORT_SYMBOL(ide_dump_status); diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c deleted file mode 100644 index a80a0f28f7b9..000000000000 --- a/drivers/ide/ide-park.c +++ /dev/null @@ -1,155 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include - -DECLARE_WAIT_QUEUE_HEAD(ide_park_wq); - -static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout) -{ - ide_hwif_t *hwif = drive->hwif; - struct request_queue *q = drive->queue; - struct request *rq; - int rc; - - timeout += jiffies; - spin_lock_irq(&hwif->lock); - if (drive->dev_flags & IDE_DFLAG_PARKED) { - int reset_timer = time_before(timeout, drive->sleep); - int start_queue = 0; - - drive->sleep = timeout; - wake_up_all(&ide_park_wq); - if (reset_timer && del_timer(&hwif->timer)) - start_queue = 1; - spin_unlock_irq(&hwif->lock); - - if (start_queue) - blk_mq_run_hw_queues(q, true); - return; - } - spin_unlock_irq(&hwif->lock); - - rq = blk_get_request(q, REQ_OP_DRV_IN, 0); - scsi_req(rq)->cmd[0] = REQ_PARK_HEADS; - scsi_req(rq)->cmd_len = 1; - ide_req(rq)->type = ATA_PRIV_MISC; - ide_req(rq)->special = &timeout; - blk_execute_rq(NULL, rq, 1); - rc = scsi_req(rq)->result ? -EIO : 0; - blk_put_request(rq); - if (rc) - goto out; - - /* - * Make sure that *some* command is sent to the drive after the - * timeout has expired, so power management will be reenabled. - */ - rq = blk_get_request(q, REQ_OP_DRV_IN, BLK_MQ_REQ_NOWAIT); - if (IS_ERR(rq)) - goto out; - - scsi_req(rq)->cmd[0] = REQ_UNPARK_HEADS; - scsi_req(rq)->cmd_len = 1; - ide_req(rq)->type = ATA_PRIV_MISC; - spin_lock_irq(&hwif->lock); - ide_insert_request_head(drive, rq); - spin_unlock_irq(&hwif->lock); - -out: - return; -} - -ide_startstop_t ide_do_park_unpark(ide_drive_t *drive, struct request *rq) -{ - struct ide_cmd cmd; - struct ide_taskfile *tf = &cmd.tf; - - memset(&cmd, 0, sizeof(cmd)); - if (scsi_req(rq)->cmd[0] == REQ_PARK_HEADS) { - drive->sleep = *(unsigned long *)ide_req(rq)->special; - drive->dev_flags |= IDE_DFLAG_SLEEPING; - tf->command = ATA_CMD_IDLEIMMEDIATE; - tf->feature = 0x44; - tf->lbal = 0x4c; - tf->lbam = 0x4e; - tf->lbah = 0x55; - cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - } else /* cmd == REQ_UNPARK_HEADS */ - tf->command = ATA_CMD_CHK_POWER; - - cmd.tf_flags |= IDE_TFLAG_CUSTOM_HANDLER; - cmd.protocol = ATA_PROT_NODATA; - - cmd.rq = rq; - - return do_rw_taskfile(drive, &cmd); -} - -ssize_t ide_park_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - ide_drive_t *drive = to_ide_device(dev); - ide_hwif_t *hwif = drive->hwif; - unsigned long now; - unsigned int msecs; - - if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD) - return -EOPNOTSUPP; - - spin_lock_irq(&hwif->lock); - now = jiffies; - if (drive->dev_flags & IDE_DFLAG_PARKED && - time_after(drive->sleep, now)) - msecs = jiffies_to_msecs(drive->sleep - now); - else - msecs = 0; - spin_unlock_irq(&hwif->lock); - - return snprintf(buf, 20, "%u\n", msecs); -} - -ssize_t ide_park_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ -#define MAX_PARK_TIMEOUT 30000 - ide_drive_t *drive = to_ide_device(dev); - long int input; - int rc; - - rc = kstrtol(buf, 10, &input); - if (rc) - return rc; - if (input < -2) - return -EINVAL; - if (input > MAX_PARK_TIMEOUT) { - input = MAX_PARK_TIMEOUT; - rc = -EOVERFLOW; - } - - mutex_lock(&ide_setting_mtx); - if (input >= 0) { - if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD) - rc = -EOPNOTSUPP; - else if (input || drive->dev_flags & IDE_DFLAG_PARKED) - issue_park_cmd(drive, msecs_to_jiffies(input)); - } else { - if (drive->media == ide_disk) - switch (input) { - case -1: - drive->dev_flags &= ~IDE_DFLAG_NO_UNLOAD; - break; - case -2: - drive->dev_flags |= IDE_DFLAG_NO_UNLOAD; - break; - } - else - rc = -EOPNOTSUPP; - } - mutex_unlock(&ide_setting_mtx); - - return rc ? rc : len; -} diff --git a/drivers/ide/ide-pci-generic.c b/drivers/ide/ide-pci-generic.c deleted file mode 100644 index 673420db953f..000000000000 --- a/drivers/ide/ide-pci-generic.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2001-2002 Andre Hedrick - * Portions (C) Copyright 2002 Red Hat Inc - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * For the avoidance of doubt the "preferred form" of this code is one which - * is in an open non patent encumbered format. Where cryptographic key signing - * forms part of the process of creating an executable the information - * including keys needed to generate an equivalently functional executable - * are deemed to be part of the source code. - */ - -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "ide_pci_generic" - -static bool ide_generic_all; /* Set to claim all devices */ - -module_param_named(all_generic_ide, ide_generic_all, bool, 0444); -MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers."); - -static void netcell_quirkproc(ide_drive_t *drive) -{ - /* mark words 85-87 as valid */ - drive->id[ATA_ID_CSF_DEFAULT] |= 0x4000; -} - -static const struct ide_port_ops netcell_port_ops = { - .quirkproc = netcell_quirkproc, -}; - -#define DECLARE_GENERIC_PCI_DEV(extra_flags) \ - { \ - .name = DRV_NAME, \ - .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA | \ - extra_flags, \ - .swdma_mask = ATA_SWDMA2, \ - .mwdma_mask = ATA_MWDMA2, \ - .udma_mask = ATA_UDMA6, \ - } - -static const struct ide_port_info generic_chipsets[] = { - /* 0: Unknown */ - DECLARE_GENERIC_PCI_DEV(0), - - { /* 1: NS87410 */ - .name = DRV_NAME, - .enablebits = { {0x43, 0x08, 0x08}, {0x47, 0x08, 0x08} }, - .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA, - .swdma_mask = ATA_SWDMA2, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA6, - }, - - /* 2: SAMURAI / HT6565 / HINT_IDE */ - DECLARE_GENERIC_PCI_DEV(0), - /* 3: UM8673F / UM8886A / UM8886BF */ - DECLARE_GENERIC_PCI_DEV(IDE_HFLAG_NO_DMA), - /* 4: VIA_IDE / OPTI621V / Piccolo010{2,3,5} */ - DECLARE_GENERIC_PCI_DEV(IDE_HFLAG_NO_AUTODMA), - - { /* 5: VIA8237SATA */ - .name = DRV_NAME, - .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA | - IDE_HFLAG_OFF_BOARD, - .swdma_mask = ATA_SWDMA2, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA6, - }, - - { /* 6: Revolution */ - .name = DRV_NAME, - .port_ops = &netcell_port_ops, - .host_flags = IDE_HFLAG_CLEAR_SIMPLEX | - IDE_HFLAG_TRUST_BIOS_FOR_DMA | - IDE_HFLAG_OFF_BOARD, - .swdma_mask = ATA_SWDMA2, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA6, - } -}; - -/** - * generic_init_one - called when a PIIX is found - * @dev: the generic device - * @id: the matching pci id - * - * Called when the PCI registration layer (or the IDE initialization) - * finds a device matching our IDE device tables. - */ - -static int generic_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - const struct ide_port_info *d = &generic_chipsets[id->driver_data]; - int ret = -ENODEV; - - /* Don't use the generic entry unless instructed to do so */ - if (id->driver_data == 0 && ide_generic_all == 0) - goto out; - - switch (dev->vendor) { - case PCI_VENDOR_ID_UMC: - if (dev->device == PCI_DEVICE_ID_UMC_UM8886A && - !(PCI_FUNC(dev->devfn) & 1)) - goto out; /* UM8886A/BF pair */ - break; - case PCI_VENDOR_ID_OPTI: - if (dev->device == PCI_DEVICE_ID_OPTI_82C558 && - !(PCI_FUNC(dev->devfn) & 1)) - goto out; - break; - case PCI_VENDOR_ID_JMICRON: - if (dev->device != PCI_DEVICE_ID_JMICRON_JMB368 && - PCI_FUNC(dev->devfn) != 1) - goto out; - break; - case PCI_VENDOR_ID_NS: - if (dev->device == PCI_DEVICE_ID_NS_87410 && - (dev->class >> 8) != PCI_CLASS_STORAGE_IDE) - goto out; - break; - } - - if (dev->vendor != PCI_VENDOR_ID_JMICRON) { - u16 command; - pci_read_config_word(dev, PCI_COMMAND, &command); - if (!(command & PCI_COMMAND_IO)) { - printk(KERN_INFO "%s %s: skipping disabled " - "controller\n", d->name, pci_name(dev)); - goto out; - } - } - ret = ide_pci_init_one(dev, d, NULL); -out: - return ret; -} - -static const struct pci_device_id generic_pci_tbl[] = { - { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87410), 1 }, - { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE), 2 }, - { PCI_VDEVICE(HOLTEK, PCI_DEVICE_ID_HOLTEK_6565), 2 }, - { PCI_VDEVICE(UMC, PCI_DEVICE_ID_UMC_UM8673F), 3 }, - { PCI_VDEVICE(UMC, PCI_DEVICE_ID_UMC_UM8886A), 3 }, - { PCI_VDEVICE(UMC, PCI_DEVICE_ID_UMC_UM8886BF), 3 }, - { PCI_VDEVICE(HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE), 2 }, - { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C561), 4 }, - { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C558), 4 }, -#ifdef CONFIG_BLK_DEV_IDE_SATA - { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_8237_SATA), 5 }, -#endif - { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), 4 }, - { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), 4 }, - { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_3), 4 }, - { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_5), 4 }, - { PCI_VDEVICE(NETCELL, PCI_DEVICE_ID_REVOLUTION), 6 }, - /* - * Must come last. If you add entries adjust - * this table and generic_chipsets[] appropriately. - */ - { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, generic_pci_tbl); - -static struct pci_driver generic_pci_driver = { - .name = "PCI_IDE", - .id_table = generic_pci_tbl, - .probe = generic_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init generic_ide_init(void) -{ - return ide_pci_register_driver(&generic_pci_driver); -} - -static void __exit generic_ide_exit(void) -{ - pci_unregister_driver(&generic_pci_driver); -} - -module_init(generic_ide_init); -module_exit(generic_ide_exit); - -MODULE_AUTHOR("Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for generic PCI IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ide-pio-blacklist.c b/drivers/ide/ide-pio-blacklist.c deleted file mode 100644 index 1fd24798e5c9..000000000000 --- a/drivers/ide/ide-pio-blacklist.c +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * PIO blacklist. Some drives incorrectly report their maximal PIO mode, - * at least in respect to CMD640. Here we keep info on some known drives. - * - * Changes to the ide_pio_blacklist[] should be made with EXTREME CAUTION - * to avoid breaking the fragile cmd640.c support. - */ - -#include -#include - -static struct ide_pio_info { - const char *name; - int pio; -} ide_pio_blacklist [] = { - { "Conner Peripherals 540MB - CFS540A", 3 }, - - { "WDC AC2700", 3 }, - { "WDC AC2540", 3 }, - { "WDC AC2420", 3 }, - { "WDC AC2340", 3 }, - { "WDC AC2250", 0 }, - { "WDC AC2200", 0 }, - { "WDC AC21200", 4 }, - { "WDC AC2120", 0 }, - { "WDC AC2850", 3 }, - { "WDC AC1270", 3 }, - { "WDC AC1170", 1 }, - { "WDC AC1210", 1 }, - { "WDC AC280", 0 }, - { "WDC AC31000", 3 }, - { "WDC AC31200", 3 }, - - { "Maxtor 7131 AT", 1 }, - { "Maxtor 7171 AT", 1 }, - { "Maxtor 7213 AT", 1 }, - { "Maxtor 7245 AT", 1 }, - { "Maxtor 7345 AT", 1 }, - { "Maxtor 7546 AT", 3 }, - { "Maxtor 7540 AV", 3 }, - - { "SAMSUNG SHD-3121A", 1 }, - { "SAMSUNG SHD-3122A", 1 }, - { "SAMSUNG SHD-3172A", 1 }, - - { "ST5660A", 3 }, - { "ST3660A", 3 }, - { "ST3630A", 3 }, - { "ST3655A", 3 }, - { "ST3391A", 3 }, - { "ST3390A", 1 }, - { "ST3600A", 1 }, - { "ST3290A", 0 }, - { "ST3144A", 0 }, - { "ST3491A", 1 }, /* reports 3, should be 1 or 2 (depending on drive) - according to Seagate's FIND-ATA program */ - - { "QUANTUM ELS127A", 0 }, - { "QUANTUM ELS170A", 0 }, - { "QUANTUM LPS240A", 0 }, - { "QUANTUM LPS210A", 3 }, - { "QUANTUM LPS270A", 3 }, - { "QUANTUM LPS365A", 3 }, - { "QUANTUM LPS540A", 3 }, - { "QUANTUM LIGHTNING 540A", 3 }, - { "QUANTUM LIGHTNING 730A", 3 }, - - { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */ - { "QUANTUM FIREBALL_640", 3 }, - { "QUANTUM FIREBALL_1080", 3 }, - { "QUANTUM FIREBALL_1280", 3 }, - { NULL, 0 } -}; - -/** - * ide_scan_pio_blacklist - check for a blacklisted drive - * @model: Drive model string - * - * This routine searches the ide_pio_blacklist for an entry - * matching the start/whole of the supplied model name. - * - * Returns -1 if no match found. - * Otherwise returns the recommended PIO mode from ide_pio_blacklist[]. - */ - -int ide_scan_pio_blacklist(char *model) -{ - struct ide_pio_info *p; - - for (p = ide_pio_blacklist; p->name != NULL; p++) { - if (strncmp(p->name, model, strlen(p->name)) == 0) - return p->pio; - } - return -1; -} diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c deleted file mode 100644 index d680b3e3295f..000000000000 --- a/drivers/ide/ide-pm.c +++ /dev/null @@ -1,261 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include - -int generic_ide_suspend(struct device *dev, pm_message_t mesg) -{ - ide_drive_t *drive = to_ide_device(dev); - ide_drive_t *pair = ide_get_pair_dev(drive); - ide_hwif_t *hwif = drive->hwif; - struct request *rq; - struct ide_pm_state rqpm; - int ret; - - if (ide_port_acpi(hwif)) { - /* call ACPI _GTM only once */ - if ((drive->dn & 1) == 0 || pair == NULL) - ide_acpi_get_timing(hwif); - } - - memset(&rqpm, 0, sizeof(rqpm)); - rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); - ide_req(rq)->type = ATA_PRIV_PM_SUSPEND; - ide_req(rq)->special = &rqpm; - rqpm.pm_step = IDE_PM_START_SUSPEND; - if (mesg.event == PM_EVENT_PRETHAW) - mesg.event = PM_EVENT_FREEZE; - rqpm.pm_state = mesg.event; - - blk_execute_rq(NULL, rq, 0); - ret = scsi_req(rq)->result ? -EIO : 0; - blk_put_request(rq); - - if (ret == 0 && ide_port_acpi(hwif)) { - /* call ACPI _PS3 only after both devices are suspended */ - if ((drive->dn & 1) || pair == NULL) - ide_acpi_set_state(hwif, 0); - } - - return ret; -} - -static int ide_pm_execute_rq(struct request *rq) -{ - struct request_queue *q = rq->q; - - if (unlikely(blk_queue_dying(q))) { - rq->rq_flags |= RQF_QUIET; - scsi_req(rq)->result = -ENXIO; - blk_mq_end_request(rq, BLK_STS_OK); - return -ENXIO; - } - blk_execute_rq(NULL, rq, true); - - return scsi_req(rq)->result ? -EIO : 0; -} - -int generic_ide_resume(struct device *dev) -{ - ide_drive_t *drive = to_ide_device(dev); - ide_drive_t *pair = ide_get_pair_dev(drive); - ide_hwif_t *hwif = drive->hwif; - struct request *rq; - struct ide_pm_state rqpm; - int err; - - blk_mq_start_stopped_hw_queues(drive->queue, true); - - if (ide_port_acpi(hwif)) { - /* call ACPI _PS0 / _STM only once */ - if ((drive->dn & 1) == 0 || pair == NULL) { - ide_acpi_set_state(hwif, 1); - ide_acpi_push_timing(hwif); - } - - ide_acpi_exec_tfs(drive); - } - - memset(&rqpm, 0, sizeof(rqpm)); - rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, BLK_MQ_REQ_PM); - ide_req(rq)->type = ATA_PRIV_PM_RESUME; - ide_req(rq)->special = &rqpm; - rqpm.pm_step = IDE_PM_START_RESUME; - rqpm.pm_state = PM_EVENT_ON; - - err = ide_pm_execute_rq(rq); - blk_put_request(rq); - - if (err == 0 && dev->driver) { - struct ide_driver *drv = to_ide_driver(dev->driver); - - if (drv->resume) - drv->resume(drive); - } - - return err; -} - -void ide_complete_power_step(ide_drive_t *drive, struct request *rq) -{ - struct ide_pm_state *pm = ide_req(rq)->special; - -#ifdef DEBUG_PM - printk(KERN_INFO "%s: complete_power_step(step: %d)\n", - drive->name, pm->pm_step); -#endif - if (drive->media != ide_disk) - return; - - switch (pm->pm_step) { - case IDE_PM_FLUSH_CACHE: /* Suspend step 1 (flush cache) */ - if (pm->pm_state == PM_EVENT_FREEZE) - pm->pm_step = IDE_PM_COMPLETED; - else - pm->pm_step = IDE_PM_STANDBY; - break; - case IDE_PM_STANDBY: /* Suspend step 2 (standby) */ - pm->pm_step = IDE_PM_COMPLETED; - break; - case IDE_PM_RESTORE_PIO: /* Resume step 1 (restore PIO) */ - pm->pm_step = IDE_PM_IDLE; - break; - case IDE_PM_IDLE: /* Resume step 2 (idle)*/ - pm->pm_step = IDE_PM_RESTORE_DMA; - break; - } -} - -ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq) -{ - struct ide_pm_state *pm = ide_req(rq)->special; - struct ide_cmd cmd = { }; - - switch (pm->pm_step) { - case IDE_PM_FLUSH_CACHE: /* Suspend step 1 (flush cache) */ - if (drive->media != ide_disk) - break; - /* Not supported? Switch to next step now. */ - if (ata_id_flush_enabled(drive->id) == 0 || - (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) { - ide_complete_power_step(drive, rq); - return ide_stopped; - } - if (ata_id_flush_ext_enabled(drive->id)) - cmd.tf.command = ATA_CMD_FLUSH_EXT; - else - cmd.tf.command = ATA_CMD_FLUSH; - goto out_do_tf; - case IDE_PM_STANDBY: /* Suspend step 2 (standby) */ - cmd.tf.command = ATA_CMD_STANDBYNOW1; - goto out_do_tf; - case IDE_PM_RESTORE_PIO: /* Resume step 1 (restore PIO) */ - ide_set_max_pio(drive); - /* - * skip IDE_PM_IDLE for ATAPI devices - */ - if (drive->media != ide_disk) - pm->pm_step = IDE_PM_RESTORE_DMA; - else - ide_complete_power_step(drive, rq); - return ide_stopped; - case IDE_PM_IDLE: /* Resume step 2 (idle) */ - cmd.tf.command = ATA_CMD_IDLEIMMEDIATE; - goto out_do_tf; - case IDE_PM_RESTORE_DMA: /* Resume step 3 (restore DMA) */ - /* - * Right now, all we do is call ide_set_dma(drive), - * we could be smarter and check for current xfer_speed - * in struct drive etc... - */ - if (drive->hwif->dma_ops == NULL) - break; - /* - * TODO: respect IDE_DFLAG_USING_DMA - */ - ide_set_dma(drive); - break; - } - - pm->pm_step = IDE_PM_COMPLETED; - - return ide_stopped; - -out_do_tf: - cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - cmd.protocol = ATA_PROT_NODATA; - - return do_rw_taskfile(drive, &cmd); -} - -/** - * ide_complete_pm_rq - end the current Power Management request - * @drive: target drive - * @rq: request - * - * This function cleans up the current PM request and stops the queue - * if necessary. - */ -void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq) -{ - struct request_queue *q = drive->queue; - struct ide_pm_state *pm = ide_req(rq)->special; - - ide_complete_power_step(drive, rq); - if (pm->pm_step != IDE_PM_COMPLETED) - return; - -#ifdef DEBUG_PM - printk("%s: completing PM request, %s\n", drive->name, - (ide_req(rq)->type == ATA_PRIV_PM_SUSPEND) ? "suspend" : "resume"); -#endif - if (ide_req(rq)->type == ATA_PRIV_PM_SUSPEND) - blk_mq_stop_hw_queues(q); - else - drive->dev_flags &= ~IDE_DFLAG_BLOCKED; - - drive->hwif->rq = NULL; - - blk_mq_end_request(rq, BLK_STS_OK); -} - -void ide_check_pm_state(ide_drive_t *drive, struct request *rq) -{ - struct ide_pm_state *pm = ide_req(rq)->special; - - if (blk_rq_is_private(rq) && - ide_req(rq)->type == ATA_PRIV_PM_SUSPEND && - pm->pm_step == IDE_PM_START_SUSPEND) - /* Mark drive blocked when starting the suspend sequence. */ - drive->dev_flags |= IDE_DFLAG_BLOCKED; - else if (blk_rq_is_private(rq) && - ide_req(rq)->type == ATA_PRIV_PM_RESUME && - pm->pm_step == IDE_PM_START_RESUME) { - /* - * The first thing we do on wakeup is to wait for BSY bit to - * go away (with a looong timeout) as a drive on this hwif may - * just be POSTing itself. - * We do that before even selecting as the "other" device on - * the bus may be broken enough to walk on our toes at this - * point. - */ - ide_hwif_t *hwif = drive->hwif; - const struct ide_tp_ops *tp_ops = hwif->tp_ops; - struct request_queue *q = drive->queue; - int rc; -#ifdef DEBUG_PM - printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name); -#endif - rc = ide_wait_not_busy(hwif, 35000); - if (rc) - printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name); - tp_ops->dev_select(drive); - tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); - rc = ide_wait_not_busy(hwif, 100000); - if (rc) - printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name); - - blk_mq_start_hw_queues(q); - } -} diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c deleted file mode 100644 index fc541f1cf8de..000000000000 --- a/drivers/ide/ide-pnp.c +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * This file provides autodetection for ISA PnP IDE interfaces. - * It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface. - * - * Copyright (C) 2000 Andrey Panin - */ - -#include -#include -#include -#include - -#define DRV_NAME "ide-pnp" - -/* Add your devices here :)) */ -static const struct pnp_device_id idepnp_devices[] = { - /* Generic ESDI/IDE/ATA compatible hard disk controller */ - {.id = "PNP0600", .driver_data = 0}, - {.id = ""} -}; - -static const struct ide_port_info ide_pnp_port_info = { - .host_flags = IDE_HFLAG_NO_DMA, - .chipset = ide_generic, -}; - -static int idepnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) -{ - struct ide_host *host; - unsigned long base, ctl; - int rc; - struct ide_hw hw, *hws[] = { &hw }; - - printk(KERN_INFO DRV_NAME ": generic PnP IDE interface\n"); - - if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && pnp_irq_valid(dev, 0))) - return -1; - - base = pnp_port_start(dev, 0); - ctl = pnp_port_start(dev, 1); - - if (!request_region(base, 8, DRV_NAME)) { - printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n", - DRV_NAME, base, base + 7); - return -EBUSY; - } - - if (!request_region(ctl, 1, DRV_NAME)) { - printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n", - DRV_NAME, ctl); - release_region(base, 8); - return -EBUSY; - } - - memset(&hw, 0, sizeof(hw)); - ide_std_init_ports(&hw, base, ctl); - hw.irq = pnp_irq(dev, 0); - - rc = ide_host_add(&ide_pnp_port_info, hws, 1, &host); - if (rc) - goto out; - - pnp_set_drvdata(dev, host); - - return 0; -out: - release_region(ctl, 1); - release_region(base, 8); - - return rc; -} - -static void idepnp_remove(struct pnp_dev *dev) -{ - struct ide_host *host = pnp_get_drvdata(dev); - - ide_host_remove(host); - - release_region(pnp_port_start(dev, 1), 1); - release_region(pnp_port_start(dev, 0), 8); -} - -static struct pnp_driver idepnp_driver = { - .name = "ide", - .id_table = idepnp_devices, - .probe = idepnp_probe, - .remove = idepnp_remove, -}; - -module_pnp_driver(idepnp_driver); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c deleted file mode 100644 index aefd74c0d862..000000000000 --- a/drivers/ide/ide-probe.c +++ /dev/null @@ -1,1623 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) - * Copyright (C) 2005, 2007 Bartlomiej Zolnierkiewicz - */ - -/* - * Mostly written by Mark Lord - * and Gadi Oxman - * and Andre Hedrick - * - * See linux/MAINTAINERS for address of current maintainer. - * - * This is the IDE probe module, as evolved from hd.c and ide.c. - * - * -- increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot - * by Andrea Arcangeli - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/** - * generic_id - add a generic drive id - * @drive: drive to make an ID block for - * - * Add a fake id field to the drive we are passed. This allows - * use to skip a ton of NULL checks (which people always miss) - * and make drive properties unconditional outside of this file - */ - -static void generic_id(ide_drive_t *drive) -{ - u16 *id = drive->id; - - id[ATA_ID_CUR_CYLS] = id[ATA_ID_CYLS] = drive->cyl; - id[ATA_ID_CUR_HEADS] = id[ATA_ID_HEADS] = drive->head; - id[ATA_ID_CUR_SECTORS] = id[ATA_ID_SECTORS] = drive->sect; -} - -static void ide_disk_init_chs(ide_drive_t *drive) -{ - u16 *id = drive->id; - - /* Extract geometry if we did not already have one for the drive */ - if (!drive->cyl || !drive->head || !drive->sect) { - drive->cyl = drive->bios_cyl = id[ATA_ID_CYLS]; - drive->head = drive->bios_head = id[ATA_ID_HEADS]; - drive->sect = drive->bios_sect = id[ATA_ID_SECTORS]; - } - - /* Handle logical geometry translation by the drive */ - if (ata_id_current_chs_valid(id)) { - drive->cyl = id[ATA_ID_CUR_CYLS]; - drive->head = id[ATA_ID_CUR_HEADS]; - drive->sect = id[ATA_ID_CUR_SECTORS]; - } - - /* Use physical geometry if what we have still makes no sense */ - if (drive->head > 16 && id[ATA_ID_HEADS] && id[ATA_ID_HEADS] <= 16) { - drive->cyl = id[ATA_ID_CYLS]; - drive->head = id[ATA_ID_HEADS]; - drive->sect = id[ATA_ID_SECTORS]; - } -} - -static void ide_disk_init_mult_count(ide_drive_t *drive) -{ - u16 *id = drive->id; - u8 max_multsect = id[ATA_ID_MAX_MULTSECT] & 0xff; - - if (max_multsect) { - if ((max_multsect / 2) > 1) - id[ATA_ID_MULTSECT] = max_multsect | 0x100; - else - id[ATA_ID_MULTSECT] &= ~0x1ff; - - drive->mult_req = id[ATA_ID_MULTSECT] & 0xff; - - if (drive->mult_req) - drive->special_flags |= IDE_SFLAG_SET_MULTMODE; - } -} - -static void ide_classify_ata_dev(ide_drive_t *drive) -{ - u16 *id = drive->id; - char *m = (char *)&id[ATA_ID_PROD]; - int is_cfa = ata_id_is_cfa(id); - - /* CF devices are *not* removable in Linux definition of the term */ - if (is_cfa == 0 && (id[ATA_ID_CONFIG] & (1 << 7))) - drive->dev_flags |= IDE_DFLAG_REMOVABLE; - - drive->media = ide_disk; - - if (!ata_id_has_unload(drive->id)) - drive->dev_flags |= IDE_DFLAG_NO_UNLOAD; - - printk(KERN_INFO "%s: %s, %s DISK drive\n", drive->name, m, - is_cfa ? "CFA" : "ATA"); -} - -static void ide_classify_atapi_dev(ide_drive_t *drive) -{ - u16 *id = drive->id; - char *m = (char *)&id[ATA_ID_PROD]; - u8 type = (id[ATA_ID_CONFIG] >> 8) & 0x1f; - - printk(KERN_INFO "%s: %s, ATAPI ", drive->name, m); - switch (type) { - case ide_floppy: - if (!strstr(m, "CD-ROM")) { - if (!strstr(m, "oppy") && - !strstr(m, "poyp") && - !strstr(m, "ZIP")) - printk(KERN_CONT "cdrom or floppy?, assuming "); - if (drive->media != ide_cdrom) { - printk(KERN_CONT "FLOPPY"); - drive->dev_flags |= IDE_DFLAG_REMOVABLE; - break; - } - } - /* Early cdrom models used zero */ - type = ide_cdrom; - fallthrough; - case ide_cdrom: - drive->dev_flags |= IDE_DFLAG_REMOVABLE; -#ifdef CONFIG_PPC - /* kludge for Apple PowerBook internal zip */ - if (!strstr(m, "CD-ROM") && strstr(m, "ZIP")) { - printk(KERN_CONT "FLOPPY"); - type = ide_floppy; - break; - } -#endif - printk(KERN_CONT "CD/DVD-ROM"); - break; - case ide_tape: - printk(KERN_CONT "TAPE"); - break; - case ide_optical: - printk(KERN_CONT "OPTICAL"); - drive->dev_flags |= IDE_DFLAG_REMOVABLE; - break; - default: - printk(KERN_CONT "UNKNOWN (type %d)", type); - break; - } - - printk(KERN_CONT " drive\n"); - drive->media = type; - /* an ATAPI device ignores DRDY */ - drive->ready_stat = 0; - if (ata_id_cdb_intr(id)) - drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT; - drive->dev_flags |= IDE_DFLAG_DOORLOCKING; - /* we don't do head unloading on ATAPI devices */ - drive->dev_flags |= IDE_DFLAG_NO_UNLOAD; -} - -/** - * do_identify - identify a drive - * @drive: drive to identify - * @cmd: command used - * @id: buffer for IDENTIFY data - * - * Called when we have issued a drive identify command to - * read and parse the results. This function is run with - * interrupts disabled. - */ - -static void do_identify(ide_drive_t *drive, u8 cmd, u16 *id) -{ - ide_hwif_t *hwif = drive->hwif; - char *m = (char *)&id[ATA_ID_PROD]; - unsigned long flags; - int bswap = 1; - - /* local CPU only; some systems need this */ - local_irq_save(flags); - /* read 512 bytes of id info */ - hwif->tp_ops->input_data(drive, NULL, id, SECTOR_SIZE); - local_irq_restore(flags); - - drive->dev_flags |= IDE_DFLAG_ID_READ; -#ifdef DEBUG - printk(KERN_INFO "%s: dumping identify data\n", drive->name); - ide_dump_identify((u8 *)id); -#endif - ide_fix_driveid(id); - - /* - * ATA_CMD_ID_ATA returns little-endian info, - * ATA_CMD_ID_ATAPI *usually* returns little-endian info. - */ - if (cmd == ATA_CMD_ID_ATAPI) { - if ((m[0] == 'N' && m[1] == 'E') || /* NEC */ - (m[0] == 'F' && m[1] == 'X') || /* Mitsumi */ - (m[0] == 'P' && m[1] == 'i')) /* Pioneer */ - /* Vertos drives may still be weird */ - bswap ^= 1; - } - - ide_fixstring(m, ATA_ID_PROD_LEN, bswap); - ide_fixstring((char *)&id[ATA_ID_FW_REV], ATA_ID_FW_REV_LEN, bswap); - ide_fixstring((char *)&id[ATA_ID_SERNO], ATA_ID_SERNO_LEN, bswap); - - /* we depend on this a lot! */ - m[ATA_ID_PROD_LEN - 1] = '\0'; - - if (strstr(m, "E X A B Y T E N E S T")) - drive->dev_flags &= ~IDE_DFLAG_PRESENT; - else - drive->dev_flags |= IDE_DFLAG_PRESENT; -} - -/** - * ide_dev_read_id - send ATA/ATAPI IDENTIFY command - * @drive: drive to identify - * @cmd: command to use - * @id: buffer for IDENTIFY data - * @irq_ctx: flag set when called from the IRQ context - * - * Sends an ATA(PI) IDENTIFY request to a drive and waits for a response. - * - * Returns: 0 device was identified - * 1 device timed-out (no response to identify request) - * 2 device aborted the command (refused to identify itself) - */ - -int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id, int irq_ctx) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_io_ports *io_ports = &hwif->io_ports; - const struct ide_tp_ops *tp_ops = hwif->tp_ops; - int use_altstatus = 0, rc; - unsigned long timeout; - u8 s = 0, a = 0; - - /* - * Disable device IRQ. Otherwise we'll get spurious interrupts - * during the identify phase that the IRQ handler isn't expecting. - */ - if (io_ports->ctl_addr) - tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS); - - /* take a deep breath */ - if (irq_ctx) - mdelay(50); - else - msleep(50); - - if (io_ports->ctl_addr && - (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0) { - a = tp_ops->read_altstatus(hwif); - s = tp_ops->read_status(hwif); - if ((a ^ s) & ~ATA_SENSE) - /* ancient Seagate drives, broken interfaces */ - printk(KERN_INFO "%s: probing with STATUS(0x%02x) " - "instead of ALTSTATUS(0x%02x)\n", - drive->name, s, a); - else - /* use non-intrusive polling */ - use_altstatus = 1; - } - - /* set features register for atapi - * identify command to be sure of reply - */ - if (cmd == ATA_CMD_ID_ATAPI) { - struct ide_taskfile tf; - - memset(&tf, 0, sizeof(tf)); - /* disable DMA & overlap */ - tp_ops->tf_load(drive, &tf, IDE_VALID_FEATURE); - } - - /* ask drive for ID */ - tp_ops->exec_command(hwif, cmd); - - timeout = ((cmd == ATA_CMD_ID_ATA) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; - - /* wait for IRQ and ATA_DRQ */ - if (irq_ctx) { - rc = __ide_wait_stat(drive, ATA_DRQ, BAD_R_STAT, timeout, &s); - if (rc) - return 1; - } else { - rc = ide_busy_sleep(drive, timeout, use_altstatus); - if (rc) - return 1; - - msleep(50); - s = tp_ops->read_status(hwif); - } - - if (OK_STAT(s, ATA_DRQ, BAD_R_STAT)) { - /* drive returned ID */ - do_identify(drive, cmd, id); - /* drive responded with ID */ - rc = 0; - /* clear drive IRQ */ - (void)tp_ops->read_status(hwif); - } else { - /* drive refused ID */ - rc = 2; - } - return rc; -} - -int ide_busy_sleep(ide_drive_t *drive, unsigned long timeout, int altstatus) -{ - ide_hwif_t *hwif = drive->hwif; - u8 stat; - - timeout += jiffies; - - do { - msleep(50); /* give drive a breather */ - stat = altstatus ? hwif->tp_ops->read_altstatus(hwif) - : hwif->tp_ops->read_status(hwif); - if ((stat & ATA_BUSY) == 0) - return 0; - } while (time_before(jiffies, timeout)); - - printk(KERN_ERR "%s: timeout in %s\n", drive->name, __func__); - - return 1; /* drive timed-out */ -} - -static u8 ide_read_device(ide_drive_t *drive) -{ - struct ide_taskfile tf; - - drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_DEVICE); - - return tf.device; -} - -/** - * do_probe - probe an IDE device - * @drive: drive to probe - * @cmd: command to use - * - * do_probe() has the difficult job of finding a drive if it exists, - * without getting hung up if it doesn't exist, without trampling on - * ethernet cards, and without leaving any IRQs dangling to haunt us later. - * - * If a drive is "known" to exist (from CMOS or kernel parameters), - * but does not respond right away, the probe will "hang in there" - * for the maximum wait time (about 30 seconds), otherwise it will - * exit much more quickly. - * - * Returns: 0 device was identified - * 1 device timed-out (no response to identify request) - * 2 device aborted the command (refused to identify itself) - * 3 bad status from device (possible for ATAPI drives) - * 4 probe was not attempted because failure was obvious - */ - -static int do_probe (ide_drive_t *drive, u8 cmd) -{ - ide_hwif_t *hwif = drive->hwif; - const struct ide_tp_ops *tp_ops = hwif->tp_ops; - u16 *id = drive->id; - int rc; - u8 present = !!(drive->dev_flags & IDE_DFLAG_PRESENT), stat; - - /* avoid waiting for inappropriate probes */ - if (present && drive->media != ide_disk && cmd == ATA_CMD_ID_ATA) - return 4; - -#ifdef DEBUG - printk(KERN_INFO "probing for %s: present=%d, media=%d, probetype=%s\n", - drive->name, present, drive->media, - (cmd == ATA_CMD_ID_ATA) ? "ATA" : "ATAPI"); -#endif - - /* needed for some systems - * (e.g. crw9624 as drive0 with disk as slave) - */ - msleep(50); - tp_ops->dev_select(drive); - msleep(50); - - if (ide_read_device(drive) != drive->select && present == 0) { - if (drive->dn & 1) { - /* exit with drive0 selected */ - tp_ops->dev_select(hwif->devices[0]); - /* allow ATA_BUSY to assert & clear */ - msleep(50); - } - /* no i/f present: mmm.. this should be a 4 -ml */ - return 3; - } - - stat = tp_ops->read_status(hwif); - - if (OK_STAT(stat, ATA_DRDY, ATA_BUSY) || - present || cmd == ATA_CMD_ID_ATAPI) { - rc = ide_dev_read_id(drive, cmd, id, 0); - if (rc) - /* failed: try again */ - rc = ide_dev_read_id(drive, cmd, id, 0); - - stat = tp_ops->read_status(hwif); - - if (stat == (ATA_BUSY | ATA_DRDY)) - return 4; - - if (rc == 1 && cmd == ATA_CMD_ID_ATAPI) { - printk(KERN_ERR "%s: no response (status = 0x%02x), " - "resetting drive\n", drive->name, stat); - msleep(50); - tp_ops->dev_select(drive); - msleep(50); - tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET); - (void)ide_busy_sleep(drive, WAIT_WORSTCASE, 0); - rc = ide_dev_read_id(drive, cmd, id, 0); - } - - /* ensure drive IRQ is clear */ - stat = tp_ops->read_status(hwif); - - if (rc == 1) - printk(KERN_ERR "%s: no response (status = 0x%02x)\n", - drive->name, stat); - } else { - /* not present or maybe ATAPI */ - rc = 3; - } - if (drive->dn & 1) { - /* exit with drive0 selected */ - tp_ops->dev_select(hwif->devices[0]); - msleep(50); - /* ensure drive irq is clear */ - (void)tp_ops->read_status(hwif); - } - return rc; -} - -/** - * probe_for_drives - upper level drive probe - * @drive: drive to probe for - * - * probe_for_drive() tests for existence of a given drive using do_probe() - * and presents things to the user as needed. - * - * Returns: 0 no device was found - * 1 device was found - * (note: IDE_DFLAG_PRESENT might still be not set) - */ - -static u8 probe_for_drive(ide_drive_t *drive) -{ - char *m; - int rc; - u8 cmd; - - drive->dev_flags &= ~IDE_DFLAG_ID_READ; - - m = (char *)&drive->id[ATA_ID_PROD]; - strcpy(m, "UNKNOWN"); - - /* skip probing? */ - if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0) { - /* if !(success||timed-out) */ - cmd = ATA_CMD_ID_ATA; - rc = do_probe(drive, cmd); - if (rc >= 2) { - /* look for ATAPI device */ - cmd = ATA_CMD_ID_ATAPI; - rc = do_probe(drive, cmd); - } - - if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) - return 0; - - /* identification failed? */ - if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) { - if (drive->media == ide_disk) { - printk(KERN_INFO "%s: non-IDE drive, CHS=%d/%d/%d\n", - drive->name, drive->cyl, - drive->head, drive->sect); - } else if (drive->media == ide_cdrom) { - printk(KERN_INFO "%s: ATAPI cdrom (?)\n", drive->name); - } else { - /* nuke it */ - printk(KERN_WARNING "%s: Unknown device on bus refused identification. Ignoring.\n", drive->name); - drive->dev_flags &= ~IDE_DFLAG_PRESENT; - } - } else { - if (cmd == ATA_CMD_ID_ATAPI) - ide_classify_atapi_dev(drive); - else - ide_classify_ata_dev(drive); - } - } - - if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) - return 0; - - /* The drive wasn't being helpful. Add generic info only */ - if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) { - generic_id(drive); - return 1; - } - - if (drive->media == ide_disk) { - ide_disk_init_chs(drive); - ide_disk_init_mult_count(drive); - } - - return 1; -} - -static void hwif_release_dev(struct device *dev) -{ - ide_hwif_t *hwif = container_of(dev, ide_hwif_t, gendev); - - complete(&hwif->gendev_rel_comp); -} - -static int ide_register_port(ide_hwif_t *hwif) -{ - int ret; - - /* register with global device tree */ - dev_set_name(&hwif->gendev, "%s", hwif->name); - dev_set_drvdata(&hwif->gendev, hwif); - if (hwif->gendev.parent == NULL) - hwif->gendev.parent = hwif->dev; - hwif->gendev.release = hwif_release_dev; - - ret = device_register(&hwif->gendev); - if (ret < 0) { - printk(KERN_WARNING "IDE: %s: device_register error: %d\n", - __func__, ret); - goto out; - } - - hwif->portdev = device_create(ide_port_class, &hwif->gendev, - MKDEV(0, 0), hwif, "%s", hwif->name); - if (IS_ERR(hwif->portdev)) { - ret = PTR_ERR(hwif->portdev); - device_unregister(&hwif->gendev); - } -out: - return ret; -} - -/** - * ide_port_wait_ready - wait for port to become ready - * @hwif: IDE port - * - * This is needed on some PPCs and a bunch of BIOS-less embedded - * platforms. Typical cases are: - * - * - The firmware hard reset the disk before booting the kernel, - * the drive is still doing it's poweron-reset sequence, that - * can take up to 30 seconds. - * - * - The firmware does nothing (or no firmware), the device is - * still in POST state (same as above actually). - * - * - Some CD/DVD/Writer combo drives tend to drive the bus during - * their reset sequence even when they are non-selected slave - * devices, thus preventing discovery of the main HD. - * - * Doing this wait-for-non-busy should not harm any existing - * configuration and fix some issues like the above. - * - * BenH. - * - * Returns 0 on success, error code (< 0) otherwise. - */ - -static int ide_port_wait_ready(ide_hwif_t *hwif) -{ - const struct ide_tp_ops *tp_ops = hwif->tp_ops; - ide_drive_t *drive; - int i, rc; - - printk(KERN_DEBUG "Probing IDE interface %s...\n", hwif->name); - - /* Let HW settle down a bit from whatever init state we - * come from */ - mdelay(2); - - /* Wait for BSY bit to go away, spec timeout is 30 seconds, - * I know of at least one disk who takes 31 seconds, I use 35 - * here to be safe - */ - rc = ide_wait_not_busy(hwif, 35000); - if (rc) - return rc; - - /* Now make sure both master & slave are ready */ - ide_port_for_each_dev(i, drive, hwif) { - /* Ignore disks that we will not probe for later. */ - if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0 || - (drive->dev_flags & IDE_DFLAG_PRESENT)) { - tp_ops->dev_select(drive); - tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); - mdelay(2); - rc = ide_wait_not_busy(hwif, 35000); - if (rc) - goto out; - } else - printk(KERN_DEBUG "%s: ide_wait_not_busy() skipped\n", - drive->name); - } -out: - /* Exit function with master reselected (let's be sane) */ - if (i) - tp_ops->dev_select(hwif->devices[0]); - - return rc; -} - -/** - * ide_undecoded_slave - look for bad CF adapters - * @dev1: slave device - * - * Analyse the drives on the interface and attempt to decide if we - * have the same drive viewed twice. This occurs with crap CF adapters - * and PCMCIA sometimes. - */ - -void ide_undecoded_slave(ide_drive_t *dev1) -{ - ide_drive_t *dev0 = dev1->hwif->devices[0]; - - if ((dev1->dn & 1) == 0 || (dev0->dev_flags & IDE_DFLAG_PRESENT) == 0) - return; - - /* If the models don't match they are not the same product */ - if (strcmp((char *)&dev0->id[ATA_ID_PROD], - (char *)&dev1->id[ATA_ID_PROD])) - return; - - /* Serial numbers do not match */ - if (strncmp((char *)&dev0->id[ATA_ID_SERNO], - (char *)&dev1->id[ATA_ID_SERNO], ATA_ID_SERNO_LEN)) - return; - - /* No serial number, thankfully very rare for CF */ - if (*(char *)&dev0->id[ATA_ID_SERNO] == 0) - return; - - /* Appears to be an IDE flash adapter with decode bugs */ - printk(KERN_WARNING "ide-probe: ignoring undecoded slave\n"); - - dev1->dev_flags &= ~IDE_DFLAG_PRESENT; -} - -EXPORT_SYMBOL_GPL(ide_undecoded_slave); - -static int ide_probe_port(ide_hwif_t *hwif) -{ - ide_drive_t *drive; - unsigned int irqd; - int i, rc = -ENODEV; - - BUG_ON(hwif->present); - - if ((hwif->devices[0]->dev_flags & IDE_DFLAG_NOPROBE) && - (hwif->devices[1]->dev_flags & IDE_DFLAG_NOPROBE)) - return -EACCES; - - /* - * We must always disable IRQ, as probe_for_drive will assert IRQ, but - * we'll install our IRQ driver much later... - */ - irqd = hwif->irq; - if (irqd) - disable_irq(hwif->irq); - - if (ide_port_wait_ready(hwif) == -EBUSY) - printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name); - - /* - * Second drive should only exist if first drive was found, - * but a lot of cdrom drives are configured as single slaves. - */ - ide_port_for_each_dev(i, drive, hwif) { - (void) probe_for_drive(drive); - if (drive->dev_flags & IDE_DFLAG_PRESENT) - rc = 0; - } - - /* - * Use cached IRQ number. It might be (and is...) changed by probe - * code above - */ - if (irqd) - enable_irq(irqd); - - return rc; -} - -static void ide_port_tune_devices(ide_hwif_t *hwif) -{ - const struct ide_port_ops *port_ops = hwif->port_ops; - ide_drive_t *drive; - int i; - - ide_port_for_each_present_dev(i, drive, hwif) { - ide_check_nien_quirk_list(drive); - - if (port_ops && port_ops->quirkproc) - port_ops->quirkproc(drive); - } - - ide_port_for_each_present_dev(i, drive, hwif) { - ide_set_max_pio(drive); - - drive->dev_flags |= IDE_DFLAG_NICE1; - - if (hwif->dma_ops) - ide_set_dma(drive); - } -} - -static void ide_initialize_rq(struct request *rq) -{ - struct ide_request *req = blk_mq_rq_to_pdu(rq); - - req->special = NULL; - scsi_req_init(&req->sreq); - req->sreq.sense = req->sense; -} - -static const struct blk_mq_ops ide_mq_ops = { - .queue_rq = ide_queue_rq, - .initialize_rq_fn = ide_initialize_rq, -}; - -/* - * init request queue - */ -static int ide_init_queue(ide_drive_t *drive) -{ - struct request_queue *q; - ide_hwif_t *hwif = drive->hwif; - int max_sectors = 256; - int max_sg_entries = PRD_ENTRIES; - struct blk_mq_tag_set *set; - - /* - * Our default set up assumes the normal IDE case, - * that is 64K segmenting, standard PRD setup - * and LBA28. Some drivers then impose their own - * limits and LBA48 we could raise it but as yet - * do not. - */ - - set = &drive->tag_set; - set->ops = &ide_mq_ops; - set->nr_hw_queues = 1; - set->queue_depth = 32; - set->reserved_tags = 1; - set->cmd_size = sizeof(struct ide_request); - set->numa_node = hwif_to_node(hwif); - set->flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING; - if (blk_mq_alloc_tag_set(set)) - return 1; - - q = blk_mq_init_queue(set); - if (IS_ERR(q)) { - blk_mq_free_tag_set(set); - return 1; - } - - blk_queue_flag_set(QUEUE_FLAG_SCSI_PASSTHROUGH, q); - - q->queuedata = drive; - blk_queue_segment_boundary(q, 0xffff); - - if (hwif->rqsize < max_sectors) - max_sectors = hwif->rqsize; - blk_queue_max_hw_sectors(q, max_sectors); - -#ifdef CONFIG_PCI - /* When we have an IOMMU, we may have a problem where pci_map_sg() - * creates segments that don't completely match our boundary - * requirements and thus need to be broken up again. Because it - * doesn't align properly either, we may actually have to break up - * to more segments than what was we got in the first place, a max - * worst case is twice as many. - * This will be fixed once we teach pci_map_sg() about our boundary - * requirements, hopefully soon. *FIXME* - */ - max_sg_entries >>= 1; -#endif /* CONFIG_PCI */ - - blk_queue_max_segments(q, max_sg_entries); - - /* assign drive queue */ - drive->queue = q; - - return 0; -} - -static DEFINE_MUTEX(ide_cfg_mtx); - -/* - * For any present drive: - * - allocate the block device queue - */ -static int ide_port_setup_devices(ide_hwif_t *hwif) -{ - ide_drive_t *drive; - int i, j = 0; - - mutex_lock(&ide_cfg_mtx); - ide_port_for_each_present_dev(i, drive, hwif) { - if (ide_init_queue(drive)) { - printk(KERN_ERR "ide: failed to init %s\n", - drive->name); - drive->dev_flags &= ~IDE_DFLAG_PRESENT; - continue; - } - - j++; - } - mutex_unlock(&ide_cfg_mtx); - - return j; -} - -static void ide_host_enable_irqs(struct ide_host *host) -{ - ide_hwif_t *hwif; - int i; - - ide_host_for_each_port(i, hwif, host) { - if (hwif == NULL) - continue; - - /* clear any pending IRQs */ - hwif->tp_ops->read_status(hwif); - - /* unmask IRQs */ - if (hwif->io_ports.ctl_addr) - hwif->tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); - } -} - -/* - * This routine sets up the IRQ for an IDE interface. - */ -static int init_irq (ide_hwif_t *hwif) -{ - struct ide_io_ports *io_ports = &hwif->io_ports; - struct ide_host *host = hwif->host; - irq_handler_t irq_handler = host->irq_handler; - int sa = host->irq_flags; - - if (irq_handler == NULL) - irq_handler = ide_intr; - - if (!host->get_lock) - if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif)) - goto out_up; - -#if !defined(__mc68000__) - printk(KERN_INFO "%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name, - io_ports->data_addr, io_ports->status_addr, - io_ports->ctl_addr, hwif->irq); -#else - printk(KERN_INFO "%s at 0x%08lx on irq %d", hwif->name, - io_ports->data_addr, hwif->irq); -#endif /* __mc68000__ */ - if (hwif->host->host_flags & IDE_HFLAG_SERIALIZE) - printk(KERN_CONT " (serialized)"); - printk(KERN_CONT "\n"); - - return 0; -out_up: - return 1; -} - -static void ata_probe(dev_t dev) -{ - request_module("ide-disk"); - request_module("ide-cd"); - request_module("ide-tape"); - request_module("ide-floppy"); -} - -void ide_init_disk(struct gendisk *disk, ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - unsigned int unit = drive->dn & 1; - - disk->major = hwif->major; - disk->first_minor = unit << PARTN_BITS; - sprintf(disk->disk_name, "hd%c", 'a' + hwif->index * MAX_DRIVES + unit); - disk->queue = drive->queue; -} - -EXPORT_SYMBOL_GPL(ide_init_disk); - -static void drive_release_dev (struct device *dev) -{ - ide_drive_t *drive = container_of(dev, ide_drive_t, gendev); - - ide_proc_unregister_device(drive); - - if (drive->sense_rq) - blk_mq_free_request(drive->sense_rq); - - blk_cleanup_queue(drive->queue); - drive->queue = NULL; - blk_mq_free_tag_set(&drive->tag_set); - - drive->dev_flags &= ~IDE_DFLAG_PRESENT; - - complete(&drive->gendev_rel_comp); -} - -static int hwif_init(ide_hwif_t *hwif) -{ - if (!hwif->irq) { - printk(KERN_ERR "%s: disabled, no IRQ\n", hwif->name); - return 0; - } - - if (__register_blkdev(hwif->major, hwif->name, ata_probe)) - return 0; - - if (!hwif->sg_max_nents) - hwif->sg_max_nents = PRD_ENTRIES; - - hwif->sg_table = kmalloc_array(hwif->sg_max_nents, - sizeof(struct scatterlist), - GFP_KERNEL); - if (!hwif->sg_table) { - printk(KERN_ERR "%s: unable to allocate SG table.\n", hwif->name); - goto out; - } - - sg_init_table(hwif->sg_table, hwif->sg_max_nents); - - if (init_irq(hwif)) { - printk(KERN_ERR "%s: disabled, unable to get IRQ %d\n", - hwif->name, hwif->irq); - goto out; - } - - return 1; - -out: - unregister_blkdev(hwif->major, hwif->name); - return 0; -} - -static void hwif_register_devices(ide_hwif_t *hwif) -{ - ide_drive_t *drive; - unsigned int i; - - ide_port_for_each_present_dev(i, drive, hwif) { - struct device *dev = &drive->gendev; - int ret; - - dev_set_name(dev, "%u.%u", hwif->index, i); - dev_set_drvdata(dev, drive); - dev->parent = &hwif->gendev; - dev->bus = &ide_bus_type; - dev->release = drive_release_dev; - - ret = device_register(dev); - if (ret < 0) - printk(KERN_WARNING "IDE: %s: device_register error: " - "%d\n", __func__, ret); - } -} - -static void ide_port_init_devices(ide_hwif_t *hwif) -{ - const struct ide_port_ops *port_ops = hwif->port_ops; - ide_drive_t *drive; - int i; - - ide_port_for_each_dev(i, drive, hwif) { - drive->dn = i + hwif->channel * 2; - - if (hwif->host_flags & IDE_HFLAG_IO_32BIT) - drive->io_32bit = 1; - if (hwif->host_flags & IDE_HFLAG_NO_IO_32BIT) - drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT; - if (hwif->host_flags & IDE_HFLAG_UNMASK_IRQS) - drive->dev_flags |= IDE_DFLAG_UNMASK; - if (hwif->host_flags & IDE_HFLAG_NO_UNMASK_IRQS) - drive->dev_flags |= IDE_DFLAG_NO_UNMASK; - - drive->pio_mode = XFER_PIO_0; - - if (port_ops && port_ops->init_dev) - port_ops->init_dev(drive); - } -} - -static void ide_init_port(ide_hwif_t *hwif, unsigned int port, - const struct ide_port_info *d) -{ - hwif->channel = port; - - hwif->chipset = d->chipset ? d->chipset : ide_pci; - - if (d->init_iops) - d->init_iops(hwif); - - /* ->host_flags may be set by ->init_iops (or even earlier...) */ - hwif->host_flags |= d->host_flags; - hwif->pio_mask = d->pio_mask; - - if (d->tp_ops) - hwif->tp_ops = d->tp_ops; - - /* ->set_pio_mode for DTC2278 is currently limited to port 0 */ - if ((hwif->host_flags & IDE_HFLAG_DTC2278) == 0 || hwif->channel == 0) - hwif->port_ops = d->port_ops; - - hwif->swdma_mask = d->swdma_mask; - hwif->mwdma_mask = d->mwdma_mask; - hwif->ultra_mask = d->udma_mask; - - if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) { - int rc; - - hwif->dma_ops = d->dma_ops; - - if (d->init_dma) - rc = d->init_dma(hwif, d); - else - rc = ide_hwif_setup_dma(hwif, d); - - if (rc < 0) { - printk(KERN_INFO "%s: DMA disabled\n", hwif->name); - - hwif->dma_ops = NULL; - hwif->dma_base = 0; - hwif->swdma_mask = 0; - hwif->mwdma_mask = 0; - hwif->ultra_mask = 0; - } - } - - if ((d->host_flags & IDE_HFLAG_SERIALIZE) || - ((d->host_flags & IDE_HFLAG_SERIALIZE_DMA) && hwif->dma_base)) - hwif->host->host_flags |= IDE_HFLAG_SERIALIZE; - - if (d->max_sectors) - hwif->rqsize = d->max_sectors; - else { - if ((hwif->host_flags & IDE_HFLAG_NO_LBA48) || - (hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA)) - hwif->rqsize = 256; - else - hwif->rqsize = 65536; - } - - /* call chipset specific routine for each enabled port */ - if (d->init_hwif) - d->init_hwif(hwif); -} - -static void ide_port_cable_detect(ide_hwif_t *hwif) -{ - const struct ide_port_ops *port_ops = hwif->port_ops; - - if (port_ops && port_ops->cable_detect && (hwif->ultra_mask & 0x78)) { - if (hwif->cbl != ATA_CBL_PATA40_SHORT) - hwif->cbl = port_ops->cable_detect(hwif); - } -} - -/* - * Deferred request list insertion handler - */ -static void drive_rq_insert_work(struct work_struct *work) -{ - ide_drive_t *drive = container_of(work, ide_drive_t, rq_work); - ide_hwif_t *hwif = drive->hwif; - struct request *rq; - blk_status_t ret; - LIST_HEAD(list); - - blk_mq_quiesce_queue(drive->queue); - - ret = BLK_STS_OK; - spin_lock_irq(&hwif->lock); - while (!list_empty(&drive->rq_list)) { - rq = list_first_entry(&drive->rq_list, struct request, queuelist); - list_del_init(&rq->queuelist); - - spin_unlock_irq(&hwif->lock); - ret = ide_issue_rq(drive, rq, true); - spin_lock_irq(&hwif->lock); - } - spin_unlock_irq(&hwif->lock); - - blk_mq_unquiesce_queue(drive->queue); - - if (ret != BLK_STS_OK) - kblockd_schedule_work(&drive->rq_work); -} - -static const u8 ide_hwif_to_major[] = - { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, - IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR }; - -static void ide_port_init_devices_data(ide_hwif_t *hwif) -{ - ide_drive_t *drive; - int i; - - ide_port_for_each_dev(i, drive, hwif) { - u8 j = (hwif->index * MAX_DRIVES) + i; - u16 *saved_id = drive->id; - - memset(drive, 0, sizeof(*drive)); - memset(saved_id, 0, SECTOR_SIZE); - drive->id = saved_id; - - drive->media = ide_disk; - drive->select = (i << 4) | ATA_DEVICE_OBS; - drive->hwif = hwif; - drive->ready_stat = ATA_DRDY; - drive->bad_wstat = BAD_W_STAT; - drive->special_flags = IDE_SFLAG_RECALIBRATE | - IDE_SFLAG_SET_GEOMETRY; - drive->name[0] = 'h'; - drive->name[1] = 'd'; - drive->name[2] = 'a' + j; - drive->max_failures = IDE_DEFAULT_MAX_FAILURES; - - INIT_LIST_HEAD(&drive->list); - init_completion(&drive->gendev_rel_comp); - - INIT_WORK(&drive->rq_work, drive_rq_insert_work); - INIT_LIST_HEAD(&drive->rq_list); - } -} - -static void ide_init_port_data(ide_hwif_t *hwif, unsigned int index) -{ - /* fill in any non-zero initial values */ - hwif->index = index; - hwif->major = ide_hwif_to_major[index]; - - hwif->name[0] = 'i'; - hwif->name[1] = 'd'; - hwif->name[2] = 'e'; - hwif->name[3] = '0' + index; - - spin_lock_init(&hwif->lock); - - timer_setup(&hwif->timer, ide_timer_expiry, 0); - - init_completion(&hwif->gendev_rel_comp); - - hwif->tp_ops = &default_tp_ops; - - ide_port_init_devices_data(hwif); -} - -static void ide_init_port_hw(ide_hwif_t *hwif, struct ide_hw *hw) -{ - memcpy(&hwif->io_ports, &hw->io_ports, sizeof(hwif->io_ports)); - hwif->irq = hw->irq; - hwif->dev = hw->dev; - hwif->gendev.parent = hw->parent ? hw->parent : hw->dev; - hwif->config_data = hw->config; -} - -static unsigned int ide_indexes; - -/** - * ide_find_port_slot - find free port slot - * @d: IDE port info - * - * Return the new port slot index or -ENOENT if we are out of free slots. - */ - -static int ide_find_port_slot(const struct ide_port_info *d) -{ - int idx = -ENOENT; - u8 bootable = (d && (d->host_flags & IDE_HFLAG_NON_BOOTABLE)) ? 0 : 1; - u8 i = (d && (d->host_flags & IDE_HFLAG_QD_2ND_PORT)) ? 1 : 0; - - /* - * Claim an unassigned slot. - * - * Give preference to claiming other slots before claiming ide0/ide1, - * just in case there's another interface yet-to-be-scanned - * which uses ports 0x1f0/0x170 (the ide0/ide1 defaults). - * - * Unless there is a bootable card that does not use the standard - * ports 0x1f0/0x170 (the ide0/ide1 defaults). - */ - mutex_lock(&ide_cfg_mtx); - if (bootable) { - if ((ide_indexes | i) != (1 << MAX_HWIFS) - 1) - idx = ffz(ide_indexes | i); - } else { - if ((ide_indexes | 3) != (1 << MAX_HWIFS) - 1) - idx = ffz(ide_indexes | 3); - else if ((ide_indexes & 3) != 3) - idx = ffz(ide_indexes); - } - if (idx >= 0) - ide_indexes |= (1 << idx); - mutex_unlock(&ide_cfg_mtx); - - return idx; -} - -static void ide_free_port_slot(int idx) -{ - mutex_lock(&ide_cfg_mtx); - ide_indexes &= ~(1 << idx); - mutex_unlock(&ide_cfg_mtx); -} - -static void ide_port_free_devices(ide_hwif_t *hwif) -{ - ide_drive_t *drive; - int i; - - ide_port_for_each_dev(i, drive, hwif) { - kfree(drive->id); - kfree(drive); - } -} - -static int ide_port_alloc_devices(ide_hwif_t *hwif, int node) -{ - ide_drive_t *drive; - int i; - - for (i = 0; i < MAX_DRIVES; i++) { - drive = kzalloc_node(sizeof(*drive), GFP_KERNEL, node); - if (drive == NULL) - goto out_nomem; - - /* - * In order to keep things simple we have an id - * block for all drives at all times. If the device - * is pre ATA or refuses ATA/ATAPI identify we - * will add faked data to this. - * - * Also note that 0 everywhere means "can't do X" - */ - drive->id = kzalloc_node(SECTOR_SIZE, GFP_KERNEL, node); - if (drive->id == NULL) - goto out_free_drive; - - hwif->devices[i] = drive; - } - return 0; - -out_free_drive: - kfree(drive); -out_nomem: - ide_port_free_devices(hwif); - return -ENOMEM; -} - -struct ide_host *ide_host_alloc(const struct ide_port_info *d, - struct ide_hw **hws, unsigned int n_ports) -{ - struct ide_host *host; - struct device *dev = hws[0] ? hws[0]->dev : NULL; - int node = dev ? dev_to_node(dev) : -1; - int i; - - host = kzalloc_node(sizeof(*host), GFP_KERNEL, node); - if (host == NULL) - return NULL; - - for (i = 0; i < n_ports; i++) { - ide_hwif_t *hwif; - int idx; - - if (hws[i] == NULL) - continue; - - hwif = kzalloc_node(sizeof(*hwif), GFP_KERNEL, node); - if (hwif == NULL) - continue; - - if (ide_port_alloc_devices(hwif, node) < 0) { - kfree(hwif); - continue; - } - - idx = ide_find_port_slot(d); - if (idx < 0) { - printk(KERN_ERR "%s: no free slot for interface\n", - d ? d->name : "ide"); - ide_port_free_devices(hwif); - kfree(hwif); - continue; - } - - ide_init_port_data(hwif, idx); - - hwif->host = host; - - host->ports[i] = hwif; - host->n_ports++; - } - - if (host->n_ports == 0) { - kfree(host); - return NULL; - } - - host->dev[0] = dev; - - if (d) { - host->init_chipset = d->init_chipset; - host->get_lock = d->get_lock; - host->release_lock = d->release_lock; - host->host_flags = d->host_flags; - host->irq_flags = d->irq_flags; - } - - return host; -} -EXPORT_SYMBOL_GPL(ide_host_alloc); - -static void ide_port_free(ide_hwif_t *hwif) -{ - ide_port_free_devices(hwif); - ide_free_port_slot(hwif->index); - kfree(hwif); -} - -static void ide_disable_port(ide_hwif_t *hwif) -{ - struct ide_host *host = hwif->host; - int i; - - printk(KERN_INFO "%s: disabling port\n", hwif->name); - - for (i = 0; i < MAX_HOST_PORTS; i++) { - if (host->ports[i] == hwif) { - host->ports[i] = NULL; - host->n_ports--; - } - } - - ide_port_free(hwif); -} - -int ide_host_register(struct ide_host *host, const struct ide_port_info *d, - struct ide_hw **hws) -{ - ide_hwif_t *hwif, *mate = NULL; - int i, j = 0; - - pr_warn("legacy IDE will be removed in 2021, please switch to libata\n" - "Report any missing HW support to linux-ide@vger.kernel.org\n"); - - ide_host_for_each_port(i, hwif, host) { - if (hwif == NULL) { - mate = NULL; - continue; - } - - ide_init_port_hw(hwif, hws[i]); - ide_port_apply_params(hwif); - - if ((i & 1) && mate) { - hwif->mate = mate; - mate->mate = hwif; - } - - mate = (i & 1) ? NULL : hwif; - - ide_init_port(hwif, i & 1, d); - ide_port_cable_detect(hwif); - - hwif->port_flags |= IDE_PFLAG_PROBING; - - ide_port_init_devices(hwif); - } - - ide_host_for_each_port(i, hwif, host) { - if (hwif == NULL) - continue; - - if (ide_probe_port(hwif) == 0) - hwif->present = 1; - - hwif->port_flags &= ~IDE_PFLAG_PROBING; - - if ((hwif->host_flags & IDE_HFLAG_4DRIVES) == 0 || - hwif->mate == NULL || hwif->mate->present == 0) { - if (ide_register_port(hwif)) { - ide_disable_port(hwif); - continue; - } - } - - if (hwif->present) - ide_port_tune_devices(hwif); - } - - ide_host_enable_irqs(host); - - ide_host_for_each_port(i, hwif, host) { - if (hwif == NULL) - continue; - - if (hwif_init(hwif) == 0) { - printk(KERN_INFO "%s: failed to initialize IDE " - "interface\n", hwif->name); - device_unregister(hwif->portdev); - device_unregister(&hwif->gendev); - ide_disable_port(hwif); - continue; - } - - if (hwif->present) - if (ide_port_setup_devices(hwif) == 0) { - hwif->present = 0; - continue; - } - - j++; - - ide_acpi_init_port(hwif); - - if (hwif->present) - ide_acpi_port_init_devices(hwif); - } - - ide_host_for_each_port(i, hwif, host) { - if (hwif == NULL) - continue; - - ide_sysfs_register_port(hwif); - ide_proc_register_port(hwif); - - if (hwif->present) { - ide_proc_port_register_devices(hwif); - hwif_register_devices(hwif); - } - } - - return j ? 0 : -1; -} -EXPORT_SYMBOL_GPL(ide_host_register); - -int ide_host_add(const struct ide_port_info *d, struct ide_hw **hws, - unsigned int n_ports, struct ide_host **hostp) -{ - struct ide_host *host; - int rc; - - host = ide_host_alloc(d, hws, n_ports); - if (host == NULL) - return -ENOMEM; - - rc = ide_host_register(host, d, hws); - if (rc) { - ide_host_free(host); - return rc; - } - - if (hostp) - *hostp = host; - - return 0; -} -EXPORT_SYMBOL_GPL(ide_host_add); - -static void __ide_port_unregister_devices(ide_hwif_t *hwif) -{ - ide_drive_t *drive; - int i; - - ide_port_for_each_present_dev(i, drive, hwif) { - device_unregister(&drive->gendev); - wait_for_completion(&drive->gendev_rel_comp); - } -} - -void ide_port_unregister_devices(ide_hwif_t *hwif) -{ - mutex_lock(&ide_cfg_mtx); - __ide_port_unregister_devices(hwif); - hwif->present = 0; - ide_port_init_devices_data(hwif); - mutex_unlock(&ide_cfg_mtx); -} -EXPORT_SYMBOL_GPL(ide_port_unregister_devices); - -/** - * ide_unregister - free an IDE interface - * @hwif: IDE interface - * - * Perform the final unregister of an IDE interface. - * - * Locking: - * The caller must not hold the IDE locks. - * - * It is up to the caller to be sure there is no pending I/O here, - * and that the interface will not be reopened (present/vanishing - * locking isn't yet done BTW). - */ - -static void ide_unregister(ide_hwif_t *hwif) -{ - mutex_lock(&ide_cfg_mtx); - - if (hwif->present) { - __ide_port_unregister_devices(hwif); - hwif->present = 0; - } - - ide_proc_unregister_port(hwif); - - if (!hwif->host->get_lock) - free_irq(hwif->irq, hwif); - - device_unregister(hwif->portdev); - device_unregister(&hwif->gendev); - wait_for_completion(&hwif->gendev_rel_comp); - - /* - * Remove us from the kernel's knowledge - */ - kfree(hwif->sg_table); - unregister_blkdev(hwif->major, hwif->name); - - ide_release_dma_engine(hwif); - - mutex_unlock(&ide_cfg_mtx); -} - -void ide_host_free(struct ide_host *host) -{ - ide_hwif_t *hwif; - int i; - - ide_host_for_each_port(i, hwif, host) { - if (hwif) - ide_port_free(hwif); - } - - kfree(host); -} -EXPORT_SYMBOL_GPL(ide_host_free); - -void ide_host_remove(struct ide_host *host) -{ - ide_hwif_t *hwif; - int i; - - ide_host_for_each_port(i, hwif, host) { - if (hwif) - ide_unregister(hwif); - } - - ide_host_free(host); -} -EXPORT_SYMBOL_GPL(ide_host_remove); - -void ide_port_scan(ide_hwif_t *hwif) -{ - int rc; - - ide_port_apply_params(hwif); - ide_port_cable_detect(hwif); - - hwif->port_flags |= IDE_PFLAG_PROBING; - - ide_port_init_devices(hwif); - - rc = ide_probe_port(hwif); - - hwif->port_flags &= ~IDE_PFLAG_PROBING; - - if (rc < 0) - return; - - hwif->present = 1; - - ide_port_tune_devices(hwif); - ide_port_setup_devices(hwif); - ide_acpi_port_init_devices(hwif); - hwif_register_devices(hwif); - ide_proc_port_register_devices(hwif); -} -EXPORT_SYMBOL_GPL(ide_port_scan); diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c deleted file mode 100644 index 15c17f3781ee..000000000000 --- a/drivers/ide/ide-proc.c +++ /dev/null @@ -1,633 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1997-1998 Mark Lord - * Copyright (C) 2003 Red Hat - * - * Some code was moved here from ide.c, see it for original copyrights. - */ - -/* - * This is the /proc/ide/ filesystem implementation. - * - * Drive/Driver settings can be retrieved by reading the drive's - * "settings" files. e.g. "cat /proc/ide0/hda/settings" - * To write a new value "val" into a specific setting "name", use: - * echo "name:val" >/proc/ide/ide0/hda/settings - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static struct proc_dir_entry *proc_ide_root; - -static int ide_imodel_proc_show(struct seq_file *m, void *v) -{ - ide_hwif_t *hwif = (ide_hwif_t *) m->private; - const char *name; - - switch (hwif->chipset) { - case ide_generic: name = "generic"; break; - case ide_pci: name = "pci"; break; - case ide_cmd640: name = "cmd640"; break; - case ide_dtc2278: name = "dtc2278"; break; - case ide_ali14xx: name = "ali14xx"; break; - case ide_qd65xx: name = "qd65xx"; break; - case ide_umc8672: name = "umc8672"; break; - case ide_ht6560b: name = "ht6560b"; break; - case ide_4drives: name = "4drives"; break; - case ide_pmac: name = "mac-io"; break; - case ide_au1xxx: name = "au1xxx"; break; - case ide_palm3710: name = "palm3710"; break; - case ide_acorn: name = "acorn"; break; - default: name = "(unknown)"; break; - } - seq_printf(m, "%s\n", name); - return 0; -} - -static int ide_mate_proc_show(struct seq_file *m, void *v) -{ - ide_hwif_t *hwif = (ide_hwif_t *) m->private; - - if (hwif && hwif->mate) - seq_printf(m, "%s\n", hwif->mate->name); - else - seq_printf(m, "(none)\n"); - return 0; -} - -static int ide_channel_proc_show(struct seq_file *m, void *v) -{ - ide_hwif_t *hwif = (ide_hwif_t *) m->private; - - seq_printf(m, "%c\n", hwif->channel ? '1' : '0'); - return 0; -} - -static int ide_identify_proc_show(struct seq_file *m, void *v) -{ - ide_drive_t *drive = (ide_drive_t *)m->private; - u8 *buf; - - if (!drive) { - seq_putc(m, '\n'); - return 0; - } - - buf = kmalloc(SECTOR_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - if (taskfile_lib_get_identify(drive, buf) == 0) { - __le16 *val = (__le16 *)buf; - int i; - - for (i = 0; i < SECTOR_SIZE / 2; i++) { - seq_printf(m, "%04x%c", le16_to_cpu(val[i]), - (i % 8) == 7 ? '\n' : ' '); - } - } else - seq_putc(m, buf[0]); - kfree(buf); - return 0; -} - -/** - * ide_find_setting - find a specific setting - * @st: setting table pointer - * @name: setting name - * - * Scan's the setting table for a matching entry and returns - * this or NULL if no entry is found. The caller must hold the - * setting semaphore - */ - -static -const struct ide_proc_devset *ide_find_setting(const struct ide_proc_devset *st, - char *name) -{ - while (st->name) { - if (strcmp(st->name, name) == 0) - break; - st++; - } - return st->name ? st : NULL; -} - -/** - * ide_read_setting - read an IDE setting - * @drive: drive to read from - * @setting: drive setting - * - * Read a drive setting and return the value. The caller - * must hold the ide_setting_mtx when making this call. - * - * BUGS: the data return and error are the same return value - * so an error -EINVAL and true return of the same value cannot - * be told apart - */ - -static int ide_read_setting(ide_drive_t *drive, - const struct ide_proc_devset *setting) -{ - const struct ide_devset *ds = setting->setting; - int val = -EINVAL; - - if (ds->get) - val = ds->get(drive); - - return val; -} - -/** - * ide_write_setting - read an IDE setting - * @drive: drive to read from - * @setting: drive setting - * @val: value - * - * Write a drive setting if it is possible. The caller - * must hold the ide_setting_mtx when making this call. - * - * BUGS: the data return and error are the same return value - * so an error -EINVAL and true return of the same value cannot - * be told apart - * - * FIXME: This should be changed to enqueue a special request - * to the driver to change settings, and then wait on a sema for completion. - * The current scheme of polling is kludgy, though safe enough. - */ - -static int ide_write_setting(ide_drive_t *drive, - const struct ide_proc_devset *setting, int val) -{ - const struct ide_devset *ds = setting->setting; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (!ds->set) - return -EPERM; - if ((ds->flags & DS_SYNC) - && (val < setting->min || val > setting->max)) - return -EINVAL; - return ide_devset_execute(drive, ds, val); -} - -ide_devset_get(xfer_rate, current_speed); - -static int set_xfer_rate (ide_drive_t *drive, int arg) -{ - struct ide_cmd cmd; - - if (arg < XFER_PIO_0 || arg > XFER_UDMA_6) - return -EINVAL; - - memset(&cmd, 0, sizeof(cmd)); - cmd.tf.command = ATA_CMD_SET_FEATURES; - cmd.tf.feature = SETFEATURES_XFER; - cmd.tf.nsect = (u8)arg; - cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT; - cmd.valid.in.tf = IDE_VALID_NSECT; - cmd.tf_flags = IDE_TFLAG_SET_XFER; - - return ide_no_data_taskfile(drive, &cmd); -} - -ide_devset_rw(current_speed, xfer_rate); -ide_devset_rw_field(init_speed, init_speed); -ide_devset_rw_flag(nice1, IDE_DFLAG_NICE1); -ide_devset_ro_field(number, dn); - -static const struct ide_proc_devset ide_generic_settings[] = { - IDE_PROC_DEVSET(current_speed, 0, 70), - IDE_PROC_DEVSET(init_speed, 0, 70), - IDE_PROC_DEVSET(io_32bit, 0, 1 + (SUPPORT_VLB_SYNC << 1)), - IDE_PROC_DEVSET(keepsettings, 0, 1), - IDE_PROC_DEVSET(nice1, 0, 1), - IDE_PROC_DEVSET(number, 0, 3), - IDE_PROC_DEVSET(pio_mode, 0, 255), - IDE_PROC_DEVSET(unmaskirq, 0, 1), - IDE_PROC_DEVSET(using_dma, 0, 1), - { NULL }, -}; - -static void proc_ide_settings_warn(void) -{ - printk_once(KERN_WARNING "Warning: /proc/ide/hd?/settings interface is " - "obsolete, and will be removed soon!\n"); -} - -static int ide_settings_proc_show(struct seq_file *m, void *v) -{ - const struct ide_proc_devset *setting, *g, *d; - const struct ide_devset *ds; - ide_drive_t *drive = (ide_drive_t *) m->private; - int rc, mul_factor, div_factor; - - proc_ide_settings_warn(); - - mutex_lock(&ide_setting_mtx); - g = ide_generic_settings; - d = drive->settings; - seq_printf(m, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n"); - seq_printf(m, "----\t\t\t-----\t\t---\t\t---\t\t----\n"); - while (g->name || (d && d->name)) { - /* read settings in the alphabetical order */ - if (g->name && d && d->name) { - if (strcmp(d->name, g->name) < 0) - setting = d++; - else - setting = g++; - } else if (d && d->name) { - setting = d++; - } else - setting = g++; - mul_factor = setting->mulf ? setting->mulf(drive) : 1; - div_factor = setting->divf ? setting->divf(drive) : 1; - seq_printf(m, "%-24s", setting->name); - rc = ide_read_setting(drive, setting); - if (rc >= 0) - seq_printf(m, "%-16d", rc * mul_factor / div_factor); - else - seq_printf(m, "%-16s", "write-only"); - seq_printf(m, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor); - ds = setting->setting; - if (ds->get) - seq_printf(m, "r"); - if (ds->set) - seq_printf(m, "w"); - seq_printf(m, "\n"); - } - mutex_unlock(&ide_setting_mtx); - return 0; -} - -static int ide_settings_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, ide_settings_proc_show, PDE_DATA(inode)); -} - -#define MAX_LEN 30 - -static ssize_t ide_settings_proc_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos) -{ - ide_drive_t *drive = PDE_DATA(file_inode(file)); - char name[MAX_LEN + 1]; - int for_real = 0, mul_factor, div_factor; - unsigned long n; - - const struct ide_proc_devset *setting; - char *buf, *s; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - proc_ide_settings_warn(); - - if (count >= PAGE_SIZE) - return -EINVAL; - - s = buf = (char *)__get_free_page(GFP_USER); - if (!buf) - return -ENOMEM; - - if (copy_from_user(buf, buffer, count)) { - free_page((unsigned long)buf); - return -EFAULT; - } - - buf[count] = '\0'; - - /* - * Skip over leading whitespace - */ - while (count && isspace(*s)) { - --count; - ++s; - } - /* - * Do one full pass to verify all parameters, - * then do another to actually write the new settings. - */ - do { - char *p = s; - n = count; - while (n > 0) { - unsigned val; - char *q = p; - - while (n > 0 && *p != ':') { - --n; - p++; - } - if (*p != ':') - goto parse_error; - if (p - q > MAX_LEN) - goto parse_error; - memcpy(name, q, p - q); - name[p - q] = 0; - - if (n > 0) { - --n; - p++; - } else - goto parse_error; - - val = simple_strtoul(p, &q, 10); - n -= q - p; - p = q; - if (n > 0 && !isspace(*p)) - goto parse_error; - while (n > 0 && isspace(*p)) { - --n; - ++p; - } - - mutex_lock(&ide_setting_mtx); - /* generic settings first, then driver specific ones */ - setting = ide_find_setting(ide_generic_settings, name); - if (!setting) { - if (drive->settings) - setting = ide_find_setting(drive->settings, name); - if (!setting) { - mutex_unlock(&ide_setting_mtx); - goto parse_error; - } - } - if (for_real) { - mul_factor = setting->mulf ? setting->mulf(drive) : 1; - div_factor = setting->divf ? setting->divf(drive) : 1; - ide_write_setting(drive, setting, val * div_factor / mul_factor); - } - mutex_unlock(&ide_setting_mtx); - } - } while (!for_real++); - free_page((unsigned long)buf); - return count; -parse_error: - free_page((unsigned long)buf); - printk("%s(): parse error\n", __func__); - return -EINVAL; -} - -static const struct proc_ops ide_settings_proc_ops = { - .proc_open = ide_settings_proc_open, - .proc_read = seq_read, - .proc_lseek = seq_lseek, - .proc_release = single_release, - .proc_write = ide_settings_proc_write, -}; - -int ide_capacity_proc_show(struct seq_file *m, void *v) -{ - seq_printf(m, "%llu\n", (long long)0x7fffffff); - return 0; -} -EXPORT_SYMBOL_GPL(ide_capacity_proc_show); - -int ide_geometry_proc_show(struct seq_file *m, void *v) -{ - ide_drive_t *drive = (ide_drive_t *) m->private; - - seq_printf(m, "physical %d/%d/%d\n", - drive->cyl, drive->head, drive->sect); - seq_printf(m, "logical %d/%d/%d\n", - drive->bios_cyl, drive->bios_head, drive->bios_sect); - return 0; -} -EXPORT_SYMBOL(ide_geometry_proc_show); - -static int ide_dmodel_proc_show(struct seq_file *seq, void *v) -{ - ide_drive_t *drive = (ide_drive_t *) seq->private; - char *m = (char *)&drive->id[ATA_ID_PROD]; - - seq_printf(seq, "%.40s\n", m[0] ? m : "(none)"); - return 0; -} - -static int ide_driver_proc_show(struct seq_file *m, void *v) -{ - ide_drive_t *drive = (ide_drive_t *)m->private; - struct device *dev = &drive->gendev; - struct ide_driver *ide_drv; - - if (dev->driver) { - ide_drv = to_ide_driver(dev->driver); - seq_printf(m, "%s version %s\n", - dev->driver->name, ide_drv->version); - } else - seq_printf(m, "ide-default version 0.9.newide\n"); - return 0; -} - -static int ide_media_proc_show(struct seq_file *m, void *v) -{ - ide_drive_t *drive = (ide_drive_t *) m->private; - const char *media; - - switch (drive->media) { - case ide_disk: media = "disk\n"; break; - case ide_cdrom: media = "cdrom\n"; break; - case ide_tape: media = "tape\n"; break; - case ide_floppy: media = "floppy\n"; break; - case ide_optical: media = "optical\n"; break; - default: media = "UNKNOWN\n"; break; - } - seq_puts(m, media); - return 0; -} - -static int ide_media_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, ide_media_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations ide_media_proc_fops = { - .owner = THIS_MODULE, - .open = ide_media_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static ide_proc_entry_t generic_drive_entries[] = { - { "driver", S_IFREG|S_IRUGO, ide_driver_proc_show }, - { "identify", S_IFREG|S_IRUSR, ide_identify_proc_show }, - { "media", S_IFREG|S_IRUGO, ide_media_proc_show }, - { "model", S_IFREG|S_IRUGO, ide_dmodel_proc_show }, - {} -}; - -static void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data) -{ - struct proc_dir_entry *ent; - - if (!dir || !p) - return; - while (p->name != NULL) { - ent = proc_create_single_data(p->name, p->mode, dir, p->show, data); - if (!ent) return; - p++; - } -} - -static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p) -{ - if (!dir || !p) - return; - while (p->name != NULL) { - remove_proc_entry(p->name, dir); - p++; - } -} - -void ide_proc_register_driver(ide_drive_t *drive, struct ide_driver *driver) -{ - mutex_lock(&ide_setting_mtx); - drive->settings = driver->proc_devsets(drive); - mutex_unlock(&ide_setting_mtx); - - ide_add_proc_entries(drive->proc, driver->proc_entries(drive), drive); -} - -EXPORT_SYMBOL(ide_proc_register_driver); - -/** - * ide_proc_unregister_driver - remove driver specific data - * @drive: drive - * @driver: driver - * - * Clean up the driver specific /proc files and IDE settings - * for a given drive. - * - * Takes ide_setting_mtx. - */ - -void ide_proc_unregister_driver(ide_drive_t *drive, struct ide_driver *driver) -{ - ide_remove_proc_entries(drive->proc, driver->proc_entries(drive)); - - mutex_lock(&ide_setting_mtx); - /* - * ide_setting_mtx protects both the settings list and the use - * of settings (we cannot take a setting out that is being used). - */ - drive->settings = NULL; - mutex_unlock(&ide_setting_mtx); -} -EXPORT_SYMBOL(ide_proc_unregister_driver); - -void ide_proc_port_register_devices(ide_hwif_t *hwif) -{ - struct proc_dir_entry *ent; - struct proc_dir_entry *parent = hwif->proc; - ide_drive_t *drive; - char name[64]; - int i; - - ide_port_for_each_dev(i, drive, hwif) { - if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) - continue; - - drive->proc = proc_mkdir(drive->name, parent); - if (drive->proc) { - ide_add_proc_entries(drive->proc, generic_drive_entries, drive); - proc_create_data("settings", S_IFREG|S_IRUSR|S_IWUSR, - drive->proc, &ide_settings_proc_ops, - drive); - } - sprintf(name, "ide%d/%s", (drive->name[2]-'a')/2, drive->name); - ent = proc_symlink(drive->name, proc_ide_root, name); - if (!ent) return; - } -} - -void ide_proc_unregister_device(ide_drive_t *drive) -{ - if (drive->proc) { - remove_proc_entry("settings", drive->proc); - ide_remove_proc_entries(drive->proc, generic_drive_entries); - remove_proc_entry(drive->name, proc_ide_root); - remove_proc_entry(drive->name, drive->hwif->proc); - drive->proc = NULL; - } -} - -static ide_proc_entry_t hwif_entries[] = { - { "channel", S_IFREG|S_IRUGO, ide_channel_proc_show }, - { "mate", S_IFREG|S_IRUGO, ide_mate_proc_show }, - { "model", S_IFREG|S_IRUGO, ide_imodel_proc_show }, - {} -}; - -void ide_proc_register_port(ide_hwif_t *hwif) -{ - if (!hwif->proc) { - hwif->proc = proc_mkdir(hwif->name, proc_ide_root); - - if (!hwif->proc) - return; - - ide_add_proc_entries(hwif->proc, hwif_entries, hwif); - } -} - -void ide_proc_unregister_port(ide_hwif_t *hwif) -{ - if (hwif->proc) { - ide_remove_proc_entries(hwif->proc, hwif_entries); - remove_proc_entry(hwif->name, proc_ide_root); - hwif->proc = NULL; - } -} - -static int proc_print_driver(struct device_driver *drv, void *data) -{ - struct ide_driver *ide_drv = to_ide_driver(drv); - struct seq_file *s = data; - - seq_printf(s, "%s version %s\n", drv->name, ide_drv->version); - - return 0; -} - -static int ide_drivers_show(struct seq_file *s, void *p) -{ - int err; - - err = bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver); - if (err < 0) - printk(KERN_WARNING "IDE: %s: bus_for_each_drv error: %d\n", - __func__, err); - return 0; -} - -DEFINE_PROC_SHOW_ATTRIBUTE(ide_drivers); - -void proc_ide_create(void) -{ - proc_ide_root = proc_mkdir("ide", NULL); - - if (!proc_ide_root) - return; - - proc_create("drivers", 0, proc_ide_root, &ide_drivers_proc_ops); -} - -void proc_ide_destroy(void) -{ - remove_proc_entry("drivers", proc_ide_root); - remove_proc_entry("ide", NULL); -} diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c deleted file mode 100644 index b0411a1827a3..000000000000 --- a/drivers/ide/ide-scan-pci.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * support for probing IDE PCI devices in the PCI bus order - * - * Copyright (c) 1998-2000 Andre Hedrick - * Copyright (c) 1995-1998 Mark Lord - * - * May be copied or modified under the terms of the GNU General Public License - */ - -#include -#include -#include -#include - -/* - * Module interfaces - */ - -static int pre_init = 1; /* Before first ordered IDE scan */ -static LIST_HEAD(ide_pci_drivers); - -/* - * __ide_pci_register_driver - attach IDE driver - * @driver: pci driver - * @module: owner module of the driver - * - * Registers a driver with the IDE layer. The IDE layer arranges that - * boot time setup is done in the expected device order and then - * hands the controllers off to the core PCI code to do the rest of - * the work. - * - * Returns are the same as for pci_register_driver - */ - -int __ide_pci_register_driver(struct pci_driver *driver, struct module *module, - const char *mod_name) -{ - if (!pre_init) - return __pci_register_driver(driver, module, mod_name); - driver->driver.owner = module; - list_add_tail(&driver->node, &ide_pci_drivers); - return 0; -} -EXPORT_SYMBOL_GPL(__ide_pci_register_driver); - -/** - * ide_scan_pcidev - find an IDE driver for a device - * @dev: PCI device to check - * - * Look for an IDE driver to handle the device we are considering. - * This is only used during boot up to get the ordering correct. After - * boot up the pci layer takes over the job. - */ - -static int __init ide_scan_pcidev(struct pci_dev *dev) -{ - struct list_head *l; - struct pci_driver *d; - int ret; - - list_for_each(l, &ide_pci_drivers) { - d = list_entry(l, struct pci_driver, node); - if (d->id_table) { - const struct pci_device_id *id = - pci_match_id(d->id_table, dev); - - if (id != NULL) { - pci_assign_irq(dev); - ret = d->probe(dev, id); - if (ret >= 0) { - dev->driver = d; - pci_dev_get(dev); - return 1; - } - } - } - } - return 0; -} - -/** - * ide_scan_pcibus - perform the initial IDE driver scan - * - * Perform the initial bus rather than driver ordered scan of the - * PCI drivers. After this all IDE pci handling becomes standard - * module ordering not traditionally ordered. - */ - -static int __init ide_scan_pcibus(void) -{ - struct pci_dev *dev = NULL; - struct pci_driver *d, *tmp; - - pre_init = 0; - for_each_pci_dev(dev) - ide_scan_pcidev(dev); - - /* - * Hand the drivers over to the PCI layer now we - * are post init. - */ - - list_for_each_entry_safe(d, tmp, &ide_pci_drivers, node) { - list_del(&d->node); - if (__pci_register_driver(d, d->driver.owner, - d->driver.mod_name)) - printk(KERN_ERR "%s: failed to register %s driver\n", - __func__, d->driver.mod_name); - } - - return 0; -} -device_initcall(ide_scan_pcibus); diff --git a/drivers/ide/ide-sysfs.c b/drivers/ide/ide-sysfs.c deleted file mode 100644 index c08a8a0916e2..000000000000 --- a/drivers/ide/ide-sysfs.c +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -char *ide_media_string(ide_drive_t *drive) -{ - switch (drive->media) { - case ide_disk: - return "disk"; - case ide_cdrom: - return "cdrom"; - case ide_tape: - return "tape"; - case ide_floppy: - return "floppy"; - case ide_optical: - return "optical"; - default: - return "UNKNOWN"; - } -} - -static ssize_t media_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - ide_drive_t *drive = to_ide_device(dev); - return sprintf(buf, "%s\n", ide_media_string(drive)); -} -static DEVICE_ATTR_RO(media); - -static ssize_t drivename_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - ide_drive_t *drive = to_ide_device(dev); - return sprintf(buf, "%s\n", drive->name); -} -static DEVICE_ATTR_RO(drivename); - -static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - ide_drive_t *drive = to_ide_device(dev); - return sprintf(buf, "ide:m-%s\n", ide_media_string(drive)); -} -static DEVICE_ATTR_RO(modalias); - -static ssize_t model_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - ide_drive_t *drive = to_ide_device(dev); - return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_PROD]); -} -static DEVICE_ATTR_RO(model); - -static ssize_t firmware_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - ide_drive_t *drive = to_ide_device(dev); - return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_FW_REV]); -} -static DEVICE_ATTR_RO(firmware); - -static ssize_t serial_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - ide_drive_t *drive = to_ide_device(dev); - return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_SERNO]); -} -static DEVICE_ATTR(serial, 0400, serial_show, NULL); - -static DEVICE_ATTR(unload_heads, 0644, ide_park_show, ide_park_store); - -static struct attribute *ide_attrs[] = { - &dev_attr_media.attr, - &dev_attr_drivename.attr, - &dev_attr_modalias.attr, - &dev_attr_model.attr, - &dev_attr_firmware.attr, - &dev_attr_serial.attr, - &dev_attr_unload_heads.attr, - NULL, -}; - -static const struct attribute_group ide_attr_group = { - .attrs = ide_attrs, -}; - -const struct attribute_group *ide_dev_groups[] = { - &ide_attr_group, - NULL, -}; - -static ssize_t store_delete_devices(struct device *portdev, - struct device_attribute *attr, - const char *buf, size_t n) -{ - ide_hwif_t *hwif = dev_get_drvdata(portdev); - - if (strncmp(buf, "1", n)) - return -EINVAL; - - ide_port_unregister_devices(hwif); - - return n; -}; - -static DEVICE_ATTR(delete_devices, S_IWUSR, NULL, store_delete_devices); - -static ssize_t store_scan(struct device *portdev, - struct device_attribute *attr, - const char *buf, size_t n) -{ - ide_hwif_t *hwif = dev_get_drvdata(portdev); - - if (strncmp(buf, "1", n)) - return -EINVAL; - - ide_port_unregister_devices(hwif); - ide_port_scan(hwif); - - return n; -}; - -static DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan); - -static struct device_attribute *ide_port_attrs[] = { - &dev_attr_delete_devices, - &dev_attr_scan, - NULL -}; - -int ide_sysfs_register_port(ide_hwif_t *hwif) -{ - int i, rc; - - for (i = 0; ide_port_attrs[i]; i++) { - rc = device_create_file(hwif->portdev, ide_port_attrs[i]); - if (rc) - break; - } - - return rc; -} diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c deleted file mode 100644 index fa05e7e7d609..000000000000 --- a/drivers/ide/ide-tape.c +++ /dev/null @@ -1,2083 +0,0 @@ -/* - * IDE ATAPI streaming tape driver. - * - * Copyright (C) 1995-1999 Gadi Oxman - * Copyright (C) 2003-2005 Bartlomiej Zolnierkiewicz - * - * This driver was constructed as a student project in the software laboratory - * of the faculty of electrical engineering in the Technion - Israel's - * Institute Of Technology, with the guide of Avner Lottem and Dr. Ilana David. - * - * It is hereby placed under the terms of the GNU general public license. - * (See linux/COPYING). - * - * For a historical changelog see - * Documentation/ide/ChangeLog.ide-tape.1995-2002 - */ - -#define DRV_NAME "ide-tape" - -#define IDETAPE_VERSION "1.20" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* define to see debug info */ -#undef IDETAPE_DEBUG_LOG - -#ifdef IDETAPE_DEBUG_LOG -#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, ## args) -#else -#define ide_debug_log(lvl, fmt, args...) do {} while (0) -#endif - -/**************************** Tunable parameters *****************************/ -/* - * After each failed packet command we issue a request sense command and retry - * the packet command IDETAPE_MAX_PC_RETRIES times. - * - * Setting IDETAPE_MAX_PC_RETRIES to 0 will disable retries. - */ -#define IDETAPE_MAX_PC_RETRIES 3 - -/* - * The following parameter is used to select the point in the internal tape fifo - * in which we will start to refill the buffer. Decreasing the following - * parameter will improve the system's latency and interactive response, while - * using a high value might improve system throughput. - */ -#define IDETAPE_FIFO_THRESHOLD 2 - -/* - * DSC polling parameters. - * - * Polling for DSC (a single bit in the status register) is a very important - * function in ide-tape. There are two cases in which we poll for DSC: - * - * 1. Before a read/write packet command, to ensure that we can transfer data - * from/to the tape's data buffers, without causing an actual media access. - * In case the tape is not ready yet, we take out our request from the device - * request queue, so that ide.c could service requests from the other device - * on the same interface in the meantime. - * - * 2. After the successful initialization of a "media access packet command", - * which is a command that can take a long time to complete (the interval can - * range from several seconds to even an hour). Again, we postpone our request - * in the middle to free the bus for the other device. The polling frequency - * here should be lower than the read/write frequency since those media access - * commands are slow. We start from a "fast" frequency - IDETAPE_DSC_MA_FAST - * (1 second), and if we don't receive DSC after IDETAPE_DSC_MA_THRESHOLD - * (5 min), we switch it to a lower frequency - IDETAPE_DSC_MA_SLOW (1 min). - * - * We also set a timeout for the timer, in case something goes wrong. The - * timeout should be longer then the maximum execution time of a tape operation. - */ - -/* DSC timings. */ -#define IDETAPE_DSC_RW_MIN 5*HZ/100 /* 50 msec */ -#define IDETAPE_DSC_RW_MAX 40*HZ/100 /* 400 msec */ -#define IDETAPE_DSC_RW_TIMEOUT 2*60*HZ /* 2 minutes */ -#define IDETAPE_DSC_MA_FAST 2*HZ /* 2 seconds */ -#define IDETAPE_DSC_MA_THRESHOLD 5*60*HZ /* 5 minutes */ -#define IDETAPE_DSC_MA_SLOW 30*HZ /* 30 seconds */ -#define IDETAPE_DSC_MA_TIMEOUT 2*60*60*HZ /* 2 hours */ - -/*************************** End of tunable parameters ***********************/ - -/* tape directions */ -enum { - IDETAPE_DIR_NONE = (1 << 0), - IDETAPE_DIR_READ = (1 << 1), - IDETAPE_DIR_WRITE = (1 << 2), -}; - -/* Tape door status */ -#define DOOR_UNLOCKED 0 -#define DOOR_LOCKED 1 -#define DOOR_EXPLICITLY_LOCKED 2 - -/* Some defines for the SPACE command */ -#define IDETAPE_SPACE_OVER_FILEMARK 1 -#define IDETAPE_SPACE_TO_EOD 3 - -/* Some defines for the LOAD UNLOAD command */ -#define IDETAPE_LU_LOAD_MASK 1 -#define IDETAPE_LU_RETENSION_MASK 2 -#define IDETAPE_LU_EOT_MASK 4 - -/* Structures related to the SELECT SENSE / MODE SENSE packet commands. */ -#define IDETAPE_BLOCK_DESCRIPTOR 0 -#define IDETAPE_CAPABILITIES_PAGE 0x2a - -/* - * Most of our global data which we need to save even as we leave the driver due - * to an interrupt or a timer event is stored in the struct defined below. - */ -typedef struct ide_tape_obj { - ide_drive_t *drive; - struct ide_driver *driver; - struct gendisk *disk; - struct device dev; - - /* used by REQ_IDETAPE_{READ,WRITE} requests */ - struct ide_atapi_pc queued_pc; - - /* - * DSC polling variables. - * - * While polling for DSC we use postponed_rq to postpone the current - * request so that ide.c will be able to service pending requests on the - * other device. Note that at most we will have only one DSC (usually - * data transfer) request in the device request queue. - */ - bool postponed_rq; - - /* The time in which we started polling for DSC */ - unsigned long dsc_polling_start; - /* Timer used to poll for dsc */ - struct timer_list dsc_timer; - /* Read/Write dsc polling frequency */ - unsigned long best_dsc_rw_freq; - unsigned long dsc_poll_freq; - unsigned long dsc_timeout; - - /* Read position information */ - u8 partition; - /* Current block */ - unsigned int first_frame; - - /* Last error information */ - u8 sense_key, asc, ascq; - - /* Character device operation */ - unsigned int minor; - /* device name */ - char name[4]; - /* Current character device data transfer direction */ - u8 chrdev_dir; - - /* tape block size, usually 512 or 1024 bytes */ - unsigned short blk_size; - int user_bs_factor; - - /* Copy of the tape's Capabilities and Mechanical Page */ - u8 caps[20]; - - /* - * Active data transfer request parameters. - * - * At most, there is only one ide-tape originated data transfer request - * in the device request queue. This allows ide.c to easily service - * requests from the other device when we postpone our active request. - */ - - /* Data buffer size chosen based on the tape's recommendation */ - int buffer_size; - /* Staging buffer of buffer_size bytes */ - void *buf; - /* The read/write cursor */ - void *cur; - /* The number of valid bytes in buf */ - size_t valid; - - /* Measures average tape speed */ - unsigned long avg_time; - int avg_size; - int avg_speed; - - /* the door is currently locked */ - int door_locked; - /* the tape hardware is write protected */ - char drv_write_prot; - /* the tape is write protected (hardware or opened as read-only) */ - char write_prot; -} idetape_tape_t; - -static DEFINE_MUTEX(ide_tape_mutex); -static DEFINE_MUTEX(idetape_ref_mutex); - -static DEFINE_MUTEX(idetape_chrdev_mutex); - -static struct class *idetape_sysfs_class; - -static void ide_tape_release(struct device *); - -static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES]; - -static struct ide_tape_obj *ide_tape_get(struct gendisk *disk, bool cdev, - unsigned int i) -{ - struct ide_tape_obj *tape = NULL; - - mutex_lock(&idetape_ref_mutex); - - if (cdev) - tape = idetape_devs[i]; - else - tape = ide_drv_g(disk, ide_tape_obj); - - if (tape) { - if (ide_device_get(tape->drive)) - tape = NULL; - else - get_device(&tape->dev); - } - - mutex_unlock(&idetape_ref_mutex); - return tape; -} - -static void ide_tape_put(struct ide_tape_obj *tape) -{ - ide_drive_t *drive = tape->drive; - - mutex_lock(&idetape_ref_mutex); - put_device(&tape->dev); - ide_device_put(drive); - mutex_unlock(&idetape_ref_mutex); -} - -/* - * called on each failed packet command retry to analyze the request sense. We - * currently do not utilize this information. - */ -static void idetape_analyze_error(ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - struct ide_atapi_pc *pc = drive->failed_pc; - struct request *rq = drive->hwif->rq; - u8 *sense = bio_data(rq->bio); - - tape->sense_key = sense[2] & 0xF; - tape->asc = sense[12]; - tape->ascq = sense[13]; - - ide_debug_log(IDE_DBG_FUNC, - "cmd: 0x%x, sense key = %x, asc = %x, ascq = %x", - rq->cmd[0], tape->sense_key, tape->asc, tape->ascq); - - /* correct remaining bytes to transfer */ - if (pc->flags & PC_FLAG_DMA_ERROR) - scsi_req(rq)->resid_len = tape->blk_size * get_unaligned_be32(&sense[3]); - - /* - * If error was the result of a zero-length read or write command, - * with sense key=5, asc=0x22, ascq=0, let it slide. Some drives - * (i.e. Seagate STT3401A Travan) don't support 0-length read/writes. - */ - if ((pc->c[0] == READ_6 || pc->c[0] == WRITE_6) - /* length == 0 */ - && pc->c[4] == 0 && pc->c[3] == 0 && pc->c[2] == 0) { - if (tape->sense_key == 5) { - /* don't report an error, everything's ok */ - pc->error = 0; - /* don't retry read/write */ - pc->flags |= PC_FLAG_ABORT; - } - } - if (pc->c[0] == READ_6 && (sense[2] & 0x80)) { - pc->error = IDE_DRV_ERROR_FILEMARK; - pc->flags |= PC_FLAG_ABORT; - } - if (pc->c[0] == WRITE_6) { - if ((sense[2] & 0x40) || (tape->sense_key == 0xd - && tape->asc == 0x0 && tape->ascq == 0x2)) { - pc->error = IDE_DRV_ERROR_EOD; - pc->flags |= PC_FLAG_ABORT; - } - } - if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) { - if (tape->sense_key == 8) { - pc->error = IDE_DRV_ERROR_EOD; - pc->flags |= PC_FLAG_ABORT; - } - if (!(pc->flags & PC_FLAG_ABORT) && - (blk_rq_bytes(rq) - scsi_req(rq)->resid_len)) - pc->retries = IDETAPE_MAX_PC_RETRIES + 1; - } -} - -static void ide_tape_handle_dsc(ide_drive_t *); - -static int ide_tape_callback(ide_drive_t *drive, int dsc) -{ - idetape_tape_t *tape = drive->driver_data; - struct ide_atapi_pc *pc = drive->pc; - struct request *rq = drive->hwif->rq; - int uptodate = pc->error ? 0 : 1; - int err = uptodate ? 0 : IDE_DRV_ERROR_GENERAL; - - ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, dsc: %d, err: %d", rq->cmd[0], - dsc, err); - - if (dsc) - ide_tape_handle_dsc(drive); - - if (drive->failed_pc == pc) - drive->failed_pc = NULL; - - if (pc->c[0] == REQUEST_SENSE) { - if (uptodate) - idetape_analyze_error(drive); - else - printk(KERN_ERR "ide-tape: Error in REQUEST SENSE " - "itself - Aborting request!\n"); - } else if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) { - unsigned int blocks = - (blk_rq_bytes(rq) - scsi_req(rq)->resid_len) / tape->blk_size; - - tape->avg_size += blocks * tape->blk_size; - - if (time_after_eq(jiffies, tape->avg_time + HZ)) { - tape->avg_speed = tape->avg_size * HZ / - (jiffies - tape->avg_time) / 1024; - tape->avg_size = 0; - tape->avg_time = jiffies; - } - - tape->first_frame += blocks; - - if (pc->error) { - uptodate = 0; - err = pc->error; - } - } - scsi_req(rq)->result = err; - - return uptodate; -} - -/* - * Postpone the current request so that ide.c will be able to service requests - * from another device on the same port while we are polling for DSC. - */ -static void ide_tape_stall_queue(ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - - ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, dsc_poll_freq: %lu", - drive->hwif->rq->cmd[0], tape->dsc_poll_freq); - - tape->postponed_rq = true; - - ide_stall_queue(drive, tape->dsc_poll_freq); -} - -static void ide_tape_handle_dsc(ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - - /* Media access command */ - tape->dsc_polling_start = jiffies; - tape->dsc_poll_freq = IDETAPE_DSC_MA_FAST; - tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT; - /* Allow ide.c to handle other requests */ - ide_tape_stall_queue(drive); -} - -/* - * Packet Command Interface - * - * The current Packet Command is available in drive->pc, and will not change - * until we finish handling it. Each packet command is associated with a - * callback function that will be called when the command is finished. - * - * The handling will be done in three stages: - * - * 1. ide_tape_issue_pc will send the packet command to the drive, and will set - * the interrupt handler to ide_pc_intr. - * - * 2. On each interrupt, ide_pc_intr will be called. This step will be - * repeated until the device signals us that no more interrupts will be issued. - * - * 3. ATAPI Tape media access commands have immediate status with a delayed - * process. In case of a successful initiation of a media access packet command, - * the DSC bit will be set when the actual execution of the command is finished. - * Since the tape drive will not issue an interrupt, we have to poll for this - * event. In this case, we define the request as "low priority request" by - * setting rq_status to IDETAPE_RQ_POSTPONED, set a timer to poll for DSC and - * exit the driver. - * - * ide.c will then give higher priority to requests which originate from the - * other device, until will change rq_status to RQ_ACTIVE. - * - * 4. When the packet command is finished, it will be checked for errors. - * - * 5. In case an error was found, we queue a request sense packet command in - * front of the request queue and retry the operation up to - * IDETAPE_MAX_PC_RETRIES times. - * - * 6. In case no error was found, or we decided to give up and not to retry - * again, the callback function will be called and then we will handle the next - * request. - */ - -static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive, - struct ide_cmd *cmd, - struct ide_atapi_pc *pc) -{ - idetape_tape_t *tape = drive->driver_data; - struct request *rq = drive->hwif->rq; - - if (drive->failed_pc == NULL && pc->c[0] != REQUEST_SENSE) - drive->failed_pc = pc; - - /* Set the current packet command */ - drive->pc = pc; - - if (pc->retries > IDETAPE_MAX_PC_RETRIES || - (pc->flags & PC_FLAG_ABORT)) { - - /* - * We will "abort" retrying a packet command in case legitimate - * error code was received (crossing a filemark, or end of the - * media, for example). - */ - if (!(pc->flags & PC_FLAG_ABORT)) { - if (!(pc->c[0] == TEST_UNIT_READY && - tape->sense_key == 2 && tape->asc == 4 && - (tape->ascq == 1 || tape->ascq == 8))) { - printk(KERN_ERR "ide-tape: %s: I/O error, " - "pc = %2x, key = %2x, " - "asc = %2x, ascq = %2x\n", - tape->name, pc->c[0], - tape->sense_key, tape->asc, - tape->ascq); - } - /* Giving up */ - pc->error = IDE_DRV_ERROR_GENERAL; - } - - drive->failed_pc = NULL; - drive->pc_callback(drive, 0); - ide_complete_rq(drive, BLK_STS_IOERR, blk_rq_bytes(rq)); - return ide_stopped; - } - ide_debug_log(IDE_DBG_SENSE, "retry #%d, cmd: 0x%02x", pc->retries, - pc->c[0]); - - pc->retries++; - - return ide_issue_pc(drive, cmd); -} - -/* A mode sense command is used to "sense" tape parameters. */ -static void idetape_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code) -{ - ide_init_pc(pc); - pc->c[0] = MODE_SENSE; - if (page_code != IDETAPE_BLOCK_DESCRIPTOR) - /* DBD = 1 - Don't return block descriptors */ - pc->c[1] = 8; - pc->c[2] = page_code; - /* - * Changed pc->c[3] to 0 (255 will at best return unused info). - * - * For SCSI this byte is defined as subpage instead of high byte - * of length and some IDE drives seem to interpret it this way - * and return an error when 255 is used. - */ - pc->c[3] = 0; - /* We will just discard data in that case */ - pc->c[4] = 255; - if (page_code == IDETAPE_BLOCK_DESCRIPTOR) - pc->req_xfer = 12; - else if (page_code == IDETAPE_CAPABILITIES_PAGE) - pc->req_xfer = 24; - else - pc->req_xfer = 50; -} - -static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - idetape_tape_t *tape = drive->driver_data; - struct ide_atapi_pc *pc = drive->pc; - u8 stat; - - stat = hwif->tp_ops->read_status(hwif); - - if (stat & ATA_DSC) { - if (stat & ATA_ERR) { - /* Error detected */ - if (pc->c[0] != TEST_UNIT_READY) - printk(KERN_ERR "ide-tape: %s: I/O error, ", - tape->name); - /* Retry operation */ - ide_retry_pc(drive); - return ide_stopped; - } - pc->error = 0; - } else { - pc->error = IDE_DRV_ERROR_GENERAL; - drive->failed_pc = NULL; - } - drive->pc_callback(drive, 0); - return ide_stopped; -} - -static void ide_tape_create_rw_cmd(idetape_tape_t *tape, - struct ide_atapi_pc *pc, struct request *rq, - u8 opcode) -{ - unsigned int length = blk_rq_sectors(rq) / (tape->blk_size >> 9); - - ide_init_pc(pc); - put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]); - pc->c[1] = 1; - - if (blk_rq_bytes(rq) == tape->buffer_size) - pc->flags |= PC_FLAG_DMA_OK; - - if (opcode == READ_6) - pc->c[0] = READ_6; - else if (opcode == WRITE_6) { - pc->c[0] = WRITE_6; - pc->flags |= PC_FLAG_WRITING; - } - - memcpy(scsi_req(rq)->cmd, pc->c, 12); -} - -static ide_startstop_t idetape_do_request(ide_drive_t *drive, - struct request *rq, sector_t block) -{ - ide_hwif_t *hwif = drive->hwif; - idetape_tape_t *tape = drive->driver_data; - struct ide_atapi_pc *pc = NULL; - struct ide_cmd cmd; - struct scsi_request *req = scsi_req(rq); - u8 stat; - - ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, sector: %llu, nr_sectors: %u", - req->cmd[0], (unsigned long long)blk_rq_pos(rq), - blk_rq_sectors(rq)); - - BUG_ON(!blk_rq_is_private(rq)); - BUG_ON(ide_req(rq)->type != ATA_PRIV_MISC && - ide_req(rq)->type != ATA_PRIV_SENSE); - - /* Retry a failed packet command */ - if (drive->failed_pc && drive->pc->c[0] == REQUEST_SENSE) { - pc = drive->failed_pc; - goto out; - } - - /* - * If the tape is still busy, postpone our request and service - * the other device meanwhile. - */ - stat = hwif->tp_ops->read_status(hwif); - - if ((drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) == 0 && - (req->cmd[13] & REQ_IDETAPE_PC2) == 0) - drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC; - - if (drive->dev_flags & IDE_DFLAG_POST_RESET) { - drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC; - drive->dev_flags &= ~IDE_DFLAG_POST_RESET; - } - - if (!(drive->atapi_flags & IDE_AFLAG_IGNORE_DSC) && - !(stat & ATA_DSC)) { - if (!tape->postponed_rq) { - tape->dsc_polling_start = jiffies; - tape->dsc_poll_freq = tape->best_dsc_rw_freq; - tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT; - } else if (time_after(jiffies, tape->dsc_timeout)) { - printk(KERN_ERR "ide-tape: %s: DSC timeout\n", - tape->name); - if (req->cmd[13] & REQ_IDETAPE_PC2) { - idetape_media_access_finished(drive); - return ide_stopped; - } else { - return ide_do_reset(drive); - } - } else if (time_after(jiffies, - tape->dsc_polling_start + - IDETAPE_DSC_MA_THRESHOLD)) - tape->dsc_poll_freq = IDETAPE_DSC_MA_SLOW; - ide_tape_stall_queue(drive); - return ide_stopped; - } else { - drive->atapi_flags &= ~IDE_AFLAG_IGNORE_DSC; - tape->postponed_rq = false; - } - - if (req->cmd[13] & REQ_IDETAPE_READ) { - pc = &tape->queued_pc; - ide_tape_create_rw_cmd(tape, pc, rq, READ_6); - goto out; - } - if (req->cmd[13] & REQ_IDETAPE_WRITE) { - pc = &tape->queued_pc; - ide_tape_create_rw_cmd(tape, pc, rq, WRITE_6); - goto out; - } - if (req->cmd[13] & REQ_IDETAPE_PC1) { - pc = (struct ide_atapi_pc *)ide_req(rq)->special; - req->cmd[13] &= ~(REQ_IDETAPE_PC1); - req->cmd[13] |= REQ_IDETAPE_PC2; - goto out; - } - if (req->cmd[13] & REQ_IDETAPE_PC2) { - idetape_media_access_finished(drive); - return ide_stopped; - } - BUG(); - -out: - /* prepare sense request for this command */ - ide_prep_sense(drive, rq); - - memset(&cmd, 0, sizeof(cmd)); - - if (rq_data_dir(rq)) - cmd.tf_flags |= IDE_TFLAG_WRITE; - - cmd.rq = rq; - - ide_init_sg_cmd(&cmd, blk_rq_bytes(rq)); - ide_map_sg(drive, &cmd); - - return ide_tape_issue_pc(drive, &cmd, pc); -} - -/* - * Write a filemark if write_filemark=1. Flush the device buffers without - * writing a filemark otherwise. - */ -static void idetape_create_write_filemark_cmd(ide_drive_t *drive, - struct ide_atapi_pc *pc, int write_filemark) -{ - ide_init_pc(pc); - pc->c[0] = WRITE_FILEMARKS; - pc->c[4] = write_filemark; - pc->flags |= PC_FLAG_WAIT_FOR_DSC; -} - -static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout) -{ - idetape_tape_t *tape = drive->driver_data; - struct gendisk *disk = tape->disk; - int load_attempted = 0; - - /* Wait for the tape to become ready */ - set_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), &drive->atapi_flags); - timeout += jiffies; - while (time_before(jiffies, timeout)) { - if (ide_do_test_unit_ready(drive, disk) == 0) - return 0; - if ((tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2) - || (tape->asc == 0x3A)) { - /* no media */ - if (load_attempted) - return -ENOMEDIUM; - ide_do_start_stop(drive, disk, IDETAPE_LU_LOAD_MASK); - load_attempted = 1; - /* not about to be ready */ - } else if (!(tape->sense_key == 2 && tape->asc == 4 && - (tape->ascq == 1 || tape->ascq == 8))) - return -EIO; - msleep(100); - } - return -EIO; -} - -static int idetape_flush_tape_buffers(ide_drive_t *drive) -{ - struct ide_tape_obj *tape = drive->driver_data; - struct ide_atapi_pc pc; - int rc; - - idetape_create_write_filemark_cmd(drive, &pc, 0); - rc = ide_queue_pc_tail(drive, tape->disk, &pc, NULL, 0); - if (rc) - return rc; - idetape_wait_ready(drive, 60 * 5 * HZ); - return 0; -} - -static int ide_tape_read_position(ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - struct ide_atapi_pc pc; - u8 buf[20]; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - /* prep cmd */ - ide_init_pc(&pc); - pc.c[0] = READ_POSITION; - pc.req_xfer = 20; - - if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) - return -1; - - if (!pc.error) { - ide_debug_log(IDE_DBG_FUNC, "BOP - %s", - (buf[0] & 0x80) ? "Yes" : "No"); - ide_debug_log(IDE_DBG_FUNC, "EOP - %s", - (buf[0] & 0x40) ? "Yes" : "No"); - - if (buf[0] & 0x4) { - printk(KERN_INFO "ide-tape: Block location is unknown" - "to the tape\n"); - clear_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), - &drive->atapi_flags); - return -1; - } else { - ide_debug_log(IDE_DBG_FUNC, "Block Location: %u", - be32_to_cpup((__be32 *)&buf[4])); - - tape->partition = buf[1]; - tape->first_frame = be32_to_cpup((__be32 *)&buf[4]); - set_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), - &drive->atapi_flags); - } - } - - return tape->first_frame; -} - -static void idetape_create_locate_cmd(ide_drive_t *drive, - struct ide_atapi_pc *pc, - unsigned int block, u8 partition, int skip) -{ - ide_init_pc(pc); - pc->c[0] = POSITION_TO_ELEMENT; - pc->c[1] = 2; - put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[3]); - pc->c[8] = partition; - pc->flags |= PC_FLAG_WAIT_FOR_DSC; -} - -static void __ide_tape_discard_merge_buffer(ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - - if (tape->chrdev_dir != IDETAPE_DIR_READ) - return; - - clear_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags); - tape->valid = 0; - if (tape->buf != NULL) { - kfree(tape->buf); - tape->buf = NULL; - } - - tape->chrdev_dir = IDETAPE_DIR_NONE; -} - -/* - * Position the tape to the requested block using the LOCATE packet command. - * A READ POSITION command is then issued to check where we are positioned. Like - * all higher level operations, we queue the commands at the tail of the request - * queue and wait for their completion. - */ -static int idetape_position_tape(ide_drive_t *drive, unsigned int block, - u8 partition, int skip) -{ - idetape_tape_t *tape = drive->driver_data; - struct gendisk *disk = tape->disk; - int ret; - struct ide_atapi_pc pc; - - if (tape->chrdev_dir == IDETAPE_DIR_READ) - __ide_tape_discard_merge_buffer(drive); - idetape_wait_ready(drive, 60 * 5 * HZ); - idetape_create_locate_cmd(drive, &pc, block, partition, skip); - ret = ide_queue_pc_tail(drive, disk, &pc, NULL, 0); - if (ret) - return ret; - - ret = ide_tape_read_position(drive); - if (ret < 0) - return ret; - return 0; -} - -static void ide_tape_discard_merge_buffer(ide_drive_t *drive, - int restore_position) -{ - idetape_tape_t *tape = drive->driver_data; - int seek, position; - - __ide_tape_discard_merge_buffer(drive); - if (restore_position) { - position = ide_tape_read_position(drive); - seek = position > 0 ? position : 0; - if (idetape_position_tape(drive, seek, 0, 0)) { - printk(KERN_INFO "ide-tape: %s: position_tape failed in" - " %s\n", tape->name, __func__); - return; - } - } -} - -/* - * Generate a read/write request for the block device interface and wait for it - * to be serviced. - */ -static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size) -{ - idetape_tape_t *tape = drive->driver_data; - struct request *rq; - int ret; - - ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, size: %d", cmd, size); - - BUG_ON(cmd != REQ_IDETAPE_READ && cmd != REQ_IDETAPE_WRITE); - BUG_ON(size < 0 || size % tape->blk_size); - - rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); - ide_req(rq)->type = ATA_PRIV_MISC; - scsi_req(rq)->cmd[13] = cmd; - rq->rq_disk = tape->disk; - rq->__sector = tape->first_frame; - - if (size) { - ret = blk_rq_map_kern(drive->queue, rq, tape->buf, size, - GFP_NOIO); - if (ret) - goto out_put; - } - - blk_execute_rq(tape->disk, rq, 0); - - /* calculate the number of transferred bytes and update buffer state */ - size -= scsi_req(rq)->resid_len; - tape->cur = tape->buf; - if (cmd == REQ_IDETAPE_READ) - tape->valid = size; - else - tape->valid = 0; - - ret = size; - if (scsi_req(rq)->result == IDE_DRV_ERROR_GENERAL) - ret = -EIO; -out_put: - blk_put_request(rq); - return ret; -} - -static void idetape_create_inquiry_cmd(struct ide_atapi_pc *pc) -{ - ide_init_pc(pc); - pc->c[0] = INQUIRY; - pc->c[4] = 254; - pc->req_xfer = 254; -} - -static void idetape_create_rewind_cmd(ide_drive_t *drive, - struct ide_atapi_pc *pc) -{ - ide_init_pc(pc); - pc->c[0] = REZERO_UNIT; - pc->flags |= PC_FLAG_WAIT_FOR_DSC; -} - -static void idetape_create_erase_cmd(struct ide_atapi_pc *pc) -{ - ide_init_pc(pc); - pc->c[0] = ERASE; - pc->c[1] = 1; - pc->flags |= PC_FLAG_WAIT_FOR_DSC; -} - -static void idetape_create_space_cmd(struct ide_atapi_pc *pc, int count, u8 cmd) -{ - ide_init_pc(pc); - pc->c[0] = SPACE; - put_unaligned(cpu_to_be32(count), (unsigned int *) &pc->c[1]); - pc->c[1] = cmd; - pc->flags |= PC_FLAG_WAIT_FOR_DSC; -} - -static void ide_tape_flush_merge_buffer(ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - - if (tape->chrdev_dir != IDETAPE_DIR_WRITE) { - printk(KERN_ERR "ide-tape: bug: Trying to empty merge buffer" - " but we are not writing.\n"); - return; - } - if (tape->buf) { - size_t aligned = roundup(tape->valid, tape->blk_size); - - memset(tape->cur, 0, aligned - tape->valid); - idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, aligned); - kfree(tape->buf); - tape->buf = NULL; - } - tape->chrdev_dir = IDETAPE_DIR_NONE; -} - -static int idetape_init_rw(ide_drive_t *drive, int dir) -{ - idetape_tape_t *tape = drive->driver_data; - int rc; - - BUG_ON(dir != IDETAPE_DIR_READ && dir != IDETAPE_DIR_WRITE); - - if (tape->chrdev_dir == dir) - return 0; - - if (tape->chrdev_dir == IDETAPE_DIR_READ) - ide_tape_discard_merge_buffer(drive, 1); - else if (tape->chrdev_dir == IDETAPE_DIR_WRITE) { - ide_tape_flush_merge_buffer(drive); - idetape_flush_tape_buffers(drive); - } - - if (tape->buf || tape->valid) { - printk(KERN_ERR "ide-tape: valid should be 0 now\n"); - tape->valid = 0; - } - - tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL); - if (!tape->buf) - return -ENOMEM; - tape->chrdev_dir = dir; - tape->cur = tape->buf; - - /* - * Issue a 0 rw command to ensure that DSC handshake is - * switched from completion mode to buffer available mode. No - * point in issuing this if DSC overlap isn't supported, some - * drives (Seagate STT3401A) will return an error. - */ - if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) { - int cmd = dir == IDETAPE_DIR_READ ? REQ_IDETAPE_READ - : REQ_IDETAPE_WRITE; - - rc = idetape_queue_rw_tail(drive, cmd, 0); - if (rc < 0) { - kfree(tape->buf); - tape->buf = NULL; - tape->chrdev_dir = IDETAPE_DIR_NONE; - return rc; - } - } - - return 0; -} - -static void idetape_pad_zeros(ide_drive_t *drive, int bcount) -{ - idetape_tape_t *tape = drive->driver_data; - - memset(tape->buf, 0, tape->buffer_size); - - while (bcount) { - unsigned int count = min(tape->buffer_size, bcount); - - idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, count); - bcount -= count; - } -} - -/* - * Rewinds the tape to the Beginning Of the current Partition (BOP). We - * currently support only one partition. - */ -static int idetape_rewind_tape(ide_drive_t *drive) -{ - struct ide_tape_obj *tape = drive->driver_data; - struct gendisk *disk = tape->disk; - struct ide_atapi_pc pc; - int ret; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - idetape_create_rewind_cmd(drive, &pc); - ret = ide_queue_pc_tail(drive, disk, &pc, NULL, 0); - if (ret) - return ret; - - ret = ide_tape_read_position(drive); - if (ret < 0) - return ret; - return 0; -} - -/* mtio.h compatible commands should be issued to the chrdev interface. */ -static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, - unsigned long arg) -{ - idetape_tape_t *tape = drive->driver_data; - void __user *argp = (void __user *)arg; - - struct idetape_config { - int dsc_rw_frequency; - int dsc_media_access_frequency; - int nr_stages; - } config; - - ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%04x", cmd); - - switch (cmd) { - case 0x0340: - if (copy_from_user(&config, argp, sizeof(config))) - return -EFAULT; - tape->best_dsc_rw_freq = config.dsc_rw_frequency; - break; - case 0x0350: - memset(&config, 0, sizeof(config)); - config.dsc_rw_frequency = (int) tape->best_dsc_rw_freq; - config.nr_stages = 1; - if (copy_to_user(argp, &config, sizeof(config))) - return -EFAULT; - break; - default: - return -EIO; - } - return 0; -} - -static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op, - int mt_count) -{ - idetape_tape_t *tape = drive->driver_data; - struct gendisk *disk = tape->disk; - struct ide_atapi_pc pc; - int retval, count = 0; - int sprev = !!(tape->caps[4] & 0x20); - - - ide_debug_log(IDE_DBG_FUNC, "mt_op: %d, mt_count: %d", mt_op, mt_count); - - if (mt_count == 0) - return 0; - if (MTBSF == mt_op || MTBSFM == mt_op) { - if (!sprev) - return -EIO; - mt_count = -mt_count; - } - - if (tape->chrdev_dir == IDETAPE_DIR_READ) { - tape->valid = 0; - if (test_and_clear_bit(ilog2(IDE_AFLAG_FILEMARK), - &drive->atapi_flags)) - ++count; - ide_tape_discard_merge_buffer(drive, 0); - } - - switch (mt_op) { - case MTFSF: - case MTBSF: - idetape_create_space_cmd(&pc, mt_count - count, - IDETAPE_SPACE_OVER_FILEMARK); - return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); - case MTFSFM: - case MTBSFM: - if (!sprev) - return -EIO; - retval = idetape_space_over_filemarks(drive, MTFSF, - mt_count - count); - if (retval) - return retval; - count = (MTBSFM == mt_op ? 1 : -1); - return idetape_space_over_filemarks(drive, MTFSF, count); - default: - printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n", - mt_op); - return -EIO; - } -} - -/* - * Our character device read / write functions. - * - * The tape is optimized to maximize throughput when it is transferring an - * integral number of the "continuous transfer limit", which is a parameter of - * the specific tape (26kB on my particular tape, 32kB for Onstream). - * - * As of version 1.3 of the driver, the character device provides an abstract - * continuous view of the media - any mix of block sizes (even 1 byte) on the - * same backup/restore procedure is supported. The driver will internally - * convert the requests to the recommended transfer unit, so that an unmatch - * between the user's block size to the recommended size will only result in a - * (slightly) increased driver overhead, but will no longer hit performance. - * This is not applicable to Onstream. - */ -static ssize_t idetape_chrdev_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct ide_tape_obj *tape = file->private_data; - ide_drive_t *drive = tape->drive; - size_t done = 0; - ssize_t ret = 0; - int rc; - - ide_debug_log(IDE_DBG_FUNC, "count %zd", count); - - if (tape->chrdev_dir != IDETAPE_DIR_READ) { - if (test_bit(ilog2(IDE_AFLAG_DETECT_BS), &drive->atapi_flags)) - if (count > tape->blk_size && - (count % tape->blk_size) == 0) - tape->user_bs_factor = count / tape->blk_size; - } - - rc = idetape_init_rw(drive, IDETAPE_DIR_READ); - if (rc < 0) - return rc; - - while (done < count) { - size_t todo; - - /* refill if staging buffer is empty */ - if (!tape->valid) { - /* If we are at a filemark, nothing more to read */ - if (test_bit(ilog2(IDE_AFLAG_FILEMARK), - &drive->atapi_flags)) - break; - /* read */ - if (idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, - tape->buffer_size) <= 0) - break; - } - - /* copy out */ - todo = min_t(size_t, count - done, tape->valid); - if (copy_to_user(buf + done, tape->cur, todo)) - ret = -EFAULT; - - tape->cur += todo; - tape->valid -= todo; - done += todo; - } - - if (!done && test_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags)) { - idetape_space_over_filemarks(drive, MTFSF, 1); - return 0; - } - - return ret ? ret : done; -} - -static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct ide_tape_obj *tape = file->private_data; - ide_drive_t *drive = tape->drive; - size_t done = 0; - ssize_t ret = 0; - int rc; - - /* The drive is write protected. */ - if (tape->write_prot) - return -EACCES; - - ide_debug_log(IDE_DBG_FUNC, "count %zd", count); - - /* Initialize write operation */ - rc = idetape_init_rw(drive, IDETAPE_DIR_WRITE); - if (rc < 0) - return rc; - - while (done < count) { - size_t todo; - - /* flush if staging buffer is full */ - if (tape->valid == tape->buffer_size && - idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, - tape->buffer_size) <= 0) - return rc; - - /* copy in */ - todo = min_t(size_t, count - done, - tape->buffer_size - tape->valid); - if (copy_from_user(tape->cur, buf + done, todo)) - ret = -EFAULT; - - tape->cur += todo; - tape->valid += todo; - done += todo; - } - - return ret ? ret : done; -} - -static int idetape_write_filemark(ide_drive_t *drive) -{ - struct ide_tape_obj *tape = drive->driver_data; - struct ide_atapi_pc pc; - - /* Write a filemark */ - idetape_create_write_filemark_cmd(drive, &pc, 1); - if (ide_queue_pc_tail(drive, tape->disk, &pc, NULL, 0)) { - printk(KERN_ERR "ide-tape: Couldn't write a filemark\n"); - return -EIO; - } - return 0; -} - -/* - * Called from idetape_chrdev_ioctl when the general mtio MTIOCTOP ioctl is - * requested. - * - * Note: MTBSF and MTBSFM are not supported when the tape doesn't support - * spacing over filemarks in the reverse direction. In this case, MTFSFM is also - * usually not supported. - * - * The following commands are currently not supported: - * - * MTFSS, MTBSS, MTWSM, MTSETDENSITY, MTSETDRVBUFFER, MT_ST_BOOLEANS, - * MT_ST_WRITE_THRESHOLD. - */ -static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count) -{ - idetape_tape_t *tape = drive->driver_data; - struct gendisk *disk = tape->disk; - struct ide_atapi_pc pc; - int i, retval; - - ide_debug_log(IDE_DBG_FUNC, "MTIOCTOP ioctl: mt_op: %d, mt_count: %d", - mt_op, mt_count); - - switch (mt_op) { - case MTFSF: - case MTFSFM: - case MTBSF: - case MTBSFM: - if (!mt_count) - return 0; - return idetape_space_over_filemarks(drive, mt_op, mt_count); - default: - break; - } - - switch (mt_op) { - case MTWEOF: - if (tape->write_prot) - return -EACCES; - ide_tape_discard_merge_buffer(drive, 1); - for (i = 0; i < mt_count; i++) { - retval = idetape_write_filemark(drive); - if (retval) - return retval; - } - return 0; - case MTREW: - ide_tape_discard_merge_buffer(drive, 0); - if (idetape_rewind_tape(drive)) - return -EIO; - return 0; - case MTLOAD: - ide_tape_discard_merge_buffer(drive, 0); - return ide_do_start_stop(drive, disk, IDETAPE_LU_LOAD_MASK); - case MTUNLOAD: - case MTOFFL: - /* - * If door is locked, attempt to unlock before - * attempting to eject. - */ - if (tape->door_locked) { - if (!ide_set_media_lock(drive, disk, 0)) - tape->door_locked = DOOR_UNLOCKED; - } - ide_tape_discard_merge_buffer(drive, 0); - retval = ide_do_start_stop(drive, disk, !IDETAPE_LU_LOAD_MASK); - if (!retval) - clear_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), - &drive->atapi_flags); - return retval; - case MTNOP: - ide_tape_discard_merge_buffer(drive, 0); - return idetape_flush_tape_buffers(drive); - case MTRETEN: - ide_tape_discard_merge_buffer(drive, 0); - return ide_do_start_stop(drive, disk, - IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK); - case MTEOM: - idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD); - return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); - case MTERASE: - (void)idetape_rewind_tape(drive); - idetape_create_erase_cmd(&pc); - return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); - case MTSETBLK: - if (mt_count) { - if (mt_count < tape->blk_size || - mt_count % tape->blk_size) - return -EIO; - tape->user_bs_factor = mt_count / tape->blk_size; - clear_bit(ilog2(IDE_AFLAG_DETECT_BS), - &drive->atapi_flags); - } else - set_bit(ilog2(IDE_AFLAG_DETECT_BS), - &drive->atapi_flags); - return 0; - case MTSEEK: - ide_tape_discard_merge_buffer(drive, 0); - return idetape_position_tape(drive, - mt_count * tape->user_bs_factor, tape->partition, 0); - case MTSETPART: - ide_tape_discard_merge_buffer(drive, 0); - return idetape_position_tape(drive, 0, mt_count, 0); - case MTFSR: - case MTBSR: - case MTLOCK: - retval = ide_set_media_lock(drive, disk, 1); - if (retval) - return retval; - tape->door_locked = DOOR_EXPLICITLY_LOCKED; - return 0; - case MTUNLOCK: - retval = ide_set_media_lock(drive, disk, 0); - if (retval) - return retval; - tape->door_locked = DOOR_UNLOCKED; - return 0; - default: - printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n", - mt_op); - return -EIO; - } -} - -/* - * Our character device ioctls. General mtio.h magnetic io commands are - * supported here, and not in the corresponding block interface. Our own - * ide-tape ioctls are supported on both interfaces. - */ -static long do_idetape_chrdev_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct ide_tape_obj *tape = file->private_data; - ide_drive_t *drive = tape->drive; - struct mtop mtop; - struct mtget mtget; - struct mtpos mtpos; - int block_offset = 0, position = tape->first_frame; - void __user *argp = (void __user *)arg; - - ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x", cmd); - - if (tape->chrdev_dir == IDETAPE_DIR_WRITE) { - ide_tape_flush_merge_buffer(drive); - idetape_flush_tape_buffers(drive); - } - if (cmd == MTIOCGET || cmd == MTIOCPOS) { - block_offset = tape->valid / - (tape->blk_size * tape->user_bs_factor); - position = ide_tape_read_position(drive); - if (position < 0) - return -EIO; - } - switch (cmd) { - case MTIOCTOP: - if (copy_from_user(&mtop, argp, sizeof(struct mtop))) - return -EFAULT; - return idetape_mtioctop(drive, mtop.mt_op, mtop.mt_count); - case MTIOCGET: - memset(&mtget, 0, sizeof(struct mtget)); - mtget.mt_type = MT_ISSCSI2; - mtget.mt_blkno = position / tape->user_bs_factor - block_offset; - mtget.mt_dsreg = - ((tape->blk_size * tape->user_bs_factor) - << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK; - - if (tape->drv_write_prot) - mtget.mt_gstat |= GMT_WR_PROT(0xffffffff); - - return put_user_mtget(argp, &mtget); - case MTIOCPOS: - mtpos.mt_blkno = position / tape->user_bs_factor - block_offset; - return put_user_mtpos(argp, &mtpos); - default: - if (tape->chrdev_dir == IDETAPE_DIR_READ) - ide_tape_discard_merge_buffer(drive, 1); - return idetape_blkdev_ioctl(drive, cmd, arg); - } -} - -static long idetape_chrdev_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - long ret; - mutex_lock(&ide_tape_mutex); - ret = do_idetape_chrdev_ioctl(file, cmd, arg); - mutex_unlock(&ide_tape_mutex); - return ret; -} - -static long idetape_chrdev_compat_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - long ret; - - if (cmd == MTIOCPOS32) - cmd = MTIOCPOS; - else if (cmd == MTIOCGET32) - cmd = MTIOCGET; - - mutex_lock(&ide_tape_mutex); - ret = do_idetape_chrdev_ioctl(file, cmd, arg); - mutex_unlock(&ide_tape_mutex); - return ret; -} - -/* - * Do a mode sense page 0 with block descriptor and if it succeeds set the tape - * block size with the reported value. - */ -static void ide_tape_get_bsize_from_bdesc(ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - struct ide_atapi_pc pc; - u8 buf[12]; - - idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR); - if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) { - printk(KERN_ERR "ide-tape: Can't get block descriptor\n"); - if (tape->blk_size == 0) { - printk(KERN_WARNING "ide-tape: Cannot deal with zero " - "block size, assuming 32k\n"); - tape->blk_size = 32768; - } - return; - } - tape->blk_size = (buf[4 + 5] << 16) + - (buf[4 + 6] << 8) + - buf[4 + 7]; - tape->drv_write_prot = (buf[2] & 0x80) >> 7; - - ide_debug_log(IDE_DBG_FUNC, "blk_size: %d, write_prot: %d", - tape->blk_size, tape->drv_write_prot); -} - -static int idetape_chrdev_open(struct inode *inode, struct file *filp) -{ - unsigned int minor = iminor(inode), i = minor & ~0xc0; - ide_drive_t *drive; - idetape_tape_t *tape; - int retval; - - if (i >= MAX_HWIFS * MAX_DRIVES) - return -ENXIO; - - mutex_lock(&idetape_chrdev_mutex); - - tape = ide_tape_get(NULL, true, i); - if (!tape) { - mutex_unlock(&idetape_chrdev_mutex); - return -ENXIO; - } - - drive = tape->drive; - filp->private_data = tape; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - /* - * We really want to do nonseekable_open(inode, filp); here, but some - * versions of tar incorrectly call lseek on tapes and bail out if that - * fails. So we disallow pread() and pwrite(), but permit lseeks. - */ - filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); - - - if (test_and_set_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags)) { - retval = -EBUSY; - goto out_put_tape; - } - - retval = idetape_wait_ready(drive, 60 * HZ); - if (retval) { - clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags); - printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name); - goto out_put_tape; - } - - ide_tape_read_position(drive); - if (!test_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), &drive->atapi_flags)) - (void)idetape_rewind_tape(drive); - - /* Read block size and write protect status from drive. */ - ide_tape_get_bsize_from_bdesc(drive); - - /* Set write protect flag if device is opened as read-only. */ - if ((filp->f_flags & O_ACCMODE) == O_RDONLY) - tape->write_prot = 1; - else - tape->write_prot = tape->drv_write_prot; - - /* Make sure drive isn't write protected if user wants to write. */ - if (tape->write_prot) { - if ((filp->f_flags & O_ACCMODE) == O_WRONLY || - (filp->f_flags & O_ACCMODE) == O_RDWR) { - clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags); - retval = -EROFS; - goto out_put_tape; - } - } - - /* Lock the tape drive door so user can't eject. */ - if (tape->chrdev_dir == IDETAPE_DIR_NONE) { - if (!ide_set_media_lock(drive, tape->disk, 1)) { - if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) - tape->door_locked = DOOR_LOCKED; - } - } - mutex_unlock(&idetape_chrdev_mutex); - - return 0; - -out_put_tape: - ide_tape_put(tape); - - mutex_unlock(&idetape_chrdev_mutex); - - return retval; -} - -static void idetape_write_release(ide_drive_t *drive, unsigned int minor) -{ - idetape_tape_t *tape = drive->driver_data; - - ide_tape_flush_merge_buffer(drive); - tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL); - if (tape->buf != NULL) { - idetape_pad_zeros(drive, tape->blk_size * - (tape->user_bs_factor - 1)); - kfree(tape->buf); - tape->buf = NULL; - } - idetape_write_filemark(drive); - idetape_flush_tape_buffers(drive); - idetape_flush_tape_buffers(drive); -} - -static int idetape_chrdev_release(struct inode *inode, struct file *filp) -{ - struct ide_tape_obj *tape = filp->private_data; - ide_drive_t *drive = tape->drive; - unsigned int minor = iminor(inode); - - mutex_lock(&idetape_chrdev_mutex); - - tape = drive->driver_data; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - if (tape->chrdev_dir == IDETAPE_DIR_WRITE) - idetape_write_release(drive, minor); - if (tape->chrdev_dir == IDETAPE_DIR_READ) { - if (minor < 128) - ide_tape_discard_merge_buffer(drive, 1); - } - - if (minor < 128 && test_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), - &drive->atapi_flags)) - (void) idetape_rewind_tape(drive); - - if (tape->chrdev_dir == IDETAPE_DIR_NONE) { - if (tape->door_locked == DOOR_LOCKED) { - if (!ide_set_media_lock(drive, tape->disk, 0)) - tape->door_locked = DOOR_UNLOCKED; - } - } - clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags); - ide_tape_put(tape); - - mutex_unlock(&idetape_chrdev_mutex); - - return 0; -} - -static void idetape_get_inquiry_results(ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - struct ide_atapi_pc pc; - u8 pc_buf[256]; - char fw_rev[4], vendor_id[8], product_id[16]; - - idetape_create_inquiry_cmd(&pc); - if (ide_queue_pc_tail(drive, tape->disk, &pc, pc_buf, pc.req_xfer)) { - printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", - tape->name); - return; - } - memcpy(vendor_id, &pc_buf[8], 8); - memcpy(product_id, &pc_buf[16], 16); - memcpy(fw_rev, &pc_buf[32], 4); - - ide_fixstring(vendor_id, 8, 0); - ide_fixstring(product_id, 16, 0); - ide_fixstring(fw_rev, 4, 0); - - printk(KERN_INFO "ide-tape: %s <-> %s: %.8s %.16s rev %.4s\n", - drive->name, tape->name, vendor_id, product_id, fw_rev); -} - -/* - * Ask the tape about its various parameters. In particular, we will adjust our - * data transfer buffer size to the recommended value as returned by the tape. - */ -static void idetape_get_mode_sense_results(ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - struct ide_atapi_pc pc; - u8 buf[24], *caps; - u8 speed, max_speed; - - idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE); - if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) { - printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming" - " some default values\n"); - tape->blk_size = 512; - put_unaligned(52, (u16 *)&tape->caps[12]); - put_unaligned(540, (u16 *)&tape->caps[14]); - put_unaligned(6*52, (u16 *)&tape->caps[16]); - return; - } - caps = buf + 4 + buf[3]; - - /* convert to host order and save for later use */ - speed = be16_to_cpup((__be16 *)&caps[14]); - max_speed = be16_to_cpup((__be16 *)&caps[8]); - - *(u16 *)&caps[8] = max_speed; - *(u16 *)&caps[12] = be16_to_cpup((__be16 *)&caps[12]); - *(u16 *)&caps[14] = speed; - *(u16 *)&caps[16] = be16_to_cpup((__be16 *)&caps[16]); - - if (!speed) { - printk(KERN_INFO "ide-tape: %s: invalid tape speed " - "(assuming 650KB/sec)\n", drive->name); - *(u16 *)&caps[14] = 650; - } - if (!max_speed) { - printk(KERN_INFO "ide-tape: %s: invalid max_speed " - "(assuming 650KB/sec)\n", drive->name); - *(u16 *)&caps[8] = 650; - } - - memcpy(&tape->caps, caps, 20); - - /* device lacks locking support according to capabilities page */ - if ((caps[6] & 1) == 0) - drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING; - - if (caps[7] & 0x02) - tape->blk_size = 512; - else if (caps[7] & 0x04) - tape->blk_size = 1024; -} - -#ifdef CONFIG_IDE_PROC_FS -#define ide_tape_devset_get(name, field) \ -static int get_##name(ide_drive_t *drive) \ -{ \ - idetape_tape_t *tape = drive->driver_data; \ - return tape->field; \ -} - -#define ide_tape_devset_set(name, field) \ -static int set_##name(ide_drive_t *drive, int arg) \ -{ \ - idetape_tape_t *tape = drive->driver_data; \ - tape->field = arg; \ - return 0; \ -} - -#define ide_tape_devset_rw_field(_name, _field) \ -ide_tape_devset_get(_name, _field) \ -ide_tape_devset_set(_name, _field) \ -IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name) - -#define ide_tape_devset_r_field(_name, _field) \ -ide_tape_devset_get(_name, _field) \ -IDE_DEVSET(_name, 0, get_##_name, NULL) - -static int mulf_tdsc(ide_drive_t *drive) { return 1000; } -static int divf_tdsc(ide_drive_t *drive) { return HZ; } -static int divf_buffer(ide_drive_t *drive) { return 2; } -static int divf_buffer_size(ide_drive_t *drive) { return 1024; } - -ide_devset_rw_flag(dsc_overlap, IDE_DFLAG_DSC_OVERLAP); - -ide_tape_devset_rw_field(tdsc, best_dsc_rw_freq); - -ide_tape_devset_r_field(avg_speed, avg_speed); -ide_tape_devset_r_field(speed, caps[14]); -ide_tape_devset_r_field(buffer, caps[16]); -ide_tape_devset_r_field(buffer_size, buffer_size); - -static const struct ide_proc_devset idetape_settings[] = { - __IDE_PROC_DEVSET(avg_speed, 0, 0xffff, NULL, NULL), - __IDE_PROC_DEVSET(buffer, 0, 0xffff, NULL, divf_buffer), - __IDE_PROC_DEVSET(buffer_size, 0, 0xffff, NULL, divf_buffer_size), - __IDE_PROC_DEVSET(dsc_overlap, 0, 1, NULL, NULL), - __IDE_PROC_DEVSET(speed, 0, 0xffff, NULL, NULL), - __IDE_PROC_DEVSET(tdsc, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX, - mulf_tdsc, divf_tdsc), - { NULL }, -}; -#endif - -/* - * The function below is called to: - * - * 1. Initialize our various state variables. - * 2. Ask the tape for its capabilities. - * 3. Allocate a buffer which will be used for data transfer. The buffer size - * is chosen based on the recommendation which we received in step 2. - * - * Note that at this point ide.c already assigned us an irq, so that we can - * queue requests here and wait for their completion. - */ -static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor) -{ - unsigned long t; - int speed; - u16 *ctl = (u16 *)&tape->caps[12]; - - ide_debug_log(IDE_DBG_FUNC, "minor: %d", minor); - - drive->pc_callback = ide_tape_callback; - - drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP; - - if (drive->hwif->host_flags & IDE_HFLAG_NO_DSC) { - printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", - tape->name); - drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP; - } - - /* Seagate Travan drives do not support DSC overlap. */ - if (strstr((char *)&drive->id[ATA_ID_PROD], "Seagate STT3401")) - drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP; - - tape->minor = minor; - tape->name[0] = 'h'; - tape->name[1] = 't'; - tape->name[2] = '0' + minor; - tape->chrdev_dir = IDETAPE_DIR_NONE; - - idetape_get_inquiry_results(drive); - idetape_get_mode_sense_results(drive); - ide_tape_get_bsize_from_bdesc(drive); - tape->user_bs_factor = 1; - tape->buffer_size = *ctl * tape->blk_size; - while (tape->buffer_size > 0xffff) { - printk(KERN_NOTICE "ide-tape: decreasing stage size\n"); - *ctl /= 2; - tape->buffer_size = *ctl * tape->blk_size; - } - - /* select the "best" DSC read/write polling freq */ - speed = max(*(u16 *)&tape->caps[14], *(u16 *)&tape->caps[8]); - - t = (IDETAPE_FIFO_THRESHOLD * tape->buffer_size * HZ) / (speed * 1000); - - /* - * Ensure that the number we got makes sense; limit it within - * IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX. - */ - tape->best_dsc_rw_freq = clamp_t(unsigned long, t, IDETAPE_DSC_RW_MIN, - IDETAPE_DSC_RW_MAX); - printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, " - "%ums tDSC%s\n", - drive->name, tape->name, *(u16 *)&tape->caps[14], - (*(u16 *)&tape->caps[16] * 512) / tape->buffer_size, - tape->buffer_size / 1024, - jiffies_to_msecs(tape->best_dsc_rw_freq), - (drive->dev_flags & IDE_DFLAG_USING_DMA) ? ", DMA" : ""); - - ide_proc_register_driver(drive, tape->driver); -} - -static void ide_tape_remove(ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - - ide_proc_unregister_driver(drive, tape->driver); - device_del(&tape->dev); - - mutex_lock(&idetape_ref_mutex); - put_device(&tape->dev); - mutex_unlock(&idetape_ref_mutex); -} - -static void ide_tape_release(struct device *dev) -{ - struct ide_tape_obj *tape = to_ide_drv(dev, ide_tape_obj); - ide_drive_t *drive = tape->drive; - struct gendisk *g = tape->disk; - - BUG_ON(tape->valid); - - drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP; - drive->driver_data = NULL; - device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor)); - device_destroy(idetape_sysfs_class, - MKDEV(IDETAPE_MAJOR, tape->minor + 128)); - idetape_devs[tape->minor] = NULL; - g->private_data = NULL; - put_disk(g); - kfree(tape); -} - -#ifdef CONFIG_IDE_PROC_FS -static int idetape_name_proc_show(struct seq_file *m, void *v) -{ - ide_drive_t *drive = (ide_drive_t *) m->private; - idetape_tape_t *tape = drive->driver_data; - - seq_printf(m, "%s\n", tape->name); - return 0; -} - -static ide_proc_entry_t idetape_proc[] = { - { "capacity", S_IFREG|S_IRUGO, ide_capacity_proc_show }, - { "name", S_IFREG|S_IRUGO, idetape_name_proc_show }, - {} -}; - -static ide_proc_entry_t *ide_tape_proc_entries(ide_drive_t *drive) -{ - return idetape_proc; -} - -static const struct ide_proc_devset *ide_tape_proc_devsets(ide_drive_t *drive) -{ - return idetape_settings; -} -#endif - -static int ide_tape_probe(ide_drive_t *); - -static struct ide_driver idetape_driver = { - .gen_driver = { - .owner = THIS_MODULE, - .name = "ide-tape", - .bus = &ide_bus_type, - }, - .probe = ide_tape_probe, - .remove = ide_tape_remove, - .version = IDETAPE_VERSION, - .do_request = idetape_do_request, -#ifdef CONFIG_IDE_PROC_FS - .proc_entries = ide_tape_proc_entries, - .proc_devsets = ide_tape_proc_devsets, -#endif -}; - -/* Our character device supporting functions, passed to register_chrdev. */ -static const struct file_operations idetape_fops = { - .owner = THIS_MODULE, - .read = idetape_chrdev_read, - .write = idetape_chrdev_write, - .unlocked_ioctl = idetape_chrdev_ioctl, - .compat_ioctl = IS_ENABLED(CONFIG_COMPAT) ? - idetape_chrdev_compat_ioctl : NULL, - .open = idetape_chrdev_open, - .release = idetape_chrdev_release, - .llseek = noop_llseek, -}; - -static int idetape_open(struct block_device *bdev, fmode_t mode) -{ - struct ide_tape_obj *tape; - - mutex_lock(&ide_tape_mutex); - tape = ide_tape_get(bdev->bd_disk, false, 0); - mutex_unlock(&ide_tape_mutex); - - if (!tape) - return -ENXIO; - - return 0; -} - -static void idetape_release(struct gendisk *disk, fmode_t mode) -{ - struct ide_tape_obj *tape = ide_drv_g(disk, ide_tape_obj); - - mutex_lock(&ide_tape_mutex); - ide_tape_put(tape); - mutex_unlock(&ide_tape_mutex); -} - -static int idetape_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - struct ide_tape_obj *tape = ide_drv_g(bdev->bd_disk, ide_tape_obj); - ide_drive_t *drive = tape->drive; - int err; - - mutex_lock(&ide_tape_mutex); - err = generic_ide_ioctl(drive, bdev, cmd, arg); - if (err == -EINVAL) - err = idetape_blkdev_ioctl(drive, cmd, arg); - mutex_unlock(&ide_tape_mutex); - - return err; -} - -static int idetape_compat_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - if (cmd == 0x0340 || cmd == 0x350) - arg = (unsigned long)compat_ptr(arg); - - return idetape_ioctl(bdev, mode, cmd, arg); -} - -static const struct block_device_operations idetape_block_ops = { - .owner = THIS_MODULE, - .open = idetape_open, - .release = idetape_release, - .ioctl = idetape_ioctl, - .compat_ioctl = IS_ENABLED(CONFIG_COMPAT) ? - idetape_compat_ioctl : NULL, -}; - -static int ide_tape_probe(ide_drive_t *drive) -{ - idetape_tape_t *tape; - struct gendisk *g; - int minor; - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - if (!strstr(DRV_NAME, drive->driver_req)) - goto failed; - - if (drive->media != ide_tape) - goto failed; - - if ((drive->dev_flags & IDE_DFLAG_ID_READ) && - ide_check_atapi_device(drive, DRV_NAME) == 0) { - printk(KERN_ERR "ide-tape: %s: not supported by this version of" - " the driver\n", drive->name); - goto failed; - } - tape = kzalloc(sizeof(idetape_tape_t), GFP_KERNEL); - if (tape == NULL) { - printk(KERN_ERR "ide-tape: %s: Can't allocate a tape struct\n", - drive->name); - goto failed; - } - - g = alloc_disk(1 << PARTN_BITS); - if (!g) - goto out_free_tape; - - ide_init_disk(g, drive); - - tape->dev.parent = &drive->gendev; - tape->dev.release = ide_tape_release; - dev_set_name(&tape->dev, "%s", dev_name(&drive->gendev)); - - if (device_register(&tape->dev)) - goto out_free_disk; - - tape->drive = drive; - tape->driver = &idetape_driver; - tape->disk = g; - - g->private_data = &tape->driver; - - drive->driver_data = tape; - - mutex_lock(&idetape_ref_mutex); - for (minor = 0; idetape_devs[minor]; minor++) - ; - idetape_devs[minor] = tape; - mutex_unlock(&idetape_ref_mutex); - - idetape_setup(drive, tape, minor); - - device_create(idetape_sysfs_class, &drive->gendev, - MKDEV(IDETAPE_MAJOR, minor), NULL, "%s", tape->name); - device_create(idetape_sysfs_class, &drive->gendev, - MKDEV(IDETAPE_MAJOR, minor + 128), NULL, - "n%s", tape->name); - - g->fops = &idetape_block_ops; - - return 0; - -out_free_disk: - put_disk(g); -out_free_tape: - kfree(tape); -failed: - return -ENODEV; -} - -static void __exit idetape_exit(void) -{ - driver_unregister(&idetape_driver.gen_driver); - class_destroy(idetape_sysfs_class); - unregister_chrdev(IDETAPE_MAJOR, "ht"); -} - -static int __init idetape_init(void) -{ - int error = 1; - idetape_sysfs_class = class_create(THIS_MODULE, "ide_tape"); - if (IS_ERR(idetape_sysfs_class)) { - idetape_sysfs_class = NULL; - printk(KERN_ERR "Unable to create sysfs class for ide tapes\n"); - error = -EBUSY; - goto out; - } - - if (register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) { - printk(KERN_ERR "ide-tape: Failed to register chrdev" - " interface\n"); - error = -EBUSY; - goto out_free_class; - } - - error = driver_register(&idetape_driver.gen_driver); - if (error) - goto out_free_chrdev; - - return 0; - -out_free_chrdev: - unregister_chrdev(IDETAPE_MAJOR, "ht"); -out_free_class: - class_destroy(idetape_sysfs_class); -out: - return error; -} - -MODULE_ALIAS("ide:*m-tape*"); -module_init(idetape_init); -module_exit(idetape_exit); -MODULE_ALIAS_CHARDEV_MAJOR(IDETAPE_MAJOR); -MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c deleted file mode 100644 index 6665fc4724b9..000000000000 --- a/drivers/ide/ide-taskfile.c +++ /dev/null @@ -1,668 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2000-2002 Michael Cornwell - * Copyright (C) 2000-2002 Andre Hedrick - * Copyright (C) 2001-2002 Klaus Smolin - * IBM Storage Technology Division - * Copyright (C) 2003-2004, 2007 Bartlomiej Zolnierkiewicz - * - * The big the bad and the ugly. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -void ide_tf_readback(ide_drive_t *drive, struct ide_cmd *cmd) -{ - ide_hwif_t *hwif = drive->hwif; - const struct ide_tp_ops *tp_ops = hwif->tp_ops; - - /* Be sure we're looking at the low order bytes */ - tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); - - tp_ops->tf_read(drive, &cmd->tf, cmd->valid.in.tf); - - if (cmd->tf_flags & IDE_TFLAG_LBA48) { - tp_ops->write_devctl(hwif, ATA_HOB | ATA_DEVCTL_OBS); - - tp_ops->tf_read(drive, &cmd->hob, cmd->valid.in.hob); - } -} - -void ide_tf_dump(const char *s, struct ide_cmd *cmd) -{ -#ifdef DEBUG - printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x " - "lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n", - s, cmd->tf.feature, cmd->tf.nsect, - cmd->tf.lbal, cmd->tf.lbam, cmd->tf.lbah, - cmd->tf.device, cmd->tf.command); - printk("%s: hob: nsect 0x%02x lbal 0x%02x lbam 0x%02x lbah 0x%02x\n", - s, cmd->hob.nsect, cmd->hob.lbal, cmd->hob.lbam, cmd->hob.lbah); -#endif -} - -int taskfile_lib_get_identify(ide_drive_t *drive, u8 *buf) -{ - struct ide_cmd cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.tf.nsect = 0x01; - if (drive->media == ide_disk) - cmd.tf.command = ATA_CMD_ID_ATA; - else - cmd.tf.command = ATA_CMD_ID_ATAPI; - cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - cmd.protocol = ATA_PROT_PIO; - - return ide_raw_taskfile(drive, &cmd, buf, 1); -} - -static ide_startstop_t task_no_data_intr(ide_drive_t *); -static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct ide_cmd *); -static ide_startstop_t task_pio_intr(ide_drive_t *); - -ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_cmd *cmd = &hwif->cmd; - struct ide_taskfile *tf = &cmd->tf; - ide_handler_t *handler = NULL; - const struct ide_tp_ops *tp_ops = hwif->tp_ops; - const struct ide_dma_ops *dma_ops = hwif->dma_ops; - - if (orig_cmd->protocol == ATA_PROT_PIO && - (orig_cmd->tf_flags & IDE_TFLAG_MULTI_PIO) && - drive->mult_count == 0) { - pr_err("%s: multimode not set!\n", drive->name); - return ide_stopped; - } - - if (orig_cmd->ftf_flags & IDE_FTFLAG_FLAGGED) - orig_cmd->ftf_flags |= IDE_FTFLAG_SET_IN_FLAGS; - - memcpy(cmd, orig_cmd, sizeof(*cmd)); - - if ((cmd->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) { - ide_tf_dump(drive->name, cmd); - tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); - - if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) { - u8 data[2] = { cmd->tf.data, cmd->hob.data }; - - tp_ops->output_data(drive, cmd, data, 2); - } - - if (cmd->valid.out.tf & IDE_VALID_DEVICE) { - u8 HIHI = (cmd->tf_flags & IDE_TFLAG_LBA48) ? - 0xE0 : 0xEF; - - if (!(cmd->ftf_flags & IDE_FTFLAG_FLAGGED)) - cmd->tf.device &= HIHI; - cmd->tf.device |= drive->select; - } - - tp_ops->tf_load(drive, &cmd->hob, cmd->valid.out.hob); - tp_ops->tf_load(drive, &cmd->tf, cmd->valid.out.tf); - } - - switch (cmd->protocol) { - case ATA_PROT_PIO: - if (cmd->tf_flags & IDE_TFLAG_WRITE) { - tp_ops->exec_command(hwif, tf->command); - ndelay(400); /* FIXME */ - return pre_task_out_intr(drive, cmd); - } - handler = task_pio_intr; - fallthrough; - case ATA_PROT_NODATA: - if (handler == NULL) - handler = task_no_data_intr; - ide_execute_command(drive, cmd, handler, WAIT_WORSTCASE); - return ide_started; - case ATA_PROT_DMA: - if (ide_dma_prepare(drive, cmd)) - return ide_stopped; - hwif->expiry = dma_ops->dma_timer_expiry; - ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD); - dma_ops->dma_start(drive); - fallthrough; - default: - return ide_started; - } -} -EXPORT_SYMBOL_GPL(do_rw_taskfile); - -static ide_startstop_t task_no_data_intr(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_cmd *cmd = &hwif->cmd; - struct ide_taskfile *tf = &cmd->tf; - int custom = (cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0; - int retries = (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) ? 5 : 1; - u8 stat; - - local_irq_enable_in_hardirq(); - - while (1) { - stat = hwif->tp_ops->read_status(hwif); - if ((stat & ATA_BUSY) == 0 || retries-- == 0) - break; - udelay(10); - }; - - if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) { - if (custom && tf->command == ATA_CMD_SET_MULTI) { - drive->mult_req = drive->mult_count = 0; - drive->special_flags |= IDE_SFLAG_RECALIBRATE; - (void)ide_dump_status(drive, __func__, stat); - return ide_stopped; - } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) { - if ((stat & (ATA_ERR | ATA_DRQ)) == 0) { - ide_set_handler(drive, &task_no_data_intr, - WAIT_WORSTCASE); - return ide_started; - } - } - return ide_error(drive, "task_no_data_intr", stat); - } - - if (custom && tf->command == ATA_CMD_SET_MULTI) - drive->mult_count = drive->mult_req; - - if (custom == 0 || tf->command == ATA_CMD_IDLEIMMEDIATE || - tf->command == ATA_CMD_CHK_POWER) { - struct request *rq = hwif->rq; - - if (ata_pm_request(rq)) - ide_complete_pm_rq(drive, rq); - else - ide_finish_cmd(drive, cmd, stat); - } - - return ide_stopped; -} - -static u8 wait_drive_not_busy(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - int retries; - u8 stat; - - /* - * Last sector was transferred, wait until device is ready. This can - * take up to 6 ms on some ATAPI devices, so we will wait max 10 ms. - */ - for (retries = 0; retries < 1000; retries++) { - stat = hwif->tp_ops->read_status(hwif); - - if (stat & ATA_BUSY) - udelay(10); - else - break; - } - - if (stat & ATA_BUSY) - pr_err("%s: drive still BUSY!\n", drive->name); - - return stat; -} - -void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd, - unsigned int write, unsigned int len) -{ - ide_hwif_t *hwif = drive->hwif; - struct scatterlist *sg = hwif->sg_table; - struct scatterlist *cursg = cmd->cursg; - struct page *page; - unsigned int offset; - u8 *buf; - - if (cursg == NULL) - cursg = cmd->cursg = sg; - - while (len) { - unsigned nr_bytes = min(len, cursg->length - cmd->cursg_ofs); - - page = sg_page(cursg); - offset = cursg->offset + cmd->cursg_ofs; - - /* get the current page and offset */ - page = nth_page(page, (offset >> PAGE_SHIFT)); - offset %= PAGE_SIZE; - - nr_bytes = min_t(unsigned, nr_bytes, (PAGE_SIZE - offset)); - - buf = kmap_atomic(page) + offset; - - cmd->nleft -= nr_bytes; - cmd->cursg_ofs += nr_bytes; - - if (cmd->cursg_ofs == cursg->length) { - cursg = cmd->cursg = sg_next(cmd->cursg); - cmd->cursg_ofs = 0; - } - - /* do the actual data transfer */ - if (write) - hwif->tp_ops->output_data(drive, cmd, buf, nr_bytes); - else - hwif->tp_ops->input_data(drive, cmd, buf, nr_bytes); - - kunmap_atomic(buf); - - len -= nr_bytes; - } -} -EXPORT_SYMBOL_GPL(ide_pio_bytes); - -static void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd, - unsigned int write) -{ - unsigned int nr_bytes; - - u8 saved_io_32bit = drive->io_32bit; - - if (cmd->tf_flags & IDE_TFLAG_FS) - scsi_req(cmd->rq)->result = 0; - - if (cmd->tf_flags & IDE_TFLAG_IO_16BIT) - drive->io_32bit = 0; - - touch_softlockup_watchdog(); - - if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) - nr_bytes = min_t(unsigned, cmd->nleft, drive->mult_count << 9); - else - nr_bytes = SECTOR_SIZE; - - ide_pio_bytes(drive, cmd, write, nr_bytes); - - drive->io_32bit = saved_io_32bit; -} - -static void ide_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd) -{ - if (cmd->tf_flags & IDE_TFLAG_FS) { - int nr_bytes = cmd->nbytes - cmd->nleft; - - if (cmd->protocol == ATA_PROT_PIO && - ((cmd->tf_flags & IDE_TFLAG_WRITE) || cmd->nleft == 0)) { - if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) - nr_bytes -= drive->mult_count << 9; - else - nr_bytes -= SECTOR_SIZE; - } - - if (nr_bytes > 0) - ide_complete_rq(drive, BLK_STS_OK, nr_bytes); - } -} - -void ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat) -{ - struct request *rq = drive->hwif->rq; - u8 err = ide_read_error(drive), nsect = cmd->tf.nsect; - u8 set_xfer = !!(cmd->tf_flags & IDE_TFLAG_SET_XFER); - - ide_complete_cmd(drive, cmd, stat, err); - scsi_req(rq)->result = err; - - if (err == 0 && set_xfer) { - ide_set_xfer_rate(drive, nsect); - ide_driveid_update(drive); - } - - ide_complete_rq(drive, err ? BLK_STS_IOERR : BLK_STS_OK, blk_rq_bytes(rq)); -} - -/* - * Handler for command with PIO data phase. - */ -static ide_startstop_t task_pio_intr(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_cmd *cmd = &drive->hwif->cmd; - u8 stat = hwif->tp_ops->read_status(hwif); - u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE); - - if (write == 0) { - /* Error? */ - if (stat & ATA_ERR) - goto out_err; - - /* Didn't want any data? Odd. */ - if ((stat & ATA_DRQ) == 0) { - /* Command all done? */ - if (OK_STAT(stat, ATA_DRDY, ATA_BUSY)) - goto out_end; - - /* Assume it was a spurious irq */ - goto out_wait; - } - } else { - if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) - goto out_err; - - /* Deal with unexpected ATA data phase. */ - if (((stat & ATA_DRQ) == 0) ^ (cmd->nleft == 0)) - goto out_err; - } - - if (write && cmd->nleft == 0) - goto out_end; - - /* Still data left to transfer. */ - ide_pio_datablock(drive, cmd, write); - - /* Are we done? Check status and finish transfer. */ - if (write == 0 && cmd->nleft == 0) { - stat = wait_drive_not_busy(drive); - if (!OK_STAT(stat, 0, BAD_STAT)) - goto out_err; - - goto out_end; - } -out_wait: - /* Still data left to transfer. */ - ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE); - return ide_started; -out_end: - if ((cmd->tf_flags & IDE_TFLAG_FS) == 0) - ide_finish_cmd(drive, cmd, stat); - else - ide_complete_rq(drive, BLK_STS_OK, blk_rq_sectors(cmd->rq) << 9); - return ide_stopped; -out_err: - ide_error_cmd(drive, cmd); - return ide_error(drive, __func__, stat); -} - -static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, - struct ide_cmd *cmd) -{ - ide_startstop_t startstop; - - if (ide_wait_stat(&startstop, drive, ATA_DRQ, - drive->bad_wstat, WAIT_DRQ)) { - pr_err("%s: no DRQ after issuing %sWRITE%s\n", drive->name, - (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) ? "MULT" : "", - (drive->dev_flags & IDE_DFLAG_LBA48) ? "_EXT" : ""); - return startstop; - } - - if (!force_irqthreads && (drive->dev_flags & IDE_DFLAG_UNMASK) == 0) - local_irq_disable(); - - ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE); - - ide_pio_datablock(drive, cmd, 1); - - return ide_started; -} - -int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf, - u16 nsect) -{ - struct request *rq; - int error; - - rq = blk_get_request(drive->queue, - (cmd->tf_flags & IDE_TFLAG_WRITE) ? - REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); - ide_req(rq)->type = ATA_PRIV_TASKFILE; - - /* - * (ks) We transfer currently only whole sectors. - * This is suffient for now. But, it would be great, - * if we would find a solution to transfer any size. - * To support special commands like READ LONG. - */ - if (nsect) { - error = blk_rq_map_kern(drive->queue, rq, buf, - nsect * SECTOR_SIZE, GFP_NOIO); - if (error) - goto put_req; - } - - ide_req(rq)->special = cmd; - cmd->rq = rq; - - blk_execute_rq(NULL, rq, 0); - error = scsi_req(rq)->result ? -EIO : 0; -put_req: - blk_put_request(rq); - return error; -} -EXPORT_SYMBOL(ide_raw_taskfile); - -int ide_no_data_taskfile(ide_drive_t *drive, struct ide_cmd *cmd) -{ - cmd->protocol = ATA_PROT_NODATA; - - return ide_raw_taskfile(drive, cmd, NULL, 0); -} -EXPORT_SYMBOL_GPL(ide_no_data_taskfile); - -#ifdef CONFIG_IDE_TASK_IOCTL -int ide_taskfile_ioctl(ide_drive_t *drive, unsigned long arg) -{ - ide_task_request_t *req_task; - struct ide_cmd cmd; - u8 *outbuf = NULL; - u8 *inbuf = NULL; - u8 *data_buf = NULL; - int err = 0; - int tasksize = sizeof(struct ide_task_request_s); - unsigned int taskin = 0; - unsigned int taskout = 0; - u16 nsect = 0; - char __user *buf = (char __user *)arg; - - req_task = memdup_user(buf, tasksize); - if (IS_ERR(req_task)) - return PTR_ERR(req_task); - - taskout = req_task->out_size; - taskin = req_task->in_size; - - if (taskin > 65536 || taskout > 65536) { - err = -EINVAL; - goto abort; - } - - if (taskout) { - int outtotal = tasksize; - outbuf = kzalloc(taskout, GFP_KERNEL); - if (outbuf == NULL) { - err = -ENOMEM; - goto abort; - } - if (copy_from_user(outbuf, buf + outtotal, taskout)) { - err = -EFAULT; - goto abort; - } - } - - if (taskin) { - int intotal = tasksize + taskout; - inbuf = kzalloc(taskin, GFP_KERNEL); - if (inbuf == NULL) { - err = -ENOMEM; - goto abort; - } - if (copy_from_user(inbuf, buf + intotal, taskin)) { - err = -EFAULT; - goto abort; - } - } - - memset(&cmd, 0, sizeof(cmd)); - - memcpy(&cmd.hob, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2); - memcpy(&cmd.tf, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE); - - cmd.valid.out.tf = IDE_VALID_DEVICE; - cmd.valid.in.tf = IDE_VALID_DEVICE | IDE_VALID_IN_TF; - cmd.tf_flags = IDE_TFLAG_IO_16BIT; - - if (drive->dev_flags & IDE_DFLAG_LBA48) { - cmd.tf_flags |= IDE_TFLAG_LBA48; - cmd.valid.in.hob = IDE_VALID_IN_HOB; - } - - if (req_task->out_flags.all) { - cmd.ftf_flags |= IDE_FTFLAG_FLAGGED; - - if (req_task->out_flags.b.data) - cmd.ftf_flags |= IDE_FTFLAG_OUT_DATA; - - if (req_task->out_flags.b.nsector_hob) - cmd.valid.out.hob |= IDE_VALID_NSECT; - if (req_task->out_flags.b.sector_hob) - cmd.valid.out.hob |= IDE_VALID_LBAL; - if (req_task->out_flags.b.lcyl_hob) - cmd.valid.out.hob |= IDE_VALID_LBAM; - if (req_task->out_flags.b.hcyl_hob) - cmd.valid.out.hob |= IDE_VALID_LBAH; - - if (req_task->out_flags.b.error_feature) - cmd.valid.out.tf |= IDE_VALID_FEATURE; - if (req_task->out_flags.b.nsector) - cmd.valid.out.tf |= IDE_VALID_NSECT; - if (req_task->out_flags.b.sector) - cmd.valid.out.tf |= IDE_VALID_LBAL; - if (req_task->out_flags.b.lcyl) - cmd.valid.out.tf |= IDE_VALID_LBAM; - if (req_task->out_flags.b.hcyl) - cmd.valid.out.tf |= IDE_VALID_LBAH; - } else { - cmd.valid.out.tf |= IDE_VALID_OUT_TF; - if (cmd.tf_flags & IDE_TFLAG_LBA48) - cmd.valid.out.hob |= IDE_VALID_OUT_HOB; - } - - if (req_task->in_flags.b.data) - cmd.ftf_flags |= IDE_FTFLAG_IN_DATA; - - if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE) { - /* fixup data phase if needed */ - if (req_task->data_phase == TASKFILE_IN_DMAQ || - req_task->data_phase == TASKFILE_IN_DMA) - cmd.tf_flags |= IDE_TFLAG_WRITE; - } - - cmd.protocol = ATA_PROT_DMA; - - switch (req_task->data_phase) { - case TASKFILE_MULTI_OUT: - if (!drive->mult_count) { - /* (hs): give up if multcount is not set */ - pr_err("%s: %s Multimode Write multcount is not set\n", - drive->name, __func__); - err = -EPERM; - goto abort; - } - cmd.tf_flags |= IDE_TFLAG_MULTI_PIO; - fallthrough; - case TASKFILE_OUT: - cmd.protocol = ATA_PROT_PIO; - fallthrough; - case TASKFILE_OUT_DMAQ: - case TASKFILE_OUT_DMA: - cmd.tf_flags |= IDE_TFLAG_WRITE; - nsect = taskout / SECTOR_SIZE; - data_buf = outbuf; - break; - case TASKFILE_MULTI_IN: - if (!drive->mult_count) { - /* (hs): give up if multcount is not set */ - pr_err("%s: %s Multimode Read multcount is not set\n", - drive->name, __func__); - err = -EPERM; - goto abort; - } - cmd.tf_flags |= IDE_TFLAG_MULTI_PIO; - fallthrough; - case TASKFILE_IN: - cmd.protocol = ATA_PROT_PIO; - fallthrough; - case TASKFILE_IN_DMAQ: - case TASKFILE_IN_DMA: - nsect = taskin / SECTOR_SIZE; - data_buf = inbuf; - break; - case TASKFILE_NO_DATA: - cmd.protocol = ATA_PROT_NODATA; - break; - default: - err = -EFAULT; - goto abort; - } - - if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA) - nsect = 0; - else if (!nsect) { - nsect = (cmd.hob.nsect << 8) | cmd.tf.nsect; - - if (!nsect) { - pr_err("%s: in/out command without data\n", - drive->name); - err = -EFAULT; - goto abort; - } - } - - err = ide_raw_taskfile(drive, &cmd, data_buf, nsect); - - memcpy(req_task->hob_ports, &cmd.hob, HDIO_DRIVE_HOB_HDR_SIZE - 2); - memcpy(req_task->io_ports, &cmd.tf, HDIO_DRIVE_TASK_HDR_SIZE); - - if ((cmd.ftf_flags & IDE_FTFLAG_SET_IN_FLAGS) && - req_task->in_flags.all == 0) { - req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS; - if (drive->dev_flags & IDE_DFLAG_LBA48) - req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8); - } - - if (copy_to_user(buf, req_task, tasksize)) { - err = -EFAULT; - goto abort; - } - if (taskout) { - int outtotal = tasksize; - if (copy_to_user(buf + outtotal, outbuf, taskout)) { - err = -EFAULT; - goto abort; - } - } - if (taskin) { - int intotal = tasksize + taskout; - if (copy_to_user(buf + intotal, inbuf, taskin)) { - err = -EFAULT; - goto abort; - } - } -abort: - kfree(req_task); - kfree(outbuf); - kfree(inbuf); - - return err; -} -#endif diff --git a/drivers/ide/ide-timings.c b/drivers/ide/ide-timings.c deleted file mode 100644 index cfe78df74b7d..000000000000 --- a/drivers/ide/ide-timings.c +++ /dev/null @@ -1,198 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) 1999-2001 Vojtech Pavlik - * Copyright (c) 2007-2008 Bartlomiej Zolnierkiewicz - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include - -/* - * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds). - * These were taken from ATA/ATAPI-6 standard, rev 0a, except - * for PIO 5, which is a nonstandard extension and UDMA6, which - * is currently supported only by Maxtor drives. - */ - -static struct ide_timing ide_timing[] = { - - { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 }, - { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 }, - { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 }, - { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 }, - - { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 }, - { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 }, - { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 }, - - { XFER_MW_DMA_4, 25, 0, 0, 0, 55, 20, 80, 0 }, - { XFER_MW_DMA_3, 25, 0, 0, 0, 65, 25, 100, 0 }, - { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 }, - { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 }, - { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 }, - - { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 }, - { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 }, - { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 }, - - { XFER_PIO_6, 10, 55, 20, 80, 55, 20, 80, 0 }, - { XFER_PIO_5, 15, 65, 25, 100, 65, 25, 100, 0 }, - { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 }, - { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 }, - - { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 }, - { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 }, - { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 }, - - { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, - - { 0xff } -}; - -struct ide_timing *ide_timing_find_mode(u8 speed) -{ - struct ide_timing *t; - - for (t = ide_timing; t->mode != speed; t++) - if (t->mode == 0xff) - return NULL; - return t; -} -EXPORT_SYMBOL_GPL(ide_timing_find_mode); - -u16 ide_pio_cycle_time(ide_drive_t *drive, u8 pio) -{ - u16 *id = drive->id; - struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); - u16 cycle = 0; - - if (id[ATA_ID_FIELD_VALID] & 2) { - if (ata_id_has_iordy(drive->id)) - cycle = id[ATA_ID_EIDE_PIO_IORDY]; - else - cycle = id[ATA_ID_EIDE_PIO]; - - /* conservative "downgrade" for all pre-ATA2 drives */ - if (pio < 3 && cycle < t->cycle) - cycle = 0; /* use standard timing */ - - /* Use the standard timing for the CF specific modes too */ - if (pio > 4 && ata_id_is_cfa(id)) - cycle = 0; - } - - return cycle ? cycle : t->cycle; -} -EXPORT_SYMBOL_GPL(ide_pio_cycle_time); - -#define ENOUGH(v, unit) (((v) - 1) / (unit) + 1) -#define EZ(v, unit) ((v) ? ENOUGH((v) * 1000, unit) : 0) - -static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q, - int T, int UT) -{ - q->setup = EZ(t->setup, T); - q->act8b = EZ(t->act8b, T); - q->rec8b = EZ(t->rec8b, T); - q->cyc8b = EZ(t->cyc8b, T); - q->active = EZ(t->active, T); - q->recover = EZ(t->recover, T); - q->cycle = EZ(t->cycle, T); - q->udma = EZ(t->udma, UT); -} - -void ide_timing_merge(struct ide_timing *a, struct ide_timing *b, - struct ide_timing *m, unsigned int what) -{ - if (what & IDE_TIMING_SETUP) - m->setup = max(a->setup, b->setup); - if (what & IDE_TIMING_ACT8B) - m->act8b = max(a->act8b, b->act8b); - if (what & IDE_TIMING_REC8B) - m->rec8b = max(a->rec8b, b->rec8b); - if (what & IDE_TIMING_CYC8B) - m->cyc8b = max(a->cyc8b, b->cyc8b); - if (what & IDE_TIMING_ACTIVE) - m->active = max(a->active, b->active); - if (what & IDE_TIMING_RECOVER) - m->recover = max(a->recover, b->recover); - if (what & IDE_TIMING_CYCLE) - m->cycle = max(a->cycle, b->cycle); - if (what & IDE_TIMING_UDMA) - m->udma = max(a->udma, b->udma); -} -EXPORT_SYMBOL_GPL(ide_timing_merge); - -int ide_timing_compute(ide_drive_t *drive, u8 speed, - struct ide_timing *t, int T, int UT) -{ - u16 *id = drive->id; - struct ide_timing *s, p; - - /* - * Find the mode. - */ - s = ide_timing_find_mode(speed); - if (s == NULL) - return -EINVAL; - - /* - * Copy the timing from the table. - */ - *t = *s; - - /* - * If the drive is an EIDE drive, it can tell us it needs extended - * PIO/MWDMA cycle timing. - */ - if (id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */ - memset(&p, 0, sizeof(p)); - - if (speed >= XFER_PIO_0 && speed < XFER_SW_DMA_0) { - if (speed <= XFER_PIO_2) - p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO]; - else if ((speed <= XFER_PIO_4) || - (speed == XFER_PIO_5 && !ata_id_is_cfa(id))) - p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY]; - } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) - p.cycle = id[ATA_ID_EIDE_DMA_MIN]; - - ide_timing_merge(&p, t, t, IDE_TIMING_CYCLE | IDE_TIMING_CYC8B); - } - - /* - * Convert the timing to bus clock counts. - */ - ide_timing_quantize(t, t, T, UT); - - /* - * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, - * S.M.A.R.T and some other commands. We have to ensure that the - * DMA cycle timing is slower/equal than the current PIO timing. - */ - if (speed >= XFER_SW_DMA_0) { - ide_timing_compute(drive, drive->pio_mode, &p, T, UT); - ide_timing_merge(&p, t, t, IDE_TIMING_ALL); - } - - /* - * Lengthen active & recovery time so that cycle time is correct. - */ - if (t->act8b + t->rec8b < t->cyc8b) { - t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2; - t->rec8b = t->cyc8b - t->act8b; - } - - if (t->active + t->recover < t->cycle) { - t->active += (t->cycle - (t->active + t->recover)) / 2; - t->recover = t->cycle - t->active; - } - - return 0; -} -EXPORT_SYMBOL_GPL(ide_timing_compute); diff --git a/drivers/ide/ide-xfer-mode.c b/drivers/ide/ide-xfer-mode.c deleted file mode 100644 index 0b9709b489b7..000000000000 --- a/drivers/ide/ide-xfer-mode.c +++ /dev/null @@ -1,267 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#include -#include -#include -#include -#include -#include -#include - -static const char *udma_str[] = - { "UDMA/16", "UDMA/25", "UDMA/33", "UDMA/44", - "UDMA/66", "UDMA/100", "UDMA/133", "UDMA7" }; -static const char *mwdma_str[] = - { "MWDMA0", "MWDMA1", "MWDMA2", "MWDMA3", "MWDMA4" }; -static const char *swdma_str[] = - { "SWDMA0", "SWDMA1", "SWDMA2" }; -static const char *pio_str[] = - { "PIO0", "PIO1", "PIO2", "PIO3", "PIO4", "PIO5", "PIO6" }; - -/** - * ide_xfer_verbose - return IDE mode names - * @mode: transfer mode - * - * Returns a constant string giving the name of the mode - * requested. - */ - -const char *ide_xfer_verbose(u8 mode) -{ - const char *s; - u8 i = mode & 0xf; - - if (mode >= XFER_UDMA_0 && mode <= XFER_UDMA_7) - s = udma_str[i]; - else if (mode >= XFER_MW_DMA_0 && mode <= XFER_MW_DMA_4) - s = mwdma_str[i]; - else if (mode >= XFER_SW_DMA_0 && mode <= XFER_SW_DMA_2) - s = swdma_str[i]; - else if (mode >= XFER_PIO_0 && mode <= XFER_PIO_6) - s = pio_str[i & 0x7]; - else if (mode == XFER_PIO_SLOW) - s = "PIO SLOW"; - else - s = "XFER ERROR"; - - return s; -} -EXPORT_SYMBOL(ide_xfer_verbose); - -/** - * ide_get_best_pio_mode - get PIO mode from drive - * @drive: drive to consider - * @mode_wanted: preferred mode - * @max_mode: highest allowed mode - * - * This routine returns the recommended PIO settings for a given drive, - * based on the drive->id information and the ide_pio_blacklist[]. - * - * Drive PIO mode is auto-selected if 255 is passed as mode_wanted. - * This is used by most chipset support modules when "auto-tuning". - */ - -static u8 ide_get_best_pio_mode(ide_drive_t *drive, u8 mode_wanted, u8 max_mode) -{ - u16 *id = drive->id; - int pio_mode = -1, overridden = 0; - - if (mode_wanted != 255) - return min_t(u8, mode_wanted, max_mode); - - if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0) - pio_mode = ide_scan_pio_blacklist((char *)&id[ATA_ID_PROD]); - - if (pio_mode != -1) { - printk(KERN_INFO "%s: is on PIO blacklist\n", drive->name); - } else { - pio_mode = id[ATA_ID_OLD_PIO_MODES] >> 8; - if (pio_mode > 2) { /* 2 is maximum allowed tPIO value */ - pio_mode = 2; - overridden = 1; - } - - if (id[ATA_ID_FIELD_VALID] & 2) { /* ATA2? */ - if (ata_id_is_cfa(id) && (id[ATA_ID_CFA_MODES] & 7)) - pio_mode = 4 + min_t(int, 2, - id[ATA_ID_CFA_MODES] & 7); - else if (ata_id_has_iordy(id)) { - if (id[ATA_ID_PIO_MODES] & 7) { - overridden = 0; - if (id[ATA_ID_PIO_MODES] & 4) - pio_mode = 5; - else if (id[ATA_ID_PIO_MODES] & 2) - pio_mode = 4; - else - pio_mode = 3; - } - } - } - - if (overridden) - printk(KERN_INFO "%s: tPIO > 2, assuming tPIO = 2\n", - drive->name); - } - - if (pio_mode > max_mode) - pio_mode = max_mode; - - return pio_mode; -} - -int ide_pio_need_iordy(ide_drive_t *drive, const u8 pio) -{ - /* - * IORDY may lead to controller lock up on certain controllers - * if the port is not occupied. - */ - if (pio == 0 && (drive->hwif->port_flags & IDE_PFLAG_PROBING)) - return 0; - return ata_id_pio_need_iordy(drive->id, pio); -} -EXPORT_SYMBOL_GPL(ide_pio_need_iordy); - -int ide_set_pio_mode(ide_drive_t *drive, const u8 mode) -{ - ide_hwif_t *hwif = drive->hwif; - const struct ide_port_ops *port_ops = hwif->port_ops; - - if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE) - return 0; - - if (port_ops == NULL || port_ops->set_pio_mode == NULL) - return -1; - - /* - * TODO: temporary hack for some legacy host drivers that didn't - * set transfer mode on the device in ->set_pio_mode method... - */ - if (port_ops->set_dma_mode == NULL) { - drive->pio_mode = mode; - port_ops->set_pio_mode(hwif, drive); - return 0; - } - - if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) { - if (ide_config_drive_speed(drive, mode)) - return -1; - drive->pio_mode = mode; - port_ops->set_pio_mode(hwif, drive); - return 0; - } else { - drive->pio_mode = mode; - port_ops->set_pio_mode(hwif, drive); - return ide_config_drive_speed(drive, mode); - } -} - -int ide_set_dma_mode(ide_drive_t *drive, const u8 mode) -{ - ide_hwif_t *hwif = drive->hwif; - const struct ide_port_ops *port_ops = hwif->port_ops; - - if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE) - return 0; - - if (port_ops == NULL || port_ops->set_dma_mode == NULL) - return -1; - - if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) { - if (ide_config_drive_speed(drive, mode)) - return -1; - drive->dma_mode = mode; - port_ops->set_dma_mode(hwif, drive); - return 0; - } else { - drive->dma_mode = mode; - port_ops->set_dma_mode(hwif, drive); - return ide_config_drive_speed(drive, mode); - } -} -EXPORT_SYMBOL_GPL(ide_set_dma_mode); - -/* req_pio == "255" for auto-tune */ -void ide_set_pio(ide_drive_t *drive, u8 req_pio) -{ - ide_hwif_t *hwif = drive->hwif; - const struct ide_port_ops *port_ops = hwif->port_ops; - u8 host_pio, pio; - - if (port_ops == NULL || port_ops->set_pio_mode == NULL || - (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)) - return; - - BUG_ON(hwif->pio_mask == 0x00); - - host_pio = fls(hwif->pio_mask) - 1; - - pio = ide_get_best_pio_mode(drive, req_pio, host_pio); - - /* - * TODO: - * - report device max PIO mode - * - check req_pio != 255 against device max PIO mode - */ - printk(KERN_DEBUG "%s: host max PIO%d wanted PIO%d%s selected PIO%d\n", - drive->name, host_pio, req_pio, - req_pio == 255 ? "(auto-tune)" : "", pio); - - (void)ide_set_pio_mode(drive, XFER_PIO_0 + pio); -} -EXPORT_SYMBOL_GPL(ide_set_pio); - -/** - * ide_rate_filter - filter transfer mode - * @drive: IDE device - * @speed: desired speed - * - * Given the available transfer modes this function returns - * the best available speed at or below the speed requested. - * - * TODO: check device PIO capabilities - */ - -static u8 ide_rate_filter(ide_drive_t *drive, u8 speed) -{ - ide_hwif_t *hwif = drive->hwif; - u8 mode = ide_find_dma_mode(drive, speed); - - if (mode == 0) { - if (hwif->pio_mask) - mode = fls(hwif->pio_mask) - 1 + XFER_PIO_0; - else - mode = XFER_PIO_4; - } - -/* printk("%s: mode 0x%02x, speed 0x%02x\n", __func__, mode, speed); */ - - return min(speed, mode); -} - -/** - * ide_set_xfer_rate - set transfer rate - * @drive: drive to set - * @rate: speed to attempt to set - * - * General helper for setting the speed of an IDE device. This - * function knows about user enforced limits from the configuration - * which ->set_pio_mode/->set_dma_mode does not. - */ - -int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) -{ - ide_hwif_t *hwif = drive->hwif; - const struct ide_port_ops *port_ops = hwif->port_ops; - - if (port_ops == NULL || port_ops->set_dma_mode == NULL || - (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)) - return -1; - - rate = ide_rate_filter(drive, rate); - - BUG_ON(rate < XFER_PIO_0); - - if (rate >= XFER_PIO_0 && rate <= XFER_PIO_6) - return ide_set_pio_mode(drive, rate); - - return ide_set_dma_mode(drive, rate); -} diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c deleted file mode 100644 index 9a9c64fd1032..000000000000 --- a/drivers/ide/ide.c +++ /dev/null @@ -1,415 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) - * Copyright (C) 2003-2005, 2007 Bartlomiej Zolnierkiewicz - */ - -/* - * Mostly written by Mark Lord - * and Gadi Oxman - * and Andre Hedrick - * - * See linux/MAINTAINERS for address of current maintainer. - * - * This is the multiple IDE interface driver, as evolved from hd.c. - * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs - * (usually 14 & 15). - * There can be up to two drives per interface, as per the ATA-2 spec. - * - * ... - * - * From hd.c: - * | - * | It traverses the request-list, using interrupts to jump between functions. - * | As nearly all functions can be called within interrupts, we may not sleep. - * | Special care is recommended. Have Fun! - * | - * | modified by Drew Eckhardt to check nr of hd's from the CMOS. - * | - * | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug - * | in the early extended-partition checks and added DM partitions. - * | - * | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI). - * | - * | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads", - * | and general streamlining by Mark Lord (mlord@pobox.com). - * - * October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by: - * - * Mark Lord (mlord@pobox.com) (IDE Perf.Pkg) - * Delman Lee (delman@ieee.org) ("Mr. atdisk2") - * Scott Snyder (snyder@fnald0.fnal.gov) (ATAPI IDE cd-rom) - * - * This was a rewrite of just about everything from hd.c, though some original - * code is still sprinkled about. Think of it as a major evolution, with - * inspiration from lots of linux users, esp. hamish@zot.apana.org.au - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct class *ide_port_class; - -/** - * ide_device_get - get an additional reference to a ide_drive_t - * @drive: device to get a reference to - * - * Gets a reference to the ide_drive_t and increments the use count of the - * underlying LLDD module. - */ -int ide_device_get(ide_drive_t *drive) -{ - struct device *host_dev; - struct module *module; - - if (!get_device(&drive->gendev)) - return -ENXIO; - - host_dev = drive->hwif->host->dev[0]; - module = host_dev ? host_dev->driver->owner : NULL; - - if (module && !try_module_get(module)) { - put_device(&drive->gendev); - return -ENXIO; - } - - return 0; -} -EXPORT_SYMBOL_GPL(ide_device_get); - -/** - * ide_device_put - release a reference to a ide_drive_t - * @drive: device to release a reference on - * - * Release a reference to the ide_drive_t and decrements the use count of - * the underlying LLDD module. - */ -void ide_device_put(ide_drive_t *drive) -{ -#ifdef CONFIG_MODULE_UNLOAD - struct device *host_dev = drive->hwif->host->dev[0]; - struct module *module = host_dev ? host_dev->driver->owner : NULL; - - module_put(module); -#endif - put_device(&drive->gendev); -} -EXPORT_SYMBOL_GPL(ide_device_put); - -static int ide_bus_match(struct device *dev, struct device_driver *drv) -{ - return 1; -} - -static int ide_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - ide_drive_t *drive = to_ide_device(dev); - - add_uevent_var(env, "MEDIA=%s", ide_media_string(drive)); - add_uevent_var(env, "DRIVENAME=%s", drive->name); - add_uevent_var(env, "MODALIAS=ide:m-%s", ide_media_string(drive)); - return 0; -} - -static int generic_ide_probe(struct device *dev) -{ - ide_drive_t *drive = to_ide_device(dev); - struct ide_driver *drv = to_ide_driver(dev->driver); - - return drv->probe ? drv->probe(drive) : -ENODEV; -} - -static int generic_ide_remove(struct device *dev) -{ - ide_drive_t *drive = to_ide_device(dev); - struct ide_driver *drv = to_ide_driver(dev->driver); - - if (drv->remove) - drv->remove(drive); - - return 0; -} - -static void generic_ide_shutdown(struct device *dev) -{ - ide_drive_t *drive = to_ide_device(dev); - struct ide_driver *drv = to_ide_driver(dev->driver); - - if (dev->driver && drv->shutdown) - drv->shutdown(drive); -} - -struct bus_type ide_bus_type = { - .name = "ide", - .match = ide_bus_match, - .uevent = ide_uevent, - .probe = generic_ide_probe, - .remove = generic_ide_remove, - .shutdown = generic_ide_shutdown, - .dev_groups = ide_dev_groups, - .suspend = generic_ide_suspend, - .resume = generic_ide_resume, -}; - -EXPORT_SYMBOL_GPL(ide_bus_type); - -int ide_vlb_clk; -EXPORT_SYMBOL_GPL(ide_vlb_clk); - -module_param_named(vlb_clock, ide_vlb_clk, int, 0); -MODULE_PARM_DESC(vlb_clock, "VLB clock frequency (in MHz)"); - -int ide_pci_clk; -EXPORT_SYMBOL_GPL(ide_pci_clk); - -module_param_named(pci_clock, ide_pci_clk, int, 0); -MODULE_PARM_DESC(pci_clock, "PCI bus clock frequency (in MHz)"); - -static int ide_set_dev_param_mask(const char *s, const struct kernel_param *kp) -{ - unsigned int a, b, i, j = 1; - unsigned int *dev_param_mask = (unsigned int *)kp->arg; - - /* controller . device (0 or 1) [ : 1 (set) | 0 (clear) ] */ - if (sscanf(s, "%u.%u:%u", &a, &b, &j) != 3 && - sscanf(s, "%u.%u", &a, &b) != 2) - return -EINVAL; - - i = a * MAX_DRIVES + b; - - if (i >= MAX_HWIFS * MAX_DRIVES || j > 1) - return -EINVAL; - - if (j) - *dev_param_mask |= (1 << i); - else - *dev_param_mask &= ~(1 << i); - - return 0; -} - -static const struct kernel_param_ops param_ops_ide_dev_mask = { - .set = ide_set_dev_param_mask -}; - -#define param_check_ide_dev_mask(name, p) param_check_uint(name, p) - -static unsigned int ide_nodma; - -module_param_named(nodma, ide_nodma, ide_dev_mask, 0); -MODULE_PARM_DESC(nodma, "disallow DMA for a device"); - -static unsigned int ide_noflush; - -module_param_named(noflush, ide_noflush, ide_dev_mask, 0); -MODULE_PARM_DESC(noflush, "disable flush requests for a device"); - -static unsigned int ide_nohpa; - -module_param_named(nohpa, ide_nohpa, ide_dev_mask, 0); -MODULE_PARM_DESC(nohpa, "disable Host Protected Area for a device"); - -static unsigned int ide_noprobe; - -module_param_named(noprobe, ide_noprobe, ide_dev_mask, 0); -MODULE_PARM_DESC(noprobe, "skip probing for a device"); - -static unsigned int ide_nowerr; - -module_param_named(nowerr, ide_nowerr, ide_dev_mask, 0); -MODULE_PARM_DESC(nowerr, "ignore the ATA_DF bit for a device"); - -static unsigned int ide_cdroms; - -module_param_named(cdrom, ide_cdroms, ide_dev_mask, 0); -MODULE_PARM_DESC(cdrom, "force device as a CD-ROM"); - -struct chs_geom { - unsigned int cyl; - u8 head; - u8 sect; -}; - -static unsigned int ide_disks; -static struct chs_geom ide_disks_chs[MAX_HWIFS * MAX_DRIVES]; - -static int ide_set_disk_chs(const char *str, const struct kernel_param *kp) -{ - unsigned int a, b, c = 0, h = 0, s = 0, i, j = 1; - - /* controller . device (0 or 1) : Cylinders , Heads , Sectors */ - /* controller . device (0 or 1) : 1 (use CHS) | 0 (ignore CHS) */ - if (sscanf(str, "%u.%u:%u,%u,%u", &a, &b, &c, &h, &s) != 5 && - sscanf(str, "%u.%u:%u", &a, &b, &j) != 3) - return -EINVAL; - - i = a * MAX_DRIVES + b; - - if (i >= MAX_HWIFS * MAX_DRIVES || j > 1) - return -EINVAL; - - if (c > INT_MAX || h > 255 || s > 255) - return -EINVAL; - - if (j) - ide_disks |= (1 << i); - else - ide_disks &= ~(1 << i); - - ide_disks_chs[i].cyl = c; - ide_disks_chs[i].head = h; - ide_disks_chs[i].sect = s; - - return 0; -} - -module_param_call(chs, ide_set_disk_chs, NULL, NULL, 0); -MODULE_PARM_DESC(chs, "force device as a disk (using CHS)"); - -static void ide_dev_apply_params(ide_drive_t *drive, u8 unit) -{ - int i = drive->hwif->index * MAX_DRIVES + unit; - - if (ide_nodma & (1 << i)) { - printk(KERN_INFO "ide: disallowing DMA for %s\n", drive->name); - drive->dev_flags |= IDE_DFLAG_NODMA; - } - if (ide_noflush & (1 << i)) { - printk(KERN_INFO "ide: disabling flush requests for %s\n", - drive->name); - drive->dev_flags |= IDE_DFLAG_NOFLUSH; - } - if (ide_nohpa & (1 << i)) { - printk(KERN_INFO "ide: disabling Host Protected Area for %s\n", - drive->name); - drive->dev_flags |= IDE_DFLAG_NOHPA; - } - if (ide_noprobe & (1 << i)) { - printk(KERN_INFO "ide: skipping probe for %s\n", drive->name); - drive->dev_flags |= IDE_DFLAG_NOPROBE; - } - if (ide_nowerr & (1 << i)) { - printk(KERN_INFO "ide: ignoring the ATA_DF bit for %s\n", - drive->name); - drive->bad_wstat = BAD_R_STAT; - } - if (ide_cdroms & (1 << i)) { - printk(KERN_INFO "ide: forcing %s as a CD-ROM\n", drive->name); - drive->dev_flags |= IDE_DFLAG_PRESENT; - drive->media = ide_cdrom; - /* an ATAPI device ignores DRDY */ - drive->ready_stat = 0; - } - if (ide_disks & (1 << i)) { - drive->cyl = drive->bios_cyl = ide_disks_chs[i].cyl; - drive->head = drive->bios_head = ide_disks_chs[i].head; - drive->sect = drive->bios_sect = ide_disks_chs[i].sect; - - printk(KERN_INFO "ide: forcing %s as a disk (%d/%d/%d)\n", - drive->name, - drive->cyl, drive->head, drive->sect); - - drive->dev_flags |= IDE_DFLAG_FORCED_GEOM | IDE_DFLAG_PRESENT; - drive->media = ide_disk; - drive->ready_stat = ATA_DRDY; - } -} - -static unsigned int ide_ignore_cable; - -static int ide_set_ignore_cable(const char *s, const struct kernel_param *kp) -{ - int i, j = 1; - - /* controller (ignore) */ - /* controller : 1 (ignore) | 0 (use) */ - if (sscanf(s, "%d:%d", &i, &j) != 2 && sscanf(s, "%d", &i) != 1) - return -EINVAL; - - if (i >= MAX_HWIFS || j < 0 || j > 1) - return -EINVAL; - - if (j) - ide_ignore_cable |= (1 << i); - else - ide_ignore_cable &= ~(1 << i); - - return 0; -} - -module_param_call(ignore_cable, ide_set_ignore_cable, NULL, NULL, 0); -MODULE_PARM_DESC(ignore_cable, "ignore cable detection"); - -void ide_port_apply_params(ide_hwif_t *hwif) -{ - ide_drive_t *drive; - int i; - - if (ide_ignore_cable & (1 << hwif->index)) { - printk(KERN_INFO "ide: ignoring cable detection for %s\n", - hwif->name); - hwif->cbl = ATA_CBL_PATA40_SHORT; - } - - ide_port_for_each_dev(i, drive, hwif) - ide_dev_apply_params(drive, i); -} - -/* - * This is gets invoked once during initialization, to set *everything* up - */ -static int __init ide_init(void) -{ - int ret; - - printk(KERN_INFO "Uniform Multi-Platform E-IDE driver\n"); - - ret = bus_register(&ide_bus_type); - if (ret < 0) { - printk(KERN_WARNING "IDE: bus_register error: %d\n", ret); - return ret; - } - - ide_port_class = class_create(THIS_MODULE, "ide_port"); - if (IS_ERR(ide_port_class)) { - ret = PTR_ERR(ide_port_class); - goto out_port_class; - } - - ide_acpi_init(); - - proc_ide_create(); - - return 0; - -out_port_class: - bus_unregister(&ide_bus_type); - - return ret; -} - -static void __exit ide_exit(void) -{ - proc_ide_destroy(); - - class_destroy(ide_port_class); - - bus_unregister(&ide_bus_type); -} - -module_init(ide_init); -module_exit(ide_exit); - -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ide_platform.c b/drivers/ide/ide_platform.c deleted file mode 100644 index 91639fd6c276..000000000000 --- a/drivers/ide/ide_platform.c +++ /dev/null @@ -1,133 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Platform IDE driver - * - * Copyright (C) 2007 MontaVista Software - * - * Maintainer: Kumar Gala - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void plat_ide_setup_ports(struct ide_hw *hw, void __iomem *base, - void __iomem *ctrl, - struct pata_platform_info *pdata, int irq) -{ - unsigned long port = (unsigned long)base; - int i; - - hw->io_ports.data_addr = port; - - port += (1 << pdata->ioport_shift); - for (i = 1; i <= 7; - i++, port += (1 << pdata->ioport_shift)) - hw->io_ports_array[i] = port; - - hw->io_ports.ctl_addr = (unsigned long)ctrl; - - hw->irq = irq; -} - -static const struct ide_port_info platform_ide_port_info = { - .host_flags = IDE_HFLAG_NO_DMA, - .chipset = ide_generic, -}; - -static int plat_ide_probe(struct platform_device *pdev) -{ - struct resource *res_base, *res_alt, *res_irq; - void __iomem *base, *alt_base; - struct pata_platform_info *pdata; - struct ide_host *host; - int ret = 0, mmio = 0; - struct ide_hw hw, *hws[] = { &hw }; - struct ide_port_info d = platform_ide_port_info; - - pdata = dev_get_platdata(&pdev->dev); - - /* get a pointer to the register memory */ - res_base = platform_get_resource(pdev, IORESOURCE_IO, 0); - res_alt = platform_get_resource(pdev, IORESOURCE_IO, 1); - - if (!res_base || !res_alt) { - res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); - res_alt = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res_base || !res_alt) { - ret = -ENOMEM; - goto out; - } - mmio = 1; - } - - res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res_irq) { - ret = -EINVAL; - goto out; - } - - if (mmio) { - base = devm_ioremap(&pdev->dev, - res_base->start, resource_size(res_base)); - alt_base = devm_ioremap(&pdev->dev, - res_alt->start, resource_size(res_alt)); - } else { - base = devm_ioport_map(&pdev->dev, - res_base->start, resource_size(res_base)); - alt_base = devm_ioport_map(&pdev->dev, - res_alt->start, resource_size(res_alt)); - } - - memset(&hw, 0, sizeof(hw)); - plat_ide_setup_ports(&hw, base, alt_base, pdata, res_irq->start); - hw.dev = &pdev->dev; - - d.irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; - if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE) - d.irq_flags |= IRQF_SHARED; - - if (mmio) - d.host_flags |= IDE_HFLAG_MMIO; - - ret = ide_host_add(&d, hws, 1, &host); - if (ret) - goto out; - - platform_set_drvdata(pdev, host); - - return 0; - -out: - return ret; -} - -static int plat_ide_remove(struct platform_device *pdev) -{ - struct ide_host *host = dev_get_drvdata(&pdev->dev); - - ide_host_remove(host); - - return 0; -} - -static struct platform_driver platform_ide_driver = { - .driver = { - .name = "pata_platform", - }, - .probe = plat_ide_probe, - .remove = plat_ide_remove, -}; - -module_platform_driver(platform_ide_driver); - -MODULE_DESCRIPTION("Platform IDE driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pata_platform"); diff --git a/drivers/ide/it8172.c b/drivers/ide/it8172.c deleted file mode 100644 index b6f674ab4fb7..000000000000 --- a/drivers/ide/it8172.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * IT8172 IDE controller support - * - * Copyright (C) 2000 MontaVista Software Inc. - * Copyright (C) 2008 Shane McDonald - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "IT8172" - -static void it8172_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u16 drive_enables; - u32 drive_timing; - const u8 pio = drive->pio_mode - XFER_PIO_0; - - /* - * The highest value of DIOR/DIOW pulse width and recovery time - * that can be set in the IT8172 is 8 PCI clock cycles. As a result, - * it cannot be configured for PIO mode 0. This table sets these - * parameters to the maximum supported by the IT8172. - */ - static const u8 timings[] = { 0x3f, 0x3c, 0x1b, 0x12, 0x0a }; - - pci_read_config_word(dev, 0x40, &drive_enables); - pci_read_config_dword(dev, 0x44, &drive_timing); - - /* - * Enable port 0x44. The IT8172 spec is confused; it calls - * this register the "Slave IDE Timing Register", but in fact, - * it controls timing for both master and slave drives. - */ - drive_enables |= 0x4000; - - drive_enables &= drive->dn ? 0xc006 : 0xc060; - if (drive->media == ide_disk) - /* enable prefetch */ - drive_enables |= 0x0004 << (drive->dn * 4); - if (ide_pio_need_iordy(drive, pio)) - /* enable IORDY sample-point */ - drive_enables |= 0x0002 << (drive->dn * 4); - - drive_timing &= drive->dn ? 0x00003f00 : 0x000fc000; - drive_timing |= timings[pio] << (drive->dn * 6 + 8); - - pci_write_config_word(dev, 0x40, drive_enables); - pci_write_config_dword(dev, 0x44, drive_timing); -} - -static void it8172_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - int a_speed = 3 << (drive->dn * 4); - int u_flag = 1 << drive->dn; - int u_speed = 0; - u8 reg48, reg4a; - const u8 speed = drive->dma_mode; - - pci_read_config_byte(dev, 0x48, ®48); - pci_read_config_byte(dev, 0x4a, ®4a); - - if (speed >= XFER_UDMA_0) { - u8 udma = speed - XFER_UDMA_0; - u_speed = udma << (drive->dn * 4); - - pci_write_config_byte(dev, 0x48, reg48 | u_flag); - reg4a &= ~a_speed; - pci_write_config_byte(dev, 0x4a, reg4a | u_speed); - } else { - const u8 mwdma_to_pio[] = { 0, 3, 4 }; - - pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); - pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed); - - drive->pio_mode = - mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0; - - it8172_set_pio_mode(hwif, drive); - } -} - - -static const struct ide_port_ops it8172_port_ops = { - .set_pio_mode = it8172_set_pio_mode, - .set_dma_mode = it8172_set_dma_mode, -}; - -static const struct ide_port_info it8172_port_info = { - .name = DRV_NAME, - .port_ops = &it8172_port_ops, - .enablebits = { {0x41, 0x80, 0x80}, {0x00, 0x00, 0x00} }, - .host_flags = IDE_HFLAG_SINGLE, - .pio_mask = ATA_PIO4 & ~ATA_PIO0, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA2, -}; - -static int it8172_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) - return -ENODEV; /* IT8172 is more than an IDE controller */ - return ide_pci_init_one(dev, &it8172_port_info, NULL); -} - -static struct pci_device_id it8172_pci_tbl[] = { - { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8172), 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, it8172_pci_tbl); - -static struct pci_driver it8172_pci_driver = { - .name = "IT8172_IDE", - .id_table = it8172_pci_tbl, - .probe = it8172_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init it8172_ide_init(void) -{ - return ide_pci_register_driver(&it8172_pci_driver); -} - -static void __exit it8172_ide_exit(void) -{ - pci_unregister_driver(&it8172_pci_driver); -} - -module_init(it8172_ide_init); -module_exit(it8172_ide_exit); - -MODULE_AUTHOR("Steve Longerbeam"); -MODULE_DESCRIPTION("PCI driver module for ITE 8172 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/it8213.c b/drivers/ide/it8213.c deleted file mode 100644 index d0bf4430c437..000000000000 --- a/drivers/ide/it8213.c +++ /dev/null @@ -1,217 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * ITE 8213 IDE driver - * - * Copyright (C) 2006 Jack Lee - * Copyright (C) 2006 Alan Cox - * Copyright (C) 2007 Bartlomiej Zolnierkiewicz - */ - -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "it8213" - -/** - * it8213_set_pio_mode - set host controller for PIO mode - * @hwif: port - * @drive: drive - * - * Set the interface PIO mode. - */ - -static void it8213_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - int is_slave = drive->dn & 1; - int master_port = 0x40; - int slave_port = 0x44; - unsigned long flags; - u16 master_data; - u8 slave_data; - static DEFINE_SPINLOCK(tune_lock); - int control = 0; - const u8 pio = drive->pio_mode - XFER_PIO_0; - - static const u8 timings[][2] = { - { 0, 0 }, - { 0, 0 }, - { 1, 0 }, - { 2, 1 }, - { 2, 3 }, }; - - spin_lock_irqsave(&tune_lock, flags); - pci_read_config_word(dev, master_port, &master_data); - - if (pio > 1) - control |= 1; /* Programmable timing on */ - if (drive->media != ide_disk) - control |= 4; /* ATAPI */ - if (ide_pio_need_iordy(drive, pio)) - control |= 2; /* IORDY */ - if (is_slave) { - master_data |= 0x4000; - master_data &= ~0x0070; - if (pio > 1) - master_data = master_data | (control << 4); - pci_read_config_byte(dev, slave_port, &slave_data); - slave_data = slave_data & 0xf0; - slave_data = slave_data | (timings[pio][0] << 2) | timings[pio][1]; - } else { - master_data &= ~0x3307; - if (pio > 1) - master_data = master_data | control; - master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8); - } - pci_write_config_word(dev, master_port, master_data); - if (is_slave) - pci_write_config_byte(dev, slave_port, slave_data); - spin_unlock_irqrestore(&tune_lock, flags); -} - -/** - * it8213_set_dma_mode - set host controller for DMA mode - * @hwif: port - * @drive: drive - * - * Tune the ITE chipset for the DMA mode. - */ - -static void it8213_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 maslave = 0x40; - int a_speed = 3 << (drive->dn * 4); - int u_flag = 1 << drive->dn; - int v_flag = 0x01 << drive->dn; - int w_flag = 0x10 << drive->dn; - int u_speed = 0; - u16 reg4042, reg4a; - u8 reg48, reg54, reg55; - const u8 speed = drive->dma_mode; - - pci_read_config_word(dev, maslave, ®4042); - pci_read_config_byte(dev, 0x48, ®48); - pci_read_config_word(dev, 0x4a, ®4a); - pci_read_config_byte(dev, 0x54, ®54); - pci_read_config_byte(dev, 0x55, ®55); - - if (speed >= XFER_UDMA_0) { - u8 udma = speed - XFER_UDMA_0; - - u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4); - - if (!(reg48 & u_flag)) - pci_write_config_byte(dev, 0x48, reg48 | u_flag); - if (speed >= XFER_UDMA_5) - pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); - else - pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); - - if ((reg4a & a_speed) != u_speed) - pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); - if (speed > XFER_UDMA_2) { - if (!(reg54 & v_flag)) - pci_write_config_byte(dev, 0x54, reg54 | v_flag); - } else - pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); - } else { - const u8 mwdma_to_pio[] = { 0, 3, 4 }; - - if (reg48 & u_flag) - pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); - if (reg4a & a_speed) - pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - if (reg54 & v_flag) - pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); - if (reg55 & w_flag) - pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); - - if (speed >= XFER_MW_DMA_0) - drive->pio_mode = - mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0; - else - drive->pio_mode = XFER_PIO_2; /* for SWDMA2 */ - - it8213_set_pio_mode(hwif, drive); - } -} - -static u8 it8213_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 reg42h = 0; - - pci_read_config_byte(dev, 0x42, ®42h); - - return (reg42h & 0x02) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; -} - -static const struct ide_port_ops it8213_port_ops = { - .set_pio_mode = it8213_set_pio_mode, - .set_dma_mode = it8213_set_dma_mode, - .cable_detect = it8213_cable_detect, -}; - -static const struct ide_port_info it8213_chipset = { - .name = DRV_NAME, - .enablebits = { {0x41, 0x80, 0x80} }, - .port_ops = &it8213_port_ops, - .host_flags = IDE_HFLAG_SINGLE, - .pio_mask = ATA_PIO4, - .swdma_mask = ATA_SWDMA2_ONLY, - .mwdma_mask = ATA_MWDMA12_ONLY, - .udma_mask = ATA_UDMA6, -}; - -/** - * it8213_init_one - pci layer discovery entry - * @dev: PCI device - * @id: ident table entry - * - * Called by the PCI code when it finds an ITE8213 controller. As - * this device follows the standard interfaces we can use the - * standard helper functions to do almost all the work for us. - */ - -static int it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_pci_init_one(dev, &it8213_chipset, NULL); -} - -static const struct pci_device_id it8213_pci_tbl[] = { - { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8213), 0 }, - { 0, }, -}; - -MODULE_DEVICE_TABLE(pci, it8213_pci_tbl); - -static struct pci_driver it8213_pci_driver = { - .name = "ITE8213_IDE", - .id_table = it8213_pci_tbl, - .probe = it8213_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init it8213_ide_init(void) -{ - return ide_pci_register_driver(&it8213_pci_driver); -} - -static void __exit it8213_ide_exit(void) -{ - pci_unregister_driver(&it8213_pci_driver); -} - -module_init(it8213_ide_init); -module_exit(it8213_ide_exit); - -MODULE_AUTHOR("Jack Lee, Alan Cox"); -MODULE_DESCRIPTION("PCI driver module for the ITE 8213"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/it821x.c b/drivers/ide/it821x.c deleted file mode 100644 index 36a64c8ea575..000000000000 --- a/drivers/ide/it821x.c +++ /dev/null @@ -1,715 +0,0 @@ -/* - * Copyright (C) 2004 Red Hat - * Copyright (C) 2007 Bartlomiej Zolnierkiewicz - * - * May be copied or modified under the terms of the GNU General Public License - * Based in part on the ITE vendor provided SCSI driver. - * - * Documentation: - * Datasheet is freely available, some other documents under NDA. - * - * The ITE8212 isn't exactly a standard IDE controller. It has two - * modes. In pass through mode then it is an IDE controller. In its smart - * mode its actually quite a capable hardware raid controller disguised - * as an IDE controller. Smart mode only understands DMA read/write and - * identify, none of the fancier commands apply. The IT8211 is identical - * in other respects but lacks the raid mode. - * - * Errata: - * o Rev 0x10 also requires master/slave hold the same DMA timings and - * cannot do ATAPI MWDMA. - * o The identify data for raid volumes lacks CHS info (technically ok) - * but also fails to set the LBA28 and other bits. We fix these in - * the IDE probe quirk code. - * o If you write LBA48 sized I/O's (ie > 256 sector) in smart mode - * raid then the controller firmware dies - * o Smart mode without RAID doesn't clear all the necessary identify - * bits to reduce the command set to the one used - * - * This has a few impacts on the driver - * - In pass through mode we do all the work you would expect - * - In smart mode the clocking set up is done by the controller generally - * but we must watch the other limits and filter. - * - There are a few extra vendor commands that actually talk to the - * controller but only work PIO with no IRQ. - * - * Vendor areas of the identify block in smart mode are used for the - * timing and policy set up. Each HDD in raid mode also has a serial - * block on the disk. The hardware extra commands are get/set chip status, - * rebuild, get rebuild status. - * - * In Linux the driver supports pass through mode as if the device was - * just another IDE controller. If the smart mode is running then - * volumes are managed by the controller firmware and each IDE "disk" - * is a raid volume. Even more cute - the controller can do automated - * hotplug and rebuild. - * - * The pass through controller itself is a little demented. It has a - * flaw that it has a single set of PIO/MWDMA timings per channel so - * non UDMA devices restrict each others performance. It also has a - * single clock source per channel so mixed UDMA100/133 performance - * isn't perfect and we have to pick a clock. Thankfully none of this - * matters in smart mode. ATAPI DMA is not currently supported. - * - * It seems the smart mode is a win for RAID1/RAID10 but otherwise not. - * - * TODO - * - ATAPI UDMA is ok but not MWDMA it seems - * - RAID configuration ioctls - * - Move to libata once it grows up - */ - -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "it821x" - -#define QUIRK_VORTEX86 1 - -struct it821x_dev -{ - unsigned int smart:1, /* Are we in smart raid mode */ - timing10:1; /* Rev 0x10 */ - u8 clock_mode; /* 0, ATA_50 or ATA_66 */ - u8 want[2][2]; /* Mode/Pri log for master slave */ - /* We need these for switching the clock when DMA goes on/off - The high byte is the 66Mhz timing */ - u16 pio[2]; /* Cached PIO values */ - u16 mwdma[2]; /* Cached MWDMA values */ - u16 udma[2]; /* Cached UDMA values (per drive) */ - u16 quirks; -}; - -#define ATA_66 0 -#define ATA_50 1 -#define ATA_ANY 2 - -#define UDMA_OFF 0 -#define MWDMA_OFF 0 - -/* - * We allow users to force the card into non raid mode without - * flashing the alternative BIOS. This is also necessary right now - * for embedded platforms that cannot run a PC BIOS but are using this - * device. - */ - -static int it8212_noraid; - -/** - * it821x_program - program the PIO/MWDMA registers - * @drive: drive to tune - * @timing: timing info - * - * Program the PIO/MWDMA timing for this channel according to the - * current clock. - */ - -static void it821x_program(ide_drive_t *drive, u16 timing) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - struct it821x_dev *itdev = ide_get_hwifdata(hwif); - int channel = hwif->channel; - u8 conf; - - /* Program PIO/MWDMA timing bits */ - if(itdev->clock_mode == ATA_66) - conf = timing >> 8; - else - conf = timing & 0xFF; - - pci_write_config_byte(dev, 0x54 + 4 * channel, conf); -} - -/** - * it821x_program_udma - program the UDMA registers - * @drive: drive to tune - * @timing: timing info - * - * Program the UDMA timing for this drive according to the - * current clock. - */ - -static void it821x_program_udma(ide_drive_t *drive, u16 timing) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - struct it821x_dev *itdev = ide_get_hwifdata(hwif); - int channel = hwif->channel; - u8 unit = drive->dn & 1, conf; - - /* Program UDMA timing bits */ - if(itdev->clock_mode == ATA_66) - conf = timing >> 8; - else - conf = timing & 0xFF; - - if (itdev->timing10 == 0) - pci_write_config_byte(dev, 0x56 + 4 * channel + unit, conf); - else { - pci_write_config_byte(dev, 0x56 + 4 * channel, conf); - pci_write_config_byte(dev, 0x56 + 4 * channel + 1, conf); - } -} - -/** - * it821x_clock_strategy - * @drive: drive to set up - * - * Select between the 50 and 66Mhz base clocks to get the best - * results for this interface. - */ - -static void it821x_clock_strategy(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - struct it821x_dev *itdev = ide_get_hwifdata(hwif); - ide_drive_t *pair = ide_get_pair_dev(drive); - int clock, altclock, sel = 0; - u8 unit = drive->dn & 1, v; - - if(itdev->want[0][0] > itdev->want[1][0]) { - clock = itdev->want[0][1]; - altclock = itdev->want[1][1]; - } else { - clock = itdev->want[1][1]; - altclock = itdev->want[0][1]; - } - - /* - * if both clocks can be used for the mode with the higher priority - * use the clock needed by the mode with the lower priority - */ - if (clock == ATA_ANY) - clock = altclock; - - /* Nobody cares - keep the same clock */ - if(clock == ATA_ANY) - return; - /* No change */ - if(clock == itdev->clock_mode) - return; - - /* Load this into the controller ? */ - if(clock == ATA_66) - itdev->clock_mode = ATA_66; - else { - itdev->clock_mode = ATA_50; - sel = 1; - } - - pci_read_config_byte(dev, 0x50, &v); - v &= ~(1 << (1 + hwif->channel)); - v |= sel << (1 + hwif->channel); - pci_write_config_byte(dev, 0x50, v); - - /* - * Reprogram the UDMA/PIO of the pair drive for the switch - * MWDMA will be dealt with by the dma switcher - */ - if(pair && itdev->udma[1-unit] != UDMA_OFF) { - it821x_program_udma(pair, itdev->udma[1-unit]); - it821x_program(pair, itdev->pio[1-unit]); - } - /* - * Reprogram the UDMA/PIO of our drive for the switch. - * MWDMA will be dealt with by the dma switcher - */ - if(itdev->udma[unit] != UDMA_OFF) { - it821x_program_udma(drive, itdev->udma[unit]); - it821x_program(drive, itdev->pio[unit]); - } -} - -/** - * it821x_set_pio_mode - set host controller for PIO mode - * @hwif: port - * @drive: drive - * - * Tune the host to the desired PIO mode taking into the consideration - * the maximum PIO mode supported by the other device on the cable. - */ - -static void it821x_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct it821x_dev *itdev = ide_get_hwifdata(hwif); - ide_drive_t *pair = ide_get_pair_dev(drive); - const u8 pio = drive->pio_mode - XFER_PIO_0; - u8 unit = drive->dn & 1, set_pio = pio; - - /* Spec says 89 ref driver uses 88 */ - static u16 pio_timings[]= { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 }; - static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY }; - - /* - * Compute the best PIO mode we can for a given device. We must - * pick a speed that does not cause problems with the other device - * on the cable. - */ - if (pair) { - u8 pair_pio = pair->pio_mode - XFER_PIO_0; - /* trim PIO to the slowest of the master/slave */ - if (pair_pio < set_pio) - set_pio = pair_pio; - } - - /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */ - itdev->want[unit][1] = pio_want[set_pio]; - itdev->want[unit][0] = 1; /* PIO is lowest priority */ - itdev->pio[unit] = pio_timings[set_pio]; - it821x_clock_strategy(drive); - it821x_program(drive, itdev->pio[unit]); -} - -/** - * it821x_tune_mwdma - tune a channel for MWDMA - * @drive: drive to set up - * @mode_wanted: the target operating mode - * - * Load the timing settings for this device mode into the - * controller when doing MWDMA in pass through mode. The caller - * must manage the whole lack of per device MWDMA/PIO timings and - * the shared MWDMA/PIO timing register. - */ - -static void it821x_tune_mwdma(ide_drive_t *drive, u8 mode_wanted) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - struct it821x_dev *itdev = (void *)ide_get_hwifdata(hwif); - u8 unit = drive->dn & 1, channel = hwif->channel, conf; - - static u16 dma[] = { 0x8866, 0x3222, 0x3121 }; - static u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY }; - - itdev->want[unit][1] = mwdma_want[mode_wanted]; - itdev->want[unit][0] = 2; /* MWDMA is low priority */ - itdev->mwdma[unit] = dma[mode_wanted]; - itdev->udma[unit] = UDMA_OFF; - - /* UDMA bits off - Revision 0x10 do them in pairs */ - pci_read_config_byte(dev, 0x50, &conf); - if (itdev->timing10) - conf |= channel ? 0x60: 0x18; - else - conf |= 1 << (3 + 2 * channel + unit); - pci_write_config_byte(dev, 0x50, conf); - - it821x_clock_strategy(drive); - /* FIXME: do we need to program this ? */ - /* it821x_program(drive, itdev->mwdma[unit]); */ -} - -/** - * it821x_tune_udma - tune a channel for UDMA - * @drive: drive to set up - * @mode_wanted: the target operating mode - * - * Load the timing settings for this device mode into the - * controller when doing UDMA modes in pass through. - */ - -static void it821x_tune_udma(ide_drive_t *drive, u8 mode_wanted) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - struct it821x_dev *itdev = ide_get_hwifdata(hwif); - u8 unit = drive->dn & 1, channel = hwif->channel, conf; - - static u16 udma[] = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 }; - static u8 udma_want[] = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 }; - - itdev->want[unit][1] = udma_want[mode_wanted]; - itdev->want[unit][0] = 3; /* UDMA is high priority */ - itdev->mwdma[unit] = MWDMA_OFF; - itdev->udma[unit] = udma[mode_wanted]; - if(mode_wanted >= 5) - itdev->udma[unit] |= 0x8080; /* UDMA 5/6 select on */ - - /* UDMA on. Again revision 0x10 must do the pair */ - pci_read_config_byte(dev, 0x50, &conf); - if (itdev->timing10) - conf &= channel ? 0x9F: 0xE7; - else - conf &= ~ (1 << (3 + 2 * channel + unit)); - pci_write_config_byte(dev, 0x50, conf); - - it821x_clock_strategy(drive); - it821x_program_udma(drive, itdev->udma[unit]); - -} - -/** - * it821x_dma_read - DMA hook - * @drive: drive for DMA - * - * The IT821x has a single timing register for MWDMA and for PIO - * operations. As we flip back and forth we have to reload the - * clock. In addition the rev 0x10 device only works if the same - * timing value is loaded into the master and slave UDMA clock - * so we must also reload that. - * - * FIXME: we could figure out in advance if we need to do reloads - */ - -static void it821x_dma_start(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct it821x_dev *itdev = ide_get_hwifdata(hwif); - u8 unit = drive->dn & 1; - - if(itdev->mwdma[unit] != MWDMA_OFF) - it821x_program(drive, itdev->mwdma[unit]); - else if(itdev->udma[unit] != UDMA_OFF && itdev->timing10) - it821x_program_udma(drive, itdev->udma[unit]); - ide_dma_start(drive); -} - -/** - * it821x_dma_write - DMA hook - * @drive: drive for DMA stop - * - * The IT821x has a single timing register for MWDMA and for PIO - * operations. As we flip back and forth we have to reload the - * clock. - */ - -static int it821x_dma_end(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct it821x_dev *itdev = ide_get_hwifdata(hwif); - int ret = ide_dma_end(drive); - u8 unit = drive->dn & 1; - - if(itdev->mwdma[unit] != MWDMA_OFF) - it821x_program(drive, itdev->pio[unit]); - return ret; -} - -/** - * it821x_set_dma_mode - set host controller for DMA mode - * @hwif: port - * @drive: drive - * - * Tune the ITE chipset for the desired DMA mode. - */ - -static void it821x_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - const u8 speed = drive->dma_mode; - - /* - * MWDMA tuning is really hard because our MWDMA and PIO - * timings are kept in the same place. We can switch in the - * host dma on/off callbacks. - */ - if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_6) - it821x_tune_udma(drive, speed - XFER_UDMA_0); - else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) - it821x_tune_mwdma(drive, speed - XFER_MW_DMA_0); -} - -/** - * it821x_cable_detect - cable detection - * @hwif: interface to check - * - * Check for the presence of an ATA66 capable cable on the - * interface. Problematic as it seems some cards don't have - * the needed logic onboard. - */ - -static u8 it821x_cable_detect(ide_hwif_t *hwif) -{ - /* The reference driver also only does disk side */ - return ATA_CBL_PATA80; -} - -/** - * it821x_quirkproc - post init callback - * @drive: drive - * - * This callback is run after the drive has been probed but - * before anything gets attached. It allows drivers to do any - * final tuning that is needed, or fixups to work around bugs. - */ - -static void it821x_quirkproc(ide_drive_t *drive) -{ - struct it821x_dev *itdev = ide_get_hwifdata(drive->hwif); - u16 *id = drive->id; - - if (!itdev->smart) { - /* - * If we are in pass through mode then not much - * needs to be done, but we do bother to clear the - * IRQ mask as we may well be in PIO (eg rev 0x10) - * for now and we know unmasking is safe on this chipset. - */ - drive->dev_flags |= IDE_DFLAG_UNMASK; - } else { - /* - * Perform fixups on smart mode. We need to "lose" some - * capabilities the firmware lacks but does not filter, and - * also patch up some capability bits that it forgets to set - * in RAID mode. - */ - - /* Check for RAID v native */ - if (strstr((char *)&id[ATA_ID_PROD], - "Integrated Technology Express")) { - /* In raid mode the ident block is slightly buggy - We need to set the bits so that the IDE layer knows - LBA28. LBA48 and DMA ar valid */ - id[ATA_ID_CAPABILITY] |= (3 << 8); /* LBA28, DMA */ - id[ATA_ID_COMMAND_SET_2] |= 0x0400; /* LBA48 valid */ - id[ATA_ID_CFS_ENABLE_2] |= 0x0400; /* LBA48 on */ - /* Reporting logic */ - printk(KERN_INFO "%s: IT8212 %sRAID %d volume", - drive->name, id[147] ? "Bootable " : "", - id[ATA_ID_CSFO]); - if (id[ATA_ID_CSFO] != 1) - printk(KERN_CONT "(%dK stripe)", id[146]); - printk(KERN_CONT ".\n"); - } else { - /* Non RAID volume. Fixups to stop the core code - doing unsupported things */ - id[ATA_ID_FIELD_VALID] &= 3; - id[ATA_ID_QUEUE_DEPTH] = 0; - id[ATA_ID_COMMAND_SET_1] = 0; - id[ATA_ID_COMMAND_SET_2] &= 0xC400; - id[ATA_ID_CFSSE] &= 0xC000; - id[ATA_ID_CFS_ENABLE_1] = 0; - id[ATA_ID_CFS_ENABLE_2] &= 0xC400; - id[ATA_ID_CSF_DEFAULT] &= 0xC000; - id[127] = 0; - id[ATA_ID_DLF] = 0; - id[ATA_ID_CSFO] = 0; - id[ATA_ID_CFA_POWER] = 0; - printk(KERN_INFO "%s: Performing identify fixups.\n", - drive->name); - } - - /* - * Set MWDMA0 mode as enabled/support - just to tell - * IDE core that DMA is supported (it821x hardware - * takes care of DMA mode programming). - */ - if (ata_id_has_dma(id)) { - id[ATA_ID_MWDMA_MODES] |= 0x0101; - drive->current_speed = XFER_MW_DMA_0; - } - } - -} - -static const struct ide_dma_ops it821x_pass_through_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = it821x_dma_start, - .dma_end = it821x_dma_end, - .dma_test_irq = ide_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = ide_dma_sff_read_status, -}; - -/** - * init_hwif_it821x - set up hwif structs - * @hwif: interface to set up - * - * We do the basic set up of the interface structure. The IT8212 - * requires several custom handlers so we override the default - * ide DMA handlers appropriately - */ - -static void init_hwif_it821x(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - struct ide_host *host = pci_get_drvdata(dev); - struct it821x_dev *itdevs = host->host_priv; - struct it821x_dev *idev = itdevs + hwif->channel; - u8 conf; - - ide_set_hwifdata(hwif, idev); - - pci_read_config_byte(dev, 0x50, &conf); - if (conf & 1) { - idev->smart = 1; - hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA; - /* Long I/O's although allowed in LBA48 space cause the - onboard firmware to enter the twighlight zone */ - hwif->rqsize = 256; - } - - /* Pull the current clocks from 0x50 also */ - if (conf & (1 << (1 + hwif->channel))) - idev->clock_mode = ATA_50; - else - idev->clock_mode = ATA_66; - - idev->want[0][1] = ATA_ANY; - idev->want[1][1] = ATA_ANY; - - /* - * Not in the docs but according to the reference driver - * this is necessary. - */ - - if (dev->revision == 0x10) { - idev->timing10 = 1; - hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA; - if (idev->smart == 0) - printk(KERN_WARNING DRV_NAME " %s: revision 0x10, " - "workarounds activated\n", pci_name(dev)); - } - - if (idev->smart == 0) { - /* MWDMA/PIO clock switching for pass through mode */ - hwif->dma_ops = &it821x_pass_through_dma_ops; - } else - hwif->host_flags |= IDE_HFLAG_NO_SET_MODE; - - if (hwif->dma_base == 0) - return; - - hwif->ultra_mask = ATA_UDMA6; - hwif->mwdma_mask = ATA_MWDMA2; - - /* Vortex86SX quirk: prevent Ultra-DMA mode to fix BadCRC issue */ - if (idev->quirks & QUIRK_VORTEX86) { - if (dev->revision == 0x11) - hwif->ultra_mask = 0; - } -} - -static void it8212_disable_raid(struct pci_dev *dev) -{ - /* Reset local CPU, and set BIOS not ready */ - pci_write_config_byte(dev, 0x5E, 0x01); - - /* Set to bypass mode, and reset PCI bus */ - pci_write_config_byte(dev, 0x50, 0x00); - pci_write_config_word(dev, PCI_COMMAND, - PCI_COMMAND_PARITY | PCI_COMMAND_IO | - PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - pci_write_config_word(dev, 0x40, 0xA0F3); - - pci_write_config_dword(dev,0x4C, 0x02040204); - pci_write_config_byte(dev, 0x42, 0x36); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); -} - -static int init_chipset_it821x(struct pci_dev *dev) -{ - u8 conf; - static char *mode[2] = { "pass through", "smart" }; - - /* Force the card into bypass mode if so requested */ - if (it8212_noraid) { - printk(KERN_INFO DRV_NAME " %s: forcing bypass mode\n", - pci_name(dev)); - it8212_disable_raid(dev); - } - pci_read_config_byte(dev, 0x50, &conf); - printk(KERN_INFO DRV_NAME " %s: controller in %s mode\n", - pci_name(dev), mode[conf & 1]); - return 0; -} - -static const struct ide_port_ops it821x_port_ops = { - /* it821x_set_{pio,dma}_mode() are only used in pass-through mode */ - .set_pio_mode = it821x_set_pio_mode, - .set_dma_mode = it821x_set_dma_mode, - .quirkproc = it821x_quirkproc, - .cable_detect = it821x_cable_detect, -}; - -static const struct ide_port_info it821x_chipset = { - .name = DRV_NAME, - .init_chipset = init_chipset_it821x, - .init_hwif = init_hwif_it821x, - .port_ops = &it821x_port_ops, - .pio_mask = ATA_PIO4, -}; - -/** - * it821x_init_one - pci layer discovery entry - * @dev: PCI device - * @id: ident table entry - * - * Called by the PCI code when it finds an ITE821x controller. - * We then use the IDE PCI generic helper to do most of the work. - */ - -static int it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct it821x_dev *itdevs; - int rc; - - itdevs = kcalloc(2, sizeof(*itdevs), GFP_KERNEL); - if (itdevs == NULL) { - printk(KERN_ERR DRV_NAME " %s: out of memory\n", pci_name(dev)); - return -ENOMEM; - } - - itdevs->quirks = id->driver_data; - - rc = ide_pci_init_one(dev, &it821x_chipset, itdevs); - if (rc) - kfree(itdevs); - - return rc; -} - -static void it821x_remove(struct pci_dev *dev) -{ - struct ide_host *host = pci_get_drvdata(dev); - struct it821x_dev *itdevs = host->host_priv; - - ide_pci_remove(dev); - kfree(itdevs); -} - -static const struct pci_device_id it821x_pci_tbl[] = { - { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), 0 }, - { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), 0 }, - { PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1010), QUIRK_VORTEX86 }, - { 0, }, -}; - -MODULE_DEVICE_TABLE(pci, it821x_pci_tbl); - -static struct pci_driver it821x_pci_driver = { - .name = "ITE821x IDE", - .id_table = it821x_pci_tbl, - .probe = it821x_init_one, - .remove = it821x_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init it821x_ide_init(void) -{ - return ide_pci_register_driver(&it821x_pci_driver); -} - -static void __exit it821x_ide_exit(void) -{ - pci_unregister_driver(&it821x_pci_driver); -} - -module_init(it821x_ide_init); -module_exit(it821x_ide_exit); - -module_param_named(noraid, it8212_noraid, int, S_IRUGO); -MODULE_PARM_DESC(noraid, "Force card into bypass mode"); - -MODULE_AUTHOR("Alan Cox"); -MODULE_DESCRIPTION("PCI driver module for the ITE 821x"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/jmicron.c b/drivers/ide/jmicron.c deleted file mode 100644 index ae6480dcbadf..000000000000 --- a/drivers/ide/jmicron.c +++ /dev/null @@ -1,176 +0,0 @@ - -/* - * Copyright (C) 2006 Red Hat - * - * May be copied or modified under the terms of the GNU General Public License - */ - -#include -#include -#include -#include -#include - -#define DRV_NAME "jmicron" - -typedef enum { - PORT_PATA0 = 0, - PORT_PATA1 = 1, - PORT_SATA = 2, -} port_type; - -/** - * jmicron_cable_detect - cable detection - * @hwif: IDE port - * - * Returns the cable type. - */ - -static u8 jmicron_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *pdev = to_pci_dev(hwif->dev); - - u32 control; - u32 control5; - - int port = hwif->channel; - port_type port_map[2]; - - pci_read_config_dword(pdev, 0x40, &control); - - /* There are two basic mappings. One has the two SATA ports merged - as master/slave and the secondary as PATA, the other has only the - SATA port mapped */ - if (control & (1 << 23)) { - port_map[0] = PORT_SATA; - port_map[1] = PORT_PATA0; - } else { - port_map[0] = PORT_SATA; - port_map[1] = PORT_SATA; - } - - /* The 365/366 may have this bit set to map the second PATA port - as the internal primary channel */ - pci_read_config_dword(pdev, 0x80, &control5); - if (control5 & (1<<24)) - port_map[0] = PORT_PATA1; - - /* The two ports may then be logically swapped by the firmware */ - if (control & (1 << 22)) - port = port ^ 1; - - /* - * Now we know which physical port we are talking about we can - * actually do our cable checking etc. Thankfully we don't need - * to do the plumbing for other cases. - */ - switch (port_map[port]) { - case PORT_PATA0: - if (control & (1 << 3)) /* 40/80 pin primary */ - return ATA_CBL_PATA40; - return ATA_CBL_PATA80; - case PORT_PATA1: - if (control5 & (1 << 19)) /* 40/80 pin secondary */ - return ATA_CBL_PATA40; - return ATA_CBL_PATA80; - case PORT_SATA: - break; - } - /* Avoid bogus "control reaches end of non-void function" */ - return ATA_CBL_PATA80; -} - -static void jmicron_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ -} - -/** - * jmicron_set_dma_mode - set host controller for DMA mode - * @hwif: port - * @drive: drive - * - * As the JMicron snoops for timings we don't need to do anything here. - */ - -static void jmicron_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ -} - -static const struct ide_port_ops jmicron_port_ops = { - .set_pio_mode = jmicron_set_pio_mode, - .set_dma_mode = jmicron_set_dma_mode, - .cable_detect = jmicron_cable_detect, -}; - -static const struct ide_port_info jmicron_chipset = { - .name = DRV_NAME, - .enablebits = { { 0x40, 0x01, 0x01 }, { 0x40, 0x10, 0x10 } }, - .port_ops = &jmicron_port_ops, - .pio_mask = ATA_PIO5, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA6, -}; - -/** - * jmicron_init_one - pci layer discovery entry - * @dev: PCI device - * @id: ident table entry - * - * Called by the PCI code when it finds a Jmicron controller. - * We then use the IDE PCI generic helper to do most of the work. - */ - -static int jmicron_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_pci_init_one(dev, &jmicron_chipset, NULL); -} - -/* All JMB PATA controllers have and will continue to have the same - * interface. Matching vendor and device class is enough for all - * current and future controllers if the controller is programmed - * properly. - * - * If libata is configured, jmicron PCI quirk programs the controller - * into the correct mode. If libata isn't configured, match known - * device IDs too to maintain backward compatibility. - */ -static struct pci_device_id jmicron_pci_tbl[] = { -#if !defined(CONFIG_ATA) && !defined(CONFIG_ATA_MODULE) - { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361) }, - { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363) }, - { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365) }, - { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366) }, - { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368) }, -#endif - { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 }, - { 0, }, -}; - -MODULE_DEVICE_TABLE(pci, jmicron_pci_tbl); - -static struct pci_driver jmicron_pci_driver = { - .name = "JMicron IDE", - .id_table = jmicron_pci_tbl, - .probe = jmicron_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init jmicron_ide_init(void) -{ - return ide_pci_register_driver(&jmicron_pci_driver); -} - -static void __exit jmicron_ide_exit(void) -{ - pci_unregister_driver(&jmicron_pci_driver); -} - -module_init(jmicron_ide_init); -module_exit(jmicron_ide_exit); - -MODULE_AUTHOR("Alan Cox"); -MODULE_DESCRIPTION("PCI driver module for the JMicron in legacy modes"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c deleted file mode 100644 index 11a672aba6ee..000000000000 --- a/drivers/ide/ns87415.c +++ /dev/null @@ -1,350 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1997-1998 Mark Lord - * Copyright (C) 1998 Eddie C. Dost - * Copyright (C) 1999-2000 Andre Hedrick - * Copyright (C) 2004 Grant Grundler - * - * Inspired by an earlier effort from David S. Miller - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "ns87415" - -#ifdef CONFIG_SUPERIO -/* SUPERIO 87560 is a PoS chip that NatSem denies exists. - * Unfortunately, it's built-in on all Astro-based PA-RISC workstations - * which use the integrated NS87514 cell for CD-ROM support. - * i.e we have to support for CD-ROM installs. - * See drivers/parisc/superio.c for more gory details. - */ -#include - -#define SUPERIO_IDE_MAX_RETRIES 25 - -/* Because of a defect in Super I/O, all reads of the PCI DMA status - * registers, IDE status register and the IDE select register need to be - * retried - */ -static u8 superio_ide_inb (unsigned long port) -{ - u8 tmp; - int retries = SUPERIO_IDE_MAX_RETRIES; - - /* printk(" [ reading port 0x%x with retry ] ", port); */ - - do { - tmp = inb(port); - if (tmp == 0) - udelay(50); - } while (tmp == 0 && retries-- > 0); - - return tmp; -} - -static u8 superio_read_status(ide_hwif_t *hwif) -{ - return superio_ide_inb(hwif->io_ports.status_addr); -} - -static u8 superio_dma_sff_read_status(ide_hwif_t *hwif) -{ - return superio_ide_inb(hwif->dma_base + ATA_DMA_STATUS); -} - -static void superio_tf_read(ide_drive_t *drive, struct ide_taskfile *tf, - u8 valid) -{ - struct ide_io_ports *io_ports = &drive->hwif->io_ports; - - if (valid & IDE_VALID_ERROR) - tf->error = inb(io_ports->feature_addr); - if (valid & IDE_VALID_NSECT) - tf->nsect = inb(io_ports->nsect_addr); - if (valid & IDE_VALID_LBAL) - tf->lbal = inb(io_ports->lbal_addr); - if (valid & IDE_VALID_LBAM) - tf->lbam = inb(io_ports->lbam_addr); - if (valid & IDE_VALID_LBAH) - tf->lbah = inb(io_ports->lbah_addr); - if (valid & IDE_VALID_DEVICE) - tf->device = superio_ide_inb(io_ports->device_addr); -} - -static void ns87415_dev_select(ide_drive_t *drive); - -static const struct ide_tp_ops superio_tp_ops = { - .exec_command = ide_exec_command, - .read_status = superio_read_status, - .read_altstatus = ide_read_altstatus, - .write_devctl = ide_write_devctl, - - .dev_select = ns87415_dev_select, - .tf_load = ide_tf_load, - .tf_read = superio_tf_read, - - .input_data = ide_input_data, - .output_data = ide_output_data, -}; - -static void superio_init_iops(struct hwif_s *hwif) -{ - struct pci_dev *pdev = to_pci_dev(hwif->dev); - u32 dma_stat; - u8 port = hwif->channel, tmp; - - dma_stat = (pci_resource_start(pdev, 4) & ~3) + (!port ? 2 : 0xa); - - /* Clear error/interrupt, enable dma */ - tmp = superio_ide_inb(dma_stat); - outb(tmp | 0x66, dma_stat); -} -#else -#define superio_dma_sff_read_status ide_dma_sff_read_status -#endif - -static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 }; - -/* - * This routine either enables/disables (according to IDE_DFLAG_PRESENT) - * the IRQ associated with the port, - * and selects either PIO or DMA handshaking for the next I/O operation. - */ -static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data; - unsigned long flags; - - local_irq_save(flags); - new = *old; - - /* Adjust IRQ enable bit */ - bit = 1 << (8 + hwif->channel); - - if (drive->dev_flags & IDE_DFLAG_PRESENT) - new &= ~bit; - else - new |= bit; - - /* Select PIO or DMA, DMA may only be selected for one drive/channel. */ - bit = 1 << (20 + (drive->dn & 1) + (hwif->channel << 1)); - other = 1 << (20 + (1 - (drive->dn & 1)) + (hwif->channel << 1)); - new = use_dma ? ((new & ~other) | bit) : (new & ~bit); - - if (new != *old) { - unsigned char stat; - - /* - * Don't change DMA engine settings while Write Buffers - * are busy. - */ - (void) pci_read_config_byte(dev, 0x43, &stat); - while (stat & 0x03) { - udelay(1); - (void) pci_read_config_byte(dev, 0x43, &stat); - } - - *old = new; - (void) pci_write_config_dword(dev, 0x40, new); - - /* - * And let things settle... - */ - udelay(10); - } - - local_irq_restore(flags); -} - -static void ns87415_dev_select(ide_drive_t *drive) -{ - ns87415_prepare_drive(drive, - !!(drive->dev_flags & IDE_DFLAG_USING_DMA)); - - outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr); -} - -static void ns87415_dma_start(ide_drive_t *drive) -{ - ns87415_prepare_drive(drive, 1); - ide_dma_start(drive); -} - -static int ns87415_dma_end(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u8 dma_stat = 0, dma_cmd = 0; - - dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); - /* get DMA command mode */ - dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); - /* stop DMA */ - outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD); - /* from ERRATA: clear the INTR & ERROR bits */ - dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); - outb(dma_cmd | 6, hwif->dma_base + ATA_DMA_CMD); - - ns87415_prepare_drive(drive, 0); - - /* verify good DMA status */ - return (dma_stat & 7) != 4; -} - -static void init_hwif_ns87415 (ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned int ctrl, using_inta; - u8 progif; -#ifdef __sparc_v9__ - int timeout; - u8 stat; -#endif - - /* - * We cannot probe for IRQ: both ports share common IRQ on INTA. - * Also, leave IRQ masked during drive probing, to prevent infinite - * interrupts from a potentially floating INTA.. - * - * IRQs get unmasked in dev_select() when drive is first used. - */ - (void) pci_read_config_dword(dev, 0x40, &ctrl); - (void) pci_read_config_byte(dev, 0x09, &progif); - /* is irq in "native" mode? */ - using_inta = progif & (1 << (hwif->channel << 1)); - if (!using_inta) - using_inta = ctrl & (1 << (4 + hwif->channel)); - if (hwif->mate) { - hwif->select_data = hwif->mate->select_data; - } else { - hwif->select_data = (unsigned long) - &ns87415_control[ns87415_count++]; - ctrl |= (1 << 8) | (1 << 9); /* mask both IRQs */ - if (using_inta) - ctrl &= ~(1 << 6); /* unmask INTA */ - *((unsigned int *)hwif->select_data) = ctrl; - (void) pci_write_config_dword(dev, 0x40, ctrl); - - /* - * Set prefetch size to 512 bytes for both ports, - * but don't turn on/off prefetching here. - */ - pci_write_config_byte(dev, 0x55, 0xee); - -#ifdef __sparc_v9__ - /* - * XXX: Reset the device, if we don't it will not respond to - * dev_select() properly during first ide_probe_port(). - */ - timeout = 10000; - outb(12, hwif->io_ports.ctl_addr); - udelay(10); - outb(8, hwif->io_ports.ctl_addr); - do { - udelay(50); - stat = hwif->tp_ops->read_status(hwif); - if (stat == 0xff) - break; - } while ((stat & ATA_BUSY) && --timeout); -#endif - } - - if (!using_inta) - hwif->irq = pci_get_legacy_ide_irq(dev, hwif->channel); - - if (!hwif->dma_base) - return; - - outb(0x60, hwif->dma_base + ATA_DMA_STATUS); -} - -static const struct ide_tp_ops ns87415_tp_ops = { - .exec_command = ide_exec_command, - .read_status = ide_read_status, - .read_altstatus = ide_read_altstatus, - .write_devctl = ide_write_devctl, - - .dev_select = ns87415_dev_select, - .tf_load = ide_tf_load, - .tf_read = ide_tf_read, - - .input_data = ide_input_data, - .output_data = ide_output_data, -}; - -static const struct ide_dma_ops ns87415_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = ns87415_dma_start, - .dma_end = ns87415_dma_end, - .dma_test_irq = ide_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = superio_dma_sff_read_status, -}; - -static const struct ide_port_info ns87415_chipset = { - .name = DRV_NAME, - .init_hwif = init_hwif_ns87415, - .tp_ops = &ns87415_tp_ops, - .dma_ops = &ns87415_dma_ops, - .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA | - IDE_HFLAG_NO_ATAPI_DMA, -}; - -static int ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct ide_port_info d = ns87415_chipset; - -#ifdef CONFIG_SUPERIO - if (PCI_SLOT(dev->devfn) == 0xE) { - /* Built-in - assume it's under superio. */ - d.init_iops = superio_init_iops; - d.tp_ops = &superio_tp_ops; - } -#endif - return ide_pci_init_one(dev, &d, NULL); -} - -static const struct pci_device_id ns87415_pci_tbl[] = { - { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87415), 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl); - -static struct pci_driver ns87415_pci_driver = { - .name = "NS87415_IDE", - .id_table = ns87415_pci_tbl, - .probe = ns87415_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init ns87415_ide_init(void) -{ - return ide_pci_register_driver(&ns87415_pci_driver); -} - -static void __exit ns87415_ide_exit(void) -{ - pci_unregister_driver(&ns87415_pci_driver); -} - -module_init(ns87415_ide_init); -module_exit(ns87415_ide_exit); - -MODULE_AUTHOR("Mark Lord, Eddie Dost, Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for NS87415 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/opti621.c b/drivers/ide/opti621.c deleted file mode 100644 index c374f82333c6..000000000000 --- a/drivers/ide/opti621.c +++ /dev/null @@ -1,179 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1996-1998 Linus Torvalds & authors (see below) - */ - -/* - * Authors: - * Jaromir Koutek , - * Jan Harkes , - * Mark Lord - * Some parts of code are from ali14xx.c and from rz1000.c. - */ - -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "opti621" - -#define READ_REG 0 /* index of Read cycle timing register */ -#define WRITE_REG 1 /* index of Write cycle timing register */ -#define CNTRL_REG 3 /* index of Control register */ -#define STRAP_REG 5 /* index of Strap register */ -#define MISC_REG 6 /* index of Miscellaneous register */ - -static int reg_base; - -static DEFINE_SPINLOCK(opti621_lock); - -/* Write value to register reg, base of register - * is at reg_base (0x1f0 primary, 0x170 secondary, - * if not changed by PCI configuration). - * This is from setupvic.exe program. - */ -static void write_reg(u8 value, int reg) -{ - inw(reg_base + 1); - inw(reg_base + 1); - outb(3, reg_base + 2); - outb(value, reg_base + reg); - outb(0x83, reg_base + 2); -} - -/* Read value from register reg, base of register - * is at reg_base (0x1f0 primary, 0x170 secondary, - * if not changed by PCI configuration). - * This is from setupvic.exe program. - */ -static u8 read_reg(int reg) -{ - u8 ret = 0; - - inw(reg_base + 1); - inw(reg_base + 1); - outb(3, reg_base + 2); - ret = inb(reg_base + reg); - outb(0x83, reg_base + 2); - - return ret; -} - -static void opti621_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - ide_drive_t *pair = ide_get_pair_dev(drive); - unsigned long flags; - unsigned long mode = drive->pio_mode, pair_mode; - const u8 pio = mode - XFER_PIO_0; - u8 tim, misc, addr_pio = pio, clk; - - /* DRDY is default 2 (by OPTi Databook) */ - static const u8 addr_timings[2][5] = { - { 0x20, 0x10, 0x00, 0x00, 0x00 }, /* 33 MHz */ - { 0x10, 0x10, 0x00, 0x00, 0x00 }, /* 25 MHz */ - }; - static const u8 data_rec_timings[2][5] = { - { 0x5b, 0x45, 0x32, 0x21, 0x20 }, /* 33 MHz */ - { 0x48, 0x34, 0x21, 0x10, 0x10 } /* 25 MHz */ - }; - - ide_set_drivedata(drive, (void *)mode); - - if (pair) { - pair_mode = (unsigned long)ide_get_drivedata(pair); - if (pair_mode && pair_mode < mode) - addr_pio = pair_mode - XFER_PIO_0; - } - - spin_lock_irqsave(&opti621_lock, flags); - - reg_base = hwif->io_ports.data_addr; - - /* allow Register-B */ - outb(0xc0, reg_base + CNTRL_REG); - /* hmm, setupvic.exe does this ;-) */ - outb(0xff, reg_base + 5); - /* if reads 0xff, adapter not exist? */ - (void)inb(reg_base + CNTRL_REG); - /* if reads 0xc0, no interface exist? */ - read_reg(CNTRL_REG); - - /* check CLK speed */ - clk = read_reg(STRAP_REG) & 1; - - printk(KERN_INFO "%s: CLK = %d MHz\n", hwif->name, clk ? 25 : 33); - - tim = data_rec_timings[clk][pio]; - misc = addr_timings[clk][addr_pio]; - - /* select Index-0/1 for Register-A/B */ - write_reg(drive->dn & 1, MISC_REG); - /* set read cycle timings */ - write_reg(tim, READ_REG); - /* set write cycle timings */ - write_reg(tim, WRITE_REG); - - /* use Register-A for drive 0 */ - /* use Register-B for drive 1 */ - write_reg(0x85, CNTRL_REG); - - /* set address setup, DRDY timings, */ - /* and read prefetch for both drives */ - write_reg(misc, MISC_REG); - - spin_unlock_irqrestore(&opti621_lock, flags); -} - -static const struct ide_port_ops opti621_port_ops = { - .set_pio_mode = opti621_set_pio_mode, -}; - -static const struct ide_port_info opti621_chipset = { - .name = DRV_NAME, - .enablebits = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} }, - .port_ops = &opti621_port_ops, - .host_flags = IDE_HFLAG_NO_DMA, - .pio_mask = ATA_PIO4, -}; - -static int opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_pci_init_one(dev, &opti621_chipset, NULL); -} - -static const struct pci_device_id opti621_pci_tbl[] = { - { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 }, - { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, opti621_pci_tbl); - -static struct pci_driver opti621_pci_driver = { - .name = "Opti621_IDE", - .id_table = opti621_pci_tbl, - .probe = opti621_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init opti621_ide_init(void) -{ - return ide_pci_register_driver(&opti621_pci_driver); -} - -static void __exit opti621_ide_exit(void) -{ - pci_unregister_driver(&opti621_pci_driver); -} - -module_init(opti621_ide_init); -module_exit(opti621_ide_exit); - -MODULE_AUTHOR("Jaromir Koutek, Jan Harkes, Mark Lord"); -MODULE_DESCRIPTION("PCI driver module for Opti621 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/palm_bk3710.c b/drivers/ide/palm_bk3710.c deleted file mode 100644 index d1fe4c13e35c..000000000000 --- a/drivers/ide/palm_bk3710.c +++ /dev/null @@ -1,387 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Palmchip bk3710 IDE controller - * - * Copyright (C) 2006 Texas Instruments. - * Copyright (C) 2007 MontaVista Software, Inc., - * - * ---------------------------------------------------------------------------- - * - * ---------------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Offset of the primary interface registers */ -#define IDE_PALM_ATA_PRI_REG_OFFSET 0x1F0 - -/* Primary Control Offset */ -#define IDE_PALM_ATA_PRI_CTL_OFFSET 0x3F6 - -#define BK3710_BMICP 0x00 -#define BK3710_BMISP 0x02 -#define BK3710_BMIDTP 0x04 -#define BK3710_IDETIMP 0x40 -#define BK3710_IDESTATUS 0x47 -#define BK3710_UDMACTL 0x48 -#define BK3710_MISCCTL 0x50 -#define BK3710_REGSTB 0x54 -#define BK3710_REGRCVR 0x58 -#define BK3710_DATSTB 0x5C -#define BK3710_DATRCVR 0x60 -#define BK3710_DMASTB 0x64 -#define BK3710_DMARCVR 0x68 -#define BK3710_UDMASTB 0x6C -#define BK3710_UDMATRP 0x70 -#define BK3710_UDMAENV 0x74 -#define BK3710_IORDYTMP 0x78 - -static unsigned ideclk_period; /* in nanoseconds */ - -struct palm_bk3710_udmatiming { - unsigned int rptime; /* tRP -- Ready to pause time (nsec) */ - unsigned int cycletime; /* tCYCTYP2/2 -- avg Cycle Time (nsec) */ - /* tENV is always a minimum of 20 nsec */ -}; - -static const struct palm_bk3710_udmatiming palm_bk3710_udmatimings[6] = { - { 160, 240 / 2 }, /* UDMA Mode 0 */ - { 125, 160 / 2 }, /* UDMA Mode 1 */ - { 100, 120 / 2 }, /* UDMA Mode 2 */ - { 100, 90 / 2 }, /* UDMA Mode 3 */ - { 100, 60 / 2 }, /* UDMA Mode 4 */ - { 85, 40 / 2 }, /* UDMA Mode 5 */ -}; - -static void palm_bk3710_setudmamode(void __iomem *base, unsigned int dev, - unsigned int mode) -{ - u8 tenv, trp, t0; - u32 val32; - u16 val16; - - /* DMA Data Setup */ - t0 = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].cycletime, - ideclk_period) - 1; - tenv = DIV_ROUND_UP(20, ideclk_period) - 1; - trp = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].rptime, - ideclk_period) - 1; - - /* udmastb Ultra DMA Access Strobe Width */ - val32 = readl(base + BK3710_UDMASTB) & (0xFF << (dev ? 0 : 8)); - val32 |= (t0 << (dev ? 8 : 0)); - writel(val32, base + BK3710_UDMASTB); - - /* udmatrp Ultra DMA Ready to Pause Time */ - val32 = readl(base + BK3710_UDMATRP) & (0xFF << (dev ? 0 : 8)); - val32 |= (trp << (dev ? 8 : 0)); - writel(val32, base + BK3710_UDMATRP); - - /* udmaenv Ultra DMA envelop Time */ - val32 = readl(base + BK3710_UDMAENV) & (0xFF << (dev ? 0 : 8)); - val32 |= (tenv << (dev ? 8 : 0)); - writel(val32, base + BK3710_UDMAENV); - - /* Enable UDMA for Device */ - val16 = readw(base + BK3710_UDMACTL) | (1 << dev); - writew(val16, base + BK3710_UDMACTL); -} - -static void palm_bk3710_setdmamode(void __iomem *base, unsigned int dev, - unsigned short min_cycle, - unsigned int mode) -{ - u8 td, tkw, t0; - u32 val32; - u16 val16; - struct ide_timing *t; - int cycletime; - - t = ide_timing_find_mode(mode); - cycletime = max_t(int, t->cycle, min_cycle); - - /* DMA Data Setup */ - t0 = DIV_ROUND_UP(cycletime, ideclk_period); - td = DIV_ROUND_UP(t->active, ideclk_period); - tkw = t0 - td - 1; - td -= 1; - - val32 = readl(base + BK3710_DMASTB) & (0xFF << (dev ? 0 : 8)); - val32 |= (td << (dev ? 8 : 0)); - writel(val32, base + BK3710_DMASTB); - - val32 = readl(base + BK3710_DMARCVR) & (0xFF << (dev ? 0 : 8)); - val32 |= (tkw << (dev ? 8 : 0)); - writel(val32, base + BK3710_DMARCVR); - - /* Disable UDMA for Device */ - val16 = readw(base + BK3710_UDMACTL) & ~(1 << dev); - writew(val16, base + BK3710_UDMACTL); -} - -static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate, - unsigned int dev, unsigned int cycletime, - unsigned int mode) -{ - u8 t2, t2i, t0; - u32 val32; - struct ide_timing *t; - - t = ide_timing_find_mode(XFER_PIO_0 + mode); - - /* PIO Data Setup */ - t0 = DIV_ROUND_UP(cycletime, ideclk_period); - t2 = DIV_ROUND_UP(t->active, ideclk_period); - - t2i = t0 - t2 - 1; - t2 -= 1; - - val32 = readl(base + BK3710_DATSTB) & (0xFF << (dev ? 0 : 8)); - val32 |= (t2 << (dev ? 8 : 0)); - writel(val32, base + BK3710_DATSTB); - - val32 = readl(base + BK3710_DATRCVR) & (0xFF << (dev ? 0 : 8)); - val32 |= (t2i << (dev ? 8 : 0)); - writel(val32, base + BK3710_DATRCVR); - - if (mate) { - u8 mode2 = mate->pio_mode - XFER_PIO_0; - - if (mode2 < mode) - mode = mode2; - } - - /* TASKFILE Setup */ - t0 = DIV_ROUND_UP(t->cyc8b, ideclk_period); - t2 = DIV_ROUND_UP(t->act8b, ideclk_period); - - t2i = t0 - t2 - 1; - t2 -= 1; - - val32 = readl(base + BK3710_REGSTB) & (0xFF << (dev ? 0 : 8)); - val32 |= (t2 << (dev ? 8 : 0)); - writel(val32, base + BK3710_REGSTB); - - val32 = readl(base + BK3710_REGRCVR) & (0xFF << (dev ? 0 : 8)); - val32 |= (t2i << (dev ? 8 : 0)); - writel(val32, base + BK3710_REGRCVR); -} - -static void palm_bk3710_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - int is_slave = drive->dn & 1; - void __iomem *base = (void __iomem *)hwif->dma_base; - const u8 xferspeed = drive->dma_mode; - - if (xferspeed >= XFER_UDMA_0) { - palm_bk3710_setudmamode(base, is_slave, - xferspeed - XFER_UDMA_0); - } else { - palm_bk3710_setdmamode(base, is_slave, - drive->id[ATA_ID_EIDE_DMA_MIN], - xferspeed); - } -} - -static void palm_bk3710_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - unsigned int cycle_time; - int is_slave = drive->dn & 1; - ide_drive_t *mate; - void __iomem *base = (void __iomem *)hwif->dma_base; - const u8 pio = drive->pio_mode - XFER_PIO_0; - - /* - * Obtain the drive PIO data for tuning the Palm Chip registers - */ - cycle_time = ide_pio_cycle_time(drive, pio); - mate = ide_get_pair_dev(drive); - palm_bk3710_setpiomode(base, mate, is_slave, cycle_time, pio); -} - -static void palm_bk3710_chipinit(void __iomem *base) -{ - /* - * REVISIT: the ATA reset signal needs to be managed through a - * GPIO, which means it should come from platform_data. Until - * we get and use such information, we have to trust that things - * have been reset before we get here. - */ - - /* - * Program the IDETIMP Register Value based on the following assumptions - * - * (ATA_IDETIMP_IDEEN , ENABLE ) | - * (ATA_IDETIMP_PREPOST1 , DISABLE) | - * (ATA_IDETIMP_PREPOST0 , DISABLE) | - * - * DM6446 silicon rev 2.1 and earlier have no observed net benefit - * from enabling prefetch/postwrite. - */ - writew(BIT(15), base + BK3710_IDETIMP); - - /* - * UDMACTL Ultra-ATA DMA Control - * (ATA_UDMACTL_UDMAP1 , 0 ) | - * (ATA_UDMACTL_UDMAP0 , 0 ) - * - */ - writew(0, base + BK3710_UDMACTL); - - /* - * MISCCTL Miscellaneous Conrol Register - * (ATA_MISCCTL_HWNHLD1P , 1 cycle) - * (ATA_MISCCTL_HWNHLD0P , 1 cycle) - * (ATA_MISCCTL_TIMORIDE , 1) - */ - writel(0x001, base + BK3710_MISCCTL); - - /* - * IORDYTMP IORDY Timer for Primary Register - * (ATA_IORDYTMP_IORDYTMP , 0xffff ) - */ - writel(0xFFFF, base + BK3710_IORDYTMP); - - /* - * Configure BMISP Register - * (ATA_BMISP_DMAEN1 , DISABLE ) | - * (ATA_BMISP_DMAEN0 , DISABLE ) | - * (ATA_BMISP_IORDYINT , CLEAR) | - * (ATA_BMISP_INTRSTAT , CLEAR) | - * (ATA_BMISP_DMAERROR , CLEAR) - */ - writew(0, base + BK3710_BMISP); - - palm_bk3710_setpiomode(base, NULL, 0, 600, 0); - palm_bk3710_setpiomode(base, NULL, 1, 600, 0); -} - -static u8 palm_bk3710_cable_detect(ide_hwif_t *hwif) -{ - return ATA_CBL_PATA80; -} - -static int palm_bk3710_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d) -{ - printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name); - - if (ide_allocate_dma_engine(hwif)) - return -1; - - hwif->dma_base = hwif->io_ports.data_addr - IDE_PALM_ATA_PRI_REG_OFFSET; - - return 0; -} - -static const struct ide_port_ops palm_bk3710_ports_ops = { - .set_pio_mode = palm_bk3710_set_pio_mode, - .set_dma_mode = palm_bk3710_set_dma_mode, - .cable_detect = palm_bk3710_cable_detect, -}; - -static struct ide_port_info palm_bk3710_port_info __initdata = { - .init_dma = palm_bk3710_init_dma, - .port_ops = &palm_bk3710_ports_ops, - .dma_ops = &sff_dma_ops, - .host_flags = IDE_HFLAG_MMIO, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .chipset = ide_palm3710, -}; - -static int __init palm_bk3710_probe(struct platform_device *pdev) -{ - struct clk *clk; - struct resource *mem, *irq; - void __iomem *base; - unsigned long rate, mem_size; - int i, rc; - struct ide_hw hw, *hws[] = { &hw }; - - clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) - return -ENODEV; - - clk_enable(clk); - rate = clk_get_rate(clk); - if (!rate) - return -EINVAL; - - /* NOTE: round *down* to meet minimum timings; we count in clocks */ - ideclk_period = 1000000000UL / rate; - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (mem == NULL) { - printk(KERN_ERR "failed to get memory region resource\n"); - return -ENODEV; - } - - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (irq == NULL) { - printk(KERN_ERR "failed to get IRQ resource\n"); - return -ENODEV; - } - - mem_size = resource_size(mem); - if (request_mem_region(mem->start, mem_size, "palm_bk3710") == NULL) { - printk(KERN_ERR "failed to request memory region\n"); - return -EBUSY; - } - - base = ioremap(mem->start, mem_size); - if (!base) { - printk(KERN_ERR "failed to map IO memory\n"); - release_mem_region(mem->start, mem_size); - return -ENOMEM; - } - - /* Configure the Palm Chip controller */ - palm_bk3710_chipinit(base); - - memset(&hw, 0, sizeof(hw)); - for (i = 0; i < IDE_NR_PORTS - 2; i++) - hw.io_ports_array[i] = (unsigned long) - (base + IDE_PALM_ATA_PRI_REG_OFFSET + i); - hw.io_ports.ctl_addr = (unsigned long) - (base + IDE_PALM_ATA_PRI_CTL_OFFSET); - hw.irq = irq->start; - hw.dev = &pdev->dev; - - palm_bk3710_port_info.udma_mask = rate < 100000000 ? ATA_UDMA4 : - ATA_UDMA5; - - /* Register the IDE interface with Linux */ - rc = ide_host_add(&palm_bk3710_port_info, hws, 1, NULL); - if (rc) - goto out; - - return 0; -out: - printk(KERN_WARNING "Palm Chip BK3710 IDE Register Fail\n"); - return rc; -} - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:palm_bk3710"); - -static struct platform_driver platform_bk_driver = { - .driver = { - .name = "palm_bk3710", - }, -}; - -static int __init palm_bk3710_init(void) -{ - return platform_driver_probe(&platform_bk_driver, palm_bk3710_probe); -} - -module_init(palm_bk3710_init); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pdc202xx_new.c b/drivers/ide/pdc202xx_new.c deleted file mode 100644 index 4fcafb9121e0..000000000000 --- a/drivers/ide/pdc202xx_new.c +++ /dev/null @@ -1,557 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Promise TX2/TX4/TX2000/133 IDE driver - * - * Split from: - * linux/drivers/ide/pdc202xx.c Version 0.35 Mar. 30, 2002 - * Copyright (C) 1998-2002 Andre Hedrick - * Copyright (C) 2005-2007 MontaVista Software, Inc. - * Portions Copyright (C) 1999 Promise Technology, Inc. - * Author: Frank Tiernan (frankt@promise.com) - * Released under terms of General Public License - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef CONFIG_PPC_PMAC -#include -#endif - -#define DRV_NAME "pdc202xx_new" - -#undef DEBUG - -#ifdef DEBUG -#define DBG(fmt, args...) printk("%s: " fmt, __func__, ## args) -#else -#define DBG(fmt, args...) -#endif - -static u8 max_dma_rate(struct pci_dev *pdev) -{ - u8 mode; - - switch(pdev->device) { - case PCI_DEVICE_ID_PROMISE_20277: - case PCI_DEVICE_ID_PROMISE_20276: - case PCI_DEVICE_ID_PROMISE_20275: - case PCI_DEVICE_ID_PROMISE_20271: - case PCI_DEVICE_ID_PROMISE_20269: - mode = 4; - break; - case PCI_DEVICE_ID_PROMISE_20270: - case PCI_DEVICE_ID_PROMISE_20268: - mode = 3; - break; - default: - return 0; - } - - return mode; -} - -/** - * get_indexed_reg - Get indexed register - * @hwif: for the port address - * @index: index of the indexed register - */ -static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index) -{ - u8 value; - - outb(index, hwif->dma_base + 1); - value = inb(hwif->dma_base + 3); - - DBG("index[%02X] value[%02X]\n", index, value); - return value; -} - -/** - * set_indexed_reg - Set indexed register - * @hwif: for the port address - * @index: index of the indexed register - */ -static void set_indexed_reg(ide_hwif_t *hwif, u8 index, u8 value) -{ - outb(index, hwif->dma_base + 1); - outb(value, hwif->dma_base + 3); - DBG("index[%02X] value[%02X]\n", index, value); -} - -/* - * ATA Timing Tables based on 133 MHz PLL output clock. - * - * If the PLL outputs 100 MHz clock, the ASIC hardware will set - * the timing registers automatically when "set features" command is - * issued to the device. However, if the PLL output clock is 133 MHz, - * the following tables must be used. - */ -static struct pio_timing { - u8 reg0c, reg0d, reg13; -} pio_timings [] = { - { 0xfb, 0x2b, 0xac }, /* PIO mode 0, IORDY off, Prefetch off */ - { 0x46, 0x29, 0xa4 }, /* PIO mode 1, IORDY off, Prefetch off */ - { 0x23, 0x26, 0x64 }, /* PIO mode 2, IORDY off, Prefetch off */ - { 0x27, 0x0d, 0x35 }, /* PIO mode 3, IORDY on, Prefetch off */ - { 0x23, 0x09, 0x25 }, /* PIO mode 4, IORDY on, Prefetch off */ -}; - -static struct mwdma_timing { - u8 reg0e, reg0f; -} mwdma_timings [] = { - { 0xdf, 0x5f }, /* MWDMA mode 0 */ - { 0x6b, 0x27 }, /* MWDMA mode 1 */ - { 0x69, 0x25 }, /* MWDMA mode 2 */ -}; - -static struct udma_timing { - u8 reg10, reg11, reg12; -} udma_timings [] = { - { 0x4a, 0x0f, 0xd5 }, /* UDMA mode 0 */ - { 0x3a, 0x0a, 0xd0 }, /* UDMA mode 1 */ - { 0x2a, 0x07, 0xcd }, /* UDMA mode 2 */ - { 0x1a, 0x05, 0xcd }, /* UDMA mode 3 */ - { 0x1a, 0x03, 0xcd }, /* UDMA mode 4 */ - { 0x1a, 0x02, 0xcb }, /* UDMA mode 5 */ - { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */ -}; - -static void pdcnew_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 adj = (drive->dn & 1) ? 0x08 : 0x00; - const u8 speed = drive->dma_mode; - - /* - * IDE core issues SETFEATURES_XFER to the drive first (thanks to - * IDE_HFLAG_POST_SET_MODE in ->host_flags). PDC202xx hardware will - * automatically set the timing registers based on 100 MHz PLL output. - * - * As we set up the PLL to output 133 MHz for UltraDMA/133 capable - * chips, we must override the default register settings... - */ - if (max_dma_rate(dev) == 4) { - u8 mode = speed & 0x07; - - if (speed >= XFER_UDMA_0) { - set_indexed_reg(hwif, 0x10 + adj, - udma_timings[mode].reg10); - set_indexed_reg(hwif, 0x11 + adj, - udma_timings[mode].reg11); - set_indexed_reg(hwif, 0x12 + adj, - udma_timings[mode].reg12); - } else { - set_indexed_reg(hwif, 0x0e + adj, - mwdma_timings[mode].reg0e); - set_indexed_reg(hwif, 0x0f + adj, - mwdma_timings[mode].reg0f); - } - } else if (speed == XFER_UDMA_2) { - /* Set tHOLD bit to 0 if using UDMA mode 2 */ - u8 tmp = get_indexed_reg(hwif, 0x10 + adj); - - set_indexed_reg(hwif, 0x10 + adj, tmp & 0x7f); - } -} - -static void pdcnew_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 adj = (drive->dn & 1) ? 0x08 : 0x00; - const u8 pio = drive->pio_mode - XFER_PIO_0; - - if (max_dma_rate(dev) == 4) { - set_indexed_reg(hwif, 0x0c + adj, pio_timings[pio].reg0c); - set_indexed_reg(hwif, 0x0d + adj, pio_timings[pio].reg0d); - set_indexed_reg(hwif, 0x13 + adj, pio_timings[pio].reg13); - } -} - -static u8 pdcnew_cable_detect(ide_hwif_t *hwif) -{ - if (get_indexed_reg(hwif, 0x0b) & 0x04) - return ATA_CBL_PATA40; - else - return ATA_CBL_PATA80; -} - -static void pdcnew_reset(ide_drive_t *drive) -{ - /* - * Deleted this because it is redundant from the caller. - */ - printk(KERN_WARNING "pdc202xx_new: %s channel reset.\n", - drive->hwif->channel ? "Secondary" : "Primary"); -} - -/** - * read_counter - Read the byte count registers - * @dma_base: for the port address - */ -static long read_counter(u32 dma_base) -{ - u32 pri_dma_base = dma_base, sec_dma_base = dma_base + 0x08; - u8 cnt0, cnt1, cnt2, cnt3; - long count = 0, last; - int retry = 3; - - do { - last = count; - - /* Read the current count */ - outb(0x20, pri_dma_base + 0x01); - cnt0 = inb(pri_dma_base + 0x03); - outb(0x21, pri_dma_base + 0x01); - cnt1 = inb(pri_dma_base + 0x03); - outb(0x20, sec_dma_base + 0x01); - cnt2 = inb(sec_dma_base + 0x03); - outb(0x21, sec_dma_base + 0x01); - cnt3 = inb(sec_dma_base + 0x03); - - count = (cnt3 << 23) | (cnt2 << 15) | (cnt1 << 8) | cnt0; - - /* - * The 30-bit decrementing counter is read in 4 pieces. - * Incorrect value may be read when the most significant bytes - * are changing... - */ - } while (retry-- && (((last ^ count) & 0x3fff8000) || last < count)); - - DBG("cnt0[%02X] cnt1[%02X] cnt2[%02X] cnt3[%02X]\n", - cnt0, cnt1, cnt2, cnt3); - - return count; -} - -/** - * detect_pll_input_clock - Detect the PLL input clock in Hz. - * @dma_base: for the port address - * E.g. 16949000 on 33 MHz PCI bus, i.e. half of the PCI clock. - */ -static long detect_pll_input_clock(unsigned long dma_base) -{ - ktime_t start_time, end_time; - long start_count, end_count; - long pll_input, usec_elapsed; - u8 scr1; - - start_count = read_counter(dma_base); - start_time = ktime_get(); - - /* Start the test mode */ - outb(0x01, dma_base + 0x01); - scr1 = inb(dma_base + 0x03); - DBG("scr1[%02X]\n", scr1); - outb(scr1 | 0x40, dma_base + 0x03); - - /* Let the counter run for 10 ms. */ - mdelay(10); - - end_count = read_counter(dma_base); - end_time = ktime_get(); - - /* Stop the test mode */ - outb(0x01, dma_base + 0x01); - scr1 = inb(dma_base + 0x03); - DBG("scr1[%02X]\n", scr1); - outb(scr1 & ~0x40, dma_base + 0x03); - - /* - * Calculate the input clock in Hz - * (the clock counter is 30 bit wide and counts down) - */ - usec_elapsed = ktime_us_delta(end_time, start_time); - pll_input = ((start_count - end_count) & 0x3fffffff) / 10 * - (10000000 / usec_elapsed); - - DBG("start[%ld] end[%ld]\n", start_count, end_count); - - return pll_input; -} - -#ifdef CONFIG_PPC_PMAC -static void apple_kiwi_init(struct pci_dev *pdev) -{ - struct device_node *np = pci_device_to_OF_node(pdev); - u8 conf; - - if (np == NULL || !of_device_is_compatible(np, "kiwi-root")) - return; - - if (pdev->revision >= 0x03) { - /* Setup chip magic config stuff (from darwin) */ - pci_read_config_byte (pdev, 0x40, &conf); - pci_write_config_byte(pdev, 0x40, (conf | 0x01)); - } -} -#endif /* CONFIG_PPC_PMAC */ - -static int init_chipset_pdcnew(struct pci_dev *dev) -{ - const char *name = DRV_NAME; - unsigned long dma_base = pci_resource_start(dev, 4); - unsigned long sec_dma_base = dma_base + 0x08; - long pll_input, pll_output, ratio; - int f, r; - u8 pll_ctl0, pll_ctl1; - - if (dma_base == 0) - return -EFAULT; - -#ifdef CONFIG_PPC_PMAC - apple_kiwi_init(dev); -#endif - - /* Calculate the required PLL output frequency */ - switch(max_dma_rate(dev)) { - case 4: /* it's 133 MHz for Ultra133 chips */ - pll_output = 133333333; - break; - case 3: /* and 100 MHz for Ultra100 chips */ - default: - pll_output = 100000000; - break; - } - - /* - * Detect PLL input clock. - * On some systems, where PCI bus is running at non-standard clock rate - * (e.g. 25 or 40 MHz), we have to adjust the cycle time. - * PDC20268 and newer chips employ PLL circuit to help correct timing - * registers setting. - */ - pll_input = detect_pll_input_clock(dma_base); - printk(KERN_INFO "%s %s: PLL input clock is %ld kHz\n", - name, pci_name(dev), pll_input / 1000); - - /* Sanity check */ - if (unlikely(pll_input < 5000000L || pll_input > 70000000L)) { - printk(KERN_ERR "%s %s: Bad PLL input clock %ld Hz, giving up!" - "\n", name, pci_name(dev), pll_input); - goto out; - } - -#ifdef DEBUG - DBG("pll_output is %ld Hz\n", pll_output); - - /* Show the current clock value of PLL control register - * (maybe already configured by the BIOS) - */ - outb(0x02, sec_dma_base + 0x01); - pll_ctl0 = inb(sec_dma_base + 0x03); - outb(0x03, sec_dma_base + 0x01); - pll_ctl1 = inb(sec_dma_base + 0x03); - - DBG("pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1); -#endif - - /* - * Calculate the ratio of F, R and NO - * POUT = (F + 2) / (( R + 2) * NO) - */ - ratio = pll_output / (pll_input / 1000); - if (ratio < 8600L) { /* 8.6x */ - /* Using NO = 0x01, R = 0x0d */ - r = 0x0d; - } else if (ratio < 12900L) { /* 12.9x */ - /* Using NO = 0x01, R = 0x08 */ - r = 0x08; - } else if (ratio < 16100L) { /* 16.1x */ - /* Using NO = 0x01, R = 0x06 */ - r = 0x06; - } else if (ratio < 64000L) { /* 64x */ - r = 0x00; - } else { - /* Invalid ratio */ - printk(KERN_ERR "%s %s: Bad ratio %ld, giving up!\n", - name, pci_name(dev), ratio); - goto out; - } - - f = (ratio * (r + 2)) / 1000 - 2; - - DBG("F[%d] R[%d] ratio*1000[%ld]\n", f, r, ratio); - - if (unlikely(f < 0 || f > 127)) { - /* Invalid F */ - printk(KERN_ERR "%s %s: F[%d] invalid!\n", - name, pci_name(dev), f); - goto out; - } - - pll_ctl0 = (u8) f; - pll_ctl1 = (u8) r; - - DBG("Writing pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1); - - outb(0x02, sec_dma_base + 0x01); - outb(pll_ctl0, sec_dma_base + 0x03); - outb(0x03, sec_dma_base + 0x01); - outb(pll_ctl1, sec_dma_base + 0x03); - - /* Wait the PLL circuit to be stable */ - mdelay(30); - -#ifdef DEBUG - /* - * Show the current clock value of PLL control register - */ - outb(0x02, sec_dma_base + 0x01); - pll_ctl0 = inb(sec_dma_base + 0x03); - outb(0x03, sec_dma_base + 0x01); - pll_ctl1 = inb(sec_dma_base + 0x03); - - DBG("pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1); -#endif - - out: - return 0; -} - -static struct pci_dev *pdc20270_get_dev2(struct pci_dev *dev) -{ - struct pci_dev *dev2; - - dev2 = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn) + 1, - PCI_FUNC(dev->devfn))); - - if (dev2 && - dev2->vendor == dev->vendor && - dev2->device == dev->device) { - - if (dev2->irq != dev->irq) { - dev2->irq = dev->irq; - printk(KERN_INFO DRV_NAME " %s: PCI config space " - "interrupt fixed\n", pci_name(dev)); - } - - return dev2; - } - - return NULL; -} - -static const struct ide_port_ops pdcnew_port_ops = { - .set_pio_mode = pdcnew_set_pio_mode, - .set_dma_mode = pdcnew_set_dma_mode, - .resetproc = pdcnew_reset, - .cable_detect = pdcnew_cable_detect, -}; - -#define DECLARE_PDCNEW_DEV(udma) \ - { \ - .name = DRV_NAME, \ - .init_chipset = init_chipset_pdcnew, \ - .port_ops = &pdcnew_port_ops, \ - .host_flags = IDE_HFLAG_POST_SET_MODE | \ - IDE_HFLAG_ERROR_STOPS_FIFO | \ - IDE_HFLAG_OFF_BOARD, \ - .pio_mask = ATA_PIO4, \ - .mwdma_mask = ATA_MWDMA2, \ - .udma_mask = udma, \ - } - -static const struct ide_port_info pdcnew_chipsets[] = { - /* 0: PDC202{68,70} */ DECLARE_PDCNEW_DEV(ATA_UDMA5), - /* 1: PDC202{69,71,75,76,77} */ DECLARE_PDCNEW_DEV(ATA_UDMA6), -}; - -/** - * pdc202new_init_one - called when a pdc202xx is found - * @dev: the pdc202new device - * @id: the matching pci id - * - * Called when the PCI registration layer (or the IDE initialization) - * finds a device matching our IDE device tables. - */ - -static int pdc202new_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - const struct ide_port_info *d = &pdcnew_chipsets[id->driver_data]; - struct pci_dev *bridge = dev->bus->self; - - if (dev->device == PCI_DEVICE_ID_PROMISE_20270 && bridge && - bridge->vendor == PCI_VENDOR_ID_DEC && - bridge->device == PCI_DEVICE_ID_DEC_21150) { - struct pci_dev *dev2; - - if (PCI_SLOT(dev->devfn) & 2) - return -ENODEV; - - dev2 = pdc20270_get_dev2(dev); - - if (dev2) { - int ret = ide_pci_init_two(dev, dev2, d, NULL); - if (ret < 0) - pci_dev_put(dev2); - return ret; - } - } - - if (dev->device == PCI_DEVICE_ID_PROMISE_20276 && bridge && - bridge->vendor == PCI_VENDOR_ID_INTEL && - (bridge->device == PCI_DEVICE_ID_INTEL_I960 || - bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) { - printk(KERN_INFO DRV_NAME " %s: attached to I2O RAID controller," - " skipping\n", pci_name(dev)); - return -ENODEV; - } - - return ide_pci_init_one(dev, d, NULL); -} - -static void pdc202new_remove(struct pci_dev *dev) -{ - struct ide_host *host = pci_get_drvdata(dev); - struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL; - - ide_pci_remove(dev); - pci_dev_put(dev2); -} - -static const struct pci_device_id pdc202new_pci_tbl[] = { - { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20268), 0 }, - { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20269), 1 }, - { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20270), 0 }, - { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20271), 1 }, - { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20275), 1 }, - { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20276), 1 }, - { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20277), 1 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, pdc202new_pci_tbl); - -static struct pci_driver pdc202new_pci_driver = { - .name = "Promise_IDE", - .id_table = pdc202new_pci_tbl, - .probe = pdc202new_init_one, - .remove = pdc202new_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init pdc202new_ide_init(void) -{ - return ide_pci_register_driver(&pdc202new_pci_driver); -} - -static void __exit pdc202new_ide_exit(void) -{ - pci_unregister_driver(&pdc202new_pci_driver); -} - -module_init(pdc202new_ide_init); -module_exit(pdc202new_ide_exit); - -MODULE_AUTHOR("Andre Hedrick, Frank Tiernan"); -MODULE_DESCRIPTION("PCI driver module for Promise PDC20268 and higher"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pdc202xx_old.c b/drivers/ide/pdc202xx_old.c deleted file mode 100644 index 5248ac064e6e..000000000000 --- a/drivers/ide/pdc202xx_old.c +++ /dev/null @@ -1,362 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1998-2002 Andre Hedrick - * Copyright (C) 2006-2007, 2009 MontaVista Software, Inc. - * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz - * - * Portions Copyright (C) 1999 Promise Technology, Inc. - * Author: Frank Tiernan (frankt@promise.com) - * Released under terms of General Public License - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "pdc202xx_old" - -static void pdc202xx_set_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 drive_pci = 0x60 + (drive->dn << 2); - const u8 speed = drive->dma_mode; - - u8 AP = 0, BP = 0, CP = 0; - u8 TA = 0, TB = 0, TC = 0; - - pci_read_config_byte(dev, drive_pci, &AP); - pci_read_config_byte(dev, drive_pci + 1, &BP); - pci_read_config_byte(dev, drive_pci + 2, &CP); - - switch(speed) { - case XFER_UDMA_5: - case XFER_UDMA_4: TB = 0x20; TC = 0x01; break; - case XFER_UDMA_2: TB = 0x20; TC = 0x01; break; - case XFER_UDMA_3: - case XFER_UDMA_1: TB = 0x40; TC = 0x02; break; - case XFER_UDMA_0: - case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break; - case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break; - case XFER_MW_DMA_0: TB = 0xE0; TC = 0x0F; break; - case XFER_PIO_4: TA = 0x01; TB = 0x04; break; - case XFER_PIO_3: TA = 0x02; TB = 0x06; break; - case XFER_PIO_2: TA = 0x03; TB = 0x08; break; - case XFER_PIO_1: TA = 0x05; TB = 0x0C; break; - case XFER_PIO_0: - default: TA = 0x09; TB = 0x13; break; - } - - if (speed < XFER_SW_DMA_0) { - /* - * preserve SYNC_INT / ERDDY_EN bits while clearing - * Prefetch_EN / IORDY_EN / PA[3:0] bits of register A - */ - AP &= ~0x3f; - if (ide_pio_need_iordy(drive, speed - XFER_PIO_0)) - AP |= 0x20; /* set IORDY_EN bit */ - if (drive->media == ide_disk) - AP |= 0x10; /* set Prefetch_EN bit */ - /* clear PB[4:0] bits of register B */ - BP &= ~0x1f; - pci_write_config_byte(dev, drive_pci, AP | TA); - pci_write_config_byte(dev, drive_pci + 1, BP | TB); - } else { - /* clear MB[2:0] bits of register B */ - BP &= ~0xe0; - /* clear MC[3:0] bits of register C */ - CP &= ~0x0f; - pci_write_config_byte(dev, drive_pci + 1, BP | TB); - pci_write_config_byte(dev, drive_pci + 2, CP | TC); - } -} - -static void pdc202xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - drive->dma_mode = drive->pio_mode; - pdc202xx_set_mode(hwif, drive); -} - -static int pdc202xx_test_irq(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long high_16 = pci_resource_start(dev, 4); - u8 sc1d = inb(high_16 + 0x1d); - - if (hwif->channel) { - /* - * bit 7: error, bit 6: interrupting, - * bit 5: FIFO full, bit 4: FIFO empty - */ - return (sc1d & 0x40) ? 1 : 0; - } else { - /* - * bit 3: error, bit 2: interrupting, - * bit 1: FIFO full, bit 0: FIFO empty - */ - return (sc1d & 0x04) ? 1 : 0; - } -} - -static u8 pdc2026x_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u16 CIS, mask = hwif->channel ? (1 << 11) : (1 << 10); - - pci_read_config_word(dev, 0x50, &CIS); - - return (CIS & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; -} - -/* - * Set the control register to use the 66MHz system - * clock for UDMA 3/4/5 mode operation when necessary. - * - * FIXME: this register is shared by both channels, some locking is needed - * - * It may also be possible to leave the 66MHz clock on - * and readjust the timing parameters. - */ -static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif) -{ - unsigned long clock_reg = hwif->extra_base + 0x01; - u8 clock = inb(clock_reg); - - outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg); -} - -static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif) -{ - unsigned long clock_reg = hwif->extra_base + 0x01; - u8 clock = inb(clock_reg); - - outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg); -} - -static void pdc2026x_init_hwif(ide_hwif_t *hwif) -{ - pdc_old_disable_66MHz_clock(hwif); -} - -static void pdc202xx_dma_start(ide_drive_t *drive) -{ - if (drive->current_speed > XFER_UDMA_2) - pdc_old_enable_66MHz_clock(drive->hwif); - if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) { - ide_hwif_t *hwif = drive->hwif; - struct request *rq = hwif->rq; - unsigned long high_16 = hwif->extra_base - 16; - unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); - u32 word_count = 0; - u8 clock = inb(high_16 + 0x11); - - outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11); - word_count = (blk_rq_sectors(rq) << 8); - word_count = (rq_data_dir(rq) == READ) ? - word_count | 0x05000000 : - word_count | 0x06000000; - outl(word_count, atapi_reg); - } - ide_dma_start(drive); -} - -static int pdc202xx_dma_end(ide_drive_t *drive) -{ - if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) { - ide_hwif_t *hwif = drive->hwif; - unsigned long high_16 = hwif->extra_base - 16; - unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); - u8 clock = 0; - - outl(0, atapi_reg); /* zero out extra */ - clock = inb(high_16 + 0x11); - outb(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11); - } - if (drive->current_speed > XFER_UDMA_2) - pdc_old_disable_66MHz_clock(drive->hwif); - return ide_dma_end(drive); -} - -static int init_chipset_pdc202xx(struct pci_dev *dev) -{ - unsigned long dmabase = pci_resource_start(dev, 4); - u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0; - - if (dmabase == 0) - goto out; - - udma_speed_flag = inb(dmabase | 0x1f); - primary_mode = inb(dmabase | 0x1a); - secondary_mode = inb(dmabase | 0x1b); - printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \ - "Primary %s Mode " \ - "Secondary %s Mode.\n", pci_name(dev), - (udma_speed_flag & 1) ? "EN" : "DIS", - (primary_mode & 1) ? "MASTER" : "PCI", - (secondary_mode & 1) ? "MASTER" : "PCI" ); - - if (!(udma_speed_flag & 1)) { - printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ", - pci_name(dev), udma_speed_flag, - (udma_speed_flag|1)); - outb(udma_speed_flag | 1, dmabase | 0x1f); - printk("%sACTIVE\n", (inb(dmabase | 0x1f) & 1) ? "" : "IN"); - } -out: - return 0; -} - -static void pdc202ata4_fixup_irq(struct pci_dev *dev, const char *name) -{ - if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) { - u8 irq = 0, irq2 = 0; - pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); - /* 0xbc */ - pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2); - if (irq != irq2) { - pci_write_config_byte(dev, - (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */ - printk(KERN_INFO "%s %s: PCI config space interrupt " - "mirror fixed\n", name, pci_name(dev)); - } - } -} - -#define IDE_HFLAGS_PDC202XX \ - (IDE_HFLAG_ERROR_STOPS_FIFO | \ - IDE_HFLAG_OFF_BOARD) - -static const struct ide_port_ops pdc20246_port_ops = { - .set_pio_mode = pdc202xx_set_pio_mode, - .set_dma_mode = pdc202xx_set_mode, - .test_irq = pdc202xx_test_irq, -}; - -static const struct ide_port_ops pdc2026x_port_ops = { - .set_pio_mode = pdc202xx_set_pio_mode, - .set_dma_mode = pdc202xx_set_mode, - .test_irq = pdc202xx_test_irq, - .cable_detect = pdc2026x_cable_detect, -}; - -static const struct ide_dma_ops pdc2026x_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = pdc202xx_dma_start, - .dma_end = pdc202xx_dma_end, - .dma_test_irq = ide_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = ide_dma_sff_read_status, -}; - -#define DECLARE_PDC2026X_DEV(udma, sectors) \ - { \ - .name = DRV_NAME, \ - .init_chipset = init_chipset_pdc202xx, \ - .init_hwif = pdc2026x_init_hwif, \ - .port_ops = &pdc2026x_port_ops, \ - .dma_ops = &pdc2026x_dma_ops, \ - .host_flags = IDE_HFLAGS_PDC202XX, \ - .pio_mask = ATA_PIO4, \ - .mwdma_mask = ATA_MWDMA2, \ - .udma_mask = udma, \ - .max_sectors = sectors, \ - } - -static const struct ide_port_info pdc202xx_chipsets[] = { - { /* 0: PDC20246 */ - .name = DRV_NAME, - .init_chipset = init_chipset_pdc202xx, - .port_ops = &pdc20246_port_ops, - .dma_ops = &sff_dma_ops, - .host_flags = IDE_HFLAGS_PDC202XX, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA2, - }, - - /* 1: PDC2026{2,3} */ - DECLARE_PDC2026X_DEV(ATA_UDMA4, 0), - /* 2: PDC2026{5,7}: UDMA5, limit LBA48 requests to 256 sectors */ - DECLARE_PDC2026X_DEV(ATA_UDMA5, 256), -}; - -/** - * pdc202xx_init_one - called when a PDC202xx is found - * @dev: the pdc202xx device - * @id: the matching pci id - * - * Called when the PCI registration layer (or the IDE initialization) - * finds a device matching our IDE device tables. - */ - -static int pdc202xx_init_one(struct pci_dev *dev, - const struct pci_device_id *id) -{ - const struct ide_port_info *d; - u8 idx = id->driver_data; - - d = &pdc202xx_chipsets[idx]; - - if (idx < 2) - pdc202ata4_fixup_irq(dev, d->name); - - if (dev->vendor == PCI_DEVICE_ID_PROMISE_20265) { - struct pci_dev *bridge = dev->bus->self; - - if (bridge && - bridge->vendor == PCI_VENDOR_ID_INTEL && - (bridge->device == PCI_DEVICE_ID_INTEL_I960 || - bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) { - printk(KERN_INFO DRV_NAME " %s: skipping Promise " - "PDC20265 attached to I2O RAID controller\n", - pci_name(dev)); - return -ENODEV; - } - } - - return ide_pci_init_one(dev, d, NULL); -} - -static const struct pci_device_id pdc202xx_pci_tbl[] = { - { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 }, - { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 }, - { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1 }, - { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2 }, - { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl); - -static struct pci_driver pdc202xx_pci_driver = { - .name = "Promise_Old_IDE", - .id_table = pdc202xx_pci_tbl, - .probe = pdc202xx_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init pdc202xx_ide_init(void) -{ - return ide_pci_register_driver(&pdc202xx_pci_driver); -} - -static void __exit pdc202xx_ide_exit(void) -{ - pci_unregister_driver(&pdc202xx_pci_driver); -} - -module_init(pdc202xx_ide_init); -module_exit(pdc202xx_ide_exit); - -MODULE_AUTHOR("Andre Hedrick, Frank Tiernan, Bartlomiej Zolnierkiewicz"); -MODULE_DESCRIPTION("PCI driver module for older Promise IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c deleted file mode 100644 index a671cead6ae7..000000000000 --- a/drivers/ide/piix.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer - * Copyright (C) 1998-2000 Andre Hedrick - * Copyright (C) 2003 Red Hat - * Copyright (C) 2006-2007 MontaVista Software, Inc. - * - * May be copied or modified under the terms of the GNU General Public License - * - * Documentation: - * - * Publicly available from Intel web site. Errata documentation - * is also publicly available. As an aide to anyone hacking on this - * driver the list of errata that are relevant is below.going back to - * PIIX4. Older device documentation is now a bit tricky to find. - * - * Errata of note: - * - * Unfixable - * PIIX4 errata #9 - Only on ultra obscure hw - * ICH3 errata #13 - Not observed to affect real hw - * by Intel - * - * Things we must deal with - * PIIX4 errata #10 - BM IDE hang with non UDMA - * (must stop/start dma to recover) - * 440MX errata #15 - As PIIX4 errata #10 - * PIIX4 errata #15 - Must not read control registers - * during a PIO transfer - * 440MX errata #13 - As PIIX4 errata #15 - * ICH2 errata #21 - DMA mode 0 doesn't work right - * ICH0/1 errata #55 - As ICH2 errata #21 - * ICH2 spec c #9 - Extra operations needed to handle - * drive hotswap [NOT YET SUPPORTED] - * ICH2 spec c #20 - IDE PRD must not cross a 64K boundary - * and must be dword aligned - * ICH2 spec c #24 - UDMA mode 4,5 t85/86 should be 6ns not 3.3 - * - * Should have been BIOS fixed: - * 450NX: errata #19 - DMA hangs on old 450NX - * 450NX: errata #20 - DMA hangs on old 450NX - * 450NX: errata #25 - Corruption with DMA on old 450NX - * ICH3 errata #15 - IDE deadlock under high load - * (BIOS must set dev 31 fn 0 bit 23) - * ICH3 errata #18 - Don't use native mode - */ - -#include -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "piix" - -static int no_piix_dma; - -/** - * piix_set_pio_mode - set host controller for PIO mode - * @port: port - * @drive: drive - * - * Set the interface PIO mode based upon the settings done by AMI BIOS. - */ - -static void piix_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - int is_slave = drive->dn & 1; - int master_port = hwif->channel ? 0x42 : 0x40; - int slave_port = 0x44; - unsigned long flags; - u16 master_data; - u8 slave_data; - static DEFINE_SPINLOCK(tune_lock); - int control = 0; - const u8 pio = drive->pio_mode - XFER_PIO_0; - - /* ISP RTC */ - static const u8 timings[][2]= { - { 0, 0 }, - { 0, 0 }, - { 1, 0 }, - { 2, 1 }, - { 2, 3 }, }; - - /* - * Master vs slave is synchronized above us but the slave register is - * shared by the two hwifs so the corner case of two slave timeouts in - * parallel must be locked. - */ - spin_lock_irqsave(&tune_lock, flags); - pci_read_config_word(dev, master_port, &master_data); - - if (pio > 1) - control |= 1; /* Programmable timing on */ - if (drive->media == ide_disk) - control |= 4; /* Prefetch, post write */ - if (ide_pio_need_iordy(drive, pio)) - control |= 2; /* IORDY */ - if (is_slave) { - master_data |= 0x4000; - master_data &= ~0x0070; - if (pio > 1) { - /* Set PPE, IE and TIME */ - master_data |= control << 4; - } - pci_read_config_byte(dev, slave_port, &slave_data); - slave_data &= hwif->channel ? 0x0f : 0xf0; - slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << - (hwif->channel ? 4 : 0); - } else { - master_data &= ~0x3307; - if (pio > 1) { - /* enable PPE, IE and TIME */ - master_data |= control; - } - master_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8); - } - pci_write_config_word(dev, master_port, master_data); - if (is_slave) - pci_write_config_byte(dev, slave_port, slave_data); - spin_unlock_irqrestore(&tune_lock, flags); -} - -/** - * piix_set_dma_mode - set host controller for DMA mode - * @hwif: port - * @drive: drive - * - * Set a PIIX host controller to the desired DMA mode. This involves - * programming the right timing data into the PCI configuration space. - */ - -static void piix_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 maslave = hwif->channel ? 0x42 : 0x40; - int a_speed = 3 << (drive->dn * 4); - int u_flag = 1 << drive->dn; - int v_flag = 0x01 << drive->dn; - int w_flag = 0x10 << drive->dn; - int u_speed = 0; - int sitre; - u16 reg4042, reg4a; - u8 reg48, reg54, reg55; - const u8 speed = drive->dma_mode; - - pci_read_config_word(dev, maslave, ®4042); - sitre = (reg4042 & 0x4000) ? 1 : 0; - pci_read_config_byte(dev, 0x48, ®48); - pci_read_config_word(dev, 0x4a, ®4a); - pci_read_config_byte(dev, 0x54, ®54); - pci_read_config_byte(dev, 0x55, ®55); - - if (speed >= XFER_UDMA_0) { - u8 udma = speed - XFER_UDMA_0; - - u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4); - - if (!(reg48 & u_flag)) - pci_write_config_byte(dev, 0x48, reg48 | u_flag); - if (speed == XFER_UDMA_5) { - pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); - } else { - pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); - } - if ((reg4a & a_speed) != u_speed) - pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); - if (speed > XFER_UDMA_2) { - if (!(reg54 & v_flag)) - pci_write_config_byte(dev, 0x54, reg54 | v_flag); - } else - pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); - } else { - const u8 mwdma_to_pio[] = { 0, 3, 4 }; - - if (reg48 & u_flag) - pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); - if (reg4a & a_speed) - pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - if (reg54 & v_flag) - pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); - if (reg55 & w_flag) - pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); - - if (speed >= XFER_MW_DMA_0) - drive->pio_mode = - mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0; - else - drive->pio_mode = XFER_PIO_2; /* for SWDMA2 */ - - piix_set_pio_mode(hwif, drive); - } -} - -/** - * init_chipset_ich - set up the ICH chipset - * @dev: PCI device to set up - * - * Initialize the PCI device as required. For the ICH this turns - * out to be nice and simple. - */ - -static int init_chipset_ich(struct pci_dev *dev) -{ - u32 extra = 0; - - pci_read_config_dword(dev, 0x54, &extra); - pci_write_config_dword(dev, 0x54, extra | 0x400); - - return 0; -} - -/** - * ich_clear_irq - clear BMDMA status - * @drive: IDE drive - * - * ICHx contollers set DMA INTR no matter DMA or PIO. - * BMDMA status might need to be cleared even for - * PIO interrupts to prevent spurious/lost IRQ. - */ -static void ich_clear_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u8 dma_stat; - - /* - * ide_dma_end() needs BMDMA status for error checking. - * So, skip clearing BMDMA status here and leave it - * to ide_dma_end() if this is DMA interrupt. - */ - if (drive->waiting_for_dma || hwif->dma_base == 0) - return; - - /* clear the INTR & ERROR bits */ - dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); - /* Should we force the bit as well ? */ - outb(dma_stat, hwif->dma_base + ATA_DMA_STATUS); -} - -struct ich_laptop { - u16 device; - u16 subvendor; - u16 subdevice; -}; - -/* - * List of laptops that use short cables rather than 80 wire - */ - -static const struct ich_laptop ich_laptop[] = { - /* devid, subvendor, subdev */ - { 0x27DF, 0x1025, 0x0102 }, /* ICH7 on Acer 5602aWLMi */ - { 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */ - { 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */ - { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */ - { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */ - { 0x27DF, 0x1071, 0xD221 }, /* ICH7 on Hercules EC-900 */ - { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on Acer Aspire 2023WLMi */ - { 0x24CA, 0x1025, 0x003d }, /* ICH4 on ACER TM290 */ - { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */ - { 0x2653, 0x1043, 0x82D8 }, /* ICH6M on Asus Eee 701 */ - { 0x27df, 0x104d, 0x900e }, /* ICH7 on Sony TZ-90 */ - /* end marker */ - { 0, } -}; - -static u8 piix_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *pdev = to_pci_dev(hwif->dev); - const struct ich_laptop *lap = &ich_laptop[0]; - u8 reg54h = 0, mask = hwif->channel ? 0xc0 : 0x30; - - /* check for specials */ - while (lap->device) { - if (lap->device == pdev->device && - lap->subvendor == pdev->subsystem_vendor && - lap->subdevice == pdev->subsystem_device) { - return ATA_CBL_PATA40_SHORT; - } - lap++; - } - - pci_read_config_byte(pdev, 0x54, ®54h); - - return (reg54h & mask) ? ATA_CBL_PATA80 : ATA_CBL_PATA40; -} - -/** - * init_hwif_piix - fill in the hwif for the PIIX - * @hwif: IDE interface - * - * Set up the ide_hwif_t for the PIIX interface according to the - * capabilities of the hardware. - */ - -static void init_hwif_piix(ide_hwif_t *hwif) -{ - if (!hwif->dma_base) - return; - - if (no_piix_dma) - hwif->ultra_mask = hwif->mwdma_mask = hwif->swdma_mask = 0; -} - -static const struct ide_port_ops piix_port_ops = { - .set_pio_mode = piix_set_pio_mode, - .set_dma_mode = piix_set_dma_mode, - .cable_detect = piix_cable_detect, -}; - -static const struct ide_port_ops ich_port_ops = { - .set_pio_mode = piix_set_pio_mode, - .set_dma_mode = piix_set_dma_mode, - .clear_irq = ich_clear_irq, - .cable_detect = piix_cable_detect, -}; - -#define DECLARE_PIIX_DEV(udma) \ - { \ - .name = DRV_NAME, \ - .init_hwif = init_hwif_piix, \ - .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \ - .port_ops = &piix_port_ops, \ - .pio_mask = ATA_PIO4, \ - .swdma_mask = ATA_SWDMA2_ONLY, \ - .mwdma_mask = ATA_MWDMA12_ONLY, \ - .udma_mask = udma, \ - } - -#define DECLARE_ICH_DEV(mwdma, udma) \ - { \ - .name = DRV_NAME, \ - .init_chipset = init_chipset_ich, \ - .init_hwif = init_hwif_piix, \ - .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \ - .port_ops = &ich_port_ops, \ - .pio_mask = ATA_PIO4, \ - .swdma_mask = ATA_SWDMA2_ONLY, \ - .mwdma_mask = mwdma, \ - .udma_mask = udma, \ - } - -static const struct ide_port_info piix_pci_info[] = { - /* 0: MPIIX */ - { /* - * MPIIX actually has only a single IDE channel mapped to - * the primary or secondary ports depending on the value - * of the bit 14 of the IDETIM register at offset 0x6c - */ - .name = DRV_NAME, - .enablebits = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}}, - .host_flags = IDE_HFLAG_ISA_PORTS | IDE_HFLAG_NO_DMA, - .pio_mask = ATA_PIO4, - /* This is a painful system best to let it self tune for now */ - }, - /* 1: PIIXa/PIIXb/PIIX3 */ - DECLARE_PIIX_DEV(0x00), /* no udma */ - /* 2: PIIX4 */ - DECLARE_PIIX_DEV(ATA_UDMA2), - /* 3: ICH0 */ - DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA2), - /* 4: ICH */ - DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA4), - /* 5: PIIX4 */ - DECLARE_PIIX_DEV(ATA_UDMA4), - /* 6: ICH[2-6]/ICH[2-3]M/C-ICH/ICH5-SATA/ESB2/ICH8M */ - DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA5), - /* 7: ICH7/7-R, no MWDMA1 */ - DECLARE_ICH_DEV(ATA_MWDMA2_ONLY, ATA_UDMA5), -}; - -/** - * piix_init_one - called when a PIIX is found - * @dev: the piix device - * @id: the matching pci id - * - * Called when the PCI registration layer (or the IDE initialization) - * finds a device matching our IDE device tables. - */ - -static int piix_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_pci_init_one(dev, &piix_pci_info[id->driver_data], NULL); -} - -/** - * piix_check_450nx - Check for problem 450NX setup - * - * Check for the present of 450NX errata #19 and errata #25. If - * they are found, disable use of DMA IDE - */ - -static void piix_check_450nx(void) -{ - struct pci_dev *pdev = NULL; - u16 cfg; - while((pdev=pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL) - { - /* Look for 450NX PXB. Check for problem configurations - A PCI quirk checks bit 6 already */ - pci_read_config_word(pdev, 0x41, &cfg); - /* Only on the original revision: IDE DMA can hang */ - if (pdev->revision == 0x00) - no_piix_dma = 1; - /* On all revisions below 5 PXB bus lock must be disabled for IDE */ - else if (cfg & (1<<14) && pdev->revision < 5) - no_piix_dma = 2; - } - if(no_piix_dma) - printk(KERN_WARNING DRV_NAME ": 450NX errata present, disabling IDE DMA.\n"); - if(no_piix_dma == 2) - printk(KERN_WARNING DRV_NAME ": A BIOS update may resolve this.\n"); -} - -static const struct pci_device_id piix_pci_tbl[] = { - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371FB_0), 1 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371FB_1), 1 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX), 0 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371SB_1), 1 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371AB), 2 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801AB_1), 3 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82443MX_1), 2 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801AA_1), 4 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82372FB_1), 5 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82451NX), 2 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801BA_9), 6 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801BA_8), 6 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801CA_10), 6 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801CA_11), 6 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_11), 6 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801EB_11), 6 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801E_11), 6 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_10), 6 }, -#ifdef CONFIG_BLK_DEV_IDE_SATA - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801EB_1), 6 }, -#endif - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB_2), 6 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH6_19), 6 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH7_21), 7 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_1), 6 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18), 7 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH8_6), 6 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, piix_pci_tbl); - -static struct pci_driver piix_pci_driver = { - .name = "PIIX_IDE", - .id_table = piix_pci_tbl, - .probe = piix_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init piix_ide_init(void) -{ - piix_check_450nx(); - return ide_pci_register_driver(&piix_pci_driver); -} - -static void __exit piix_ide_exit(void) -{ - pci_unregister_driver(&piix_pci_driver); -} - -module_init(piix_ide_init); -module_exit(piix_ide_exit); - -MODULE_AUTHOR("Andre Hedrick, Andrzej Krzysztofowicz"); -MODULE_DESCRIPTION("PCI driver module for Intel PIIX IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c deleted file mode 100644 index ea0b064b5f56..000000000000 --- a/drivers/ide/pmac.c +++ /dev/null @@ -1,1703 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Support for IDE interfaces on PowerMacs. - * - * These IDE interfaces are memory-mapped and have a DBDMA channel - * for doing DMA. - * - * Copyright (C) 1998-2003 Paul Mackerras & Ben. Herrenschmidt - * Copyright (C) 2007-2008 Bartlomiej Zolnierkiewicz - * - * Some code taken from drivers/ide/ide-dma.c: - * - * Copyright (c) 1995-1998 Mark Lord - * - * TODO: - Use pre-calculated (kauai) timing tables all the time and - * get rid of the "rounded" tables used previously, so we have the - * same table format for all controllers and can then just have one - * big table - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "ide-pmac" - -#undef IDE_PMAC_DEBUG - -#define DMA_WAIT_TIMEOUT 50 - -typedef struct pmac_ide_hwif { - unsigned long regbase; - int irq; - int kind; - int aapl_bus_id; - unsigned broken_dma : 1; - unsigned broken_dma_warn : 1; - struct device_node* node; - struct macio_dev *mdev; - u32 timings[4]; - volatile u32 __iomem * *kauai_fcr; - ide_hwif_t *hwif; - - /* Those fields are duplicating what is in hwif. We currently - * can't use the hwif ones because of some assumptions that are - * beeing done by the generic code about the kind of dma controller - * and format of the dma table. This will have to be fixed though. - */ - volatile struct dbdma_regs __iomem * dma_regs; - struct dbdma_cmd* dma_table_cpu; -} pmac_ide_hwif_t; - -enum { - controller_ohare, /* OHare based */ - controller_heathrow, /* Heathrow/Paddington */ - controller_kl_ata3, /* KeyLargo ATA-3 */ - controller_kl_ata4, /* KeyLargo ATA-4 */ - controller_un_ata6, /* UniNorth2 ATA-6 */ - controller_k2_ata6, /* K2 ATA-6 */ - controller_sh_ata6, /* Shasta ATA-6 */ -}; - -static const char* model_name[] = { - "OHare ATA", /* OHare based */ - "Heathrow ATA", /* Heathrow/Paddington */ - "KeyLargo ATA-3", /* KeyLargo ATA-3 (MDMA only) */ - "KeyLargo ATA-4", /* KeyLargo ATA-4 (UDMA/66) */ - "UniNorth ATA-6", /* UniNorth2 ATA-6 (UDMA/100) */ - "K2 ATA-6", /* K2 ATA-6 (UDMA/100) */ - "Shasta ATA-6", /* Shasta ATA-6 (UDMA/133) */ -}; - -/* - * Extra registers, both 32-bit little-endian - */ -#define IDE_TIMING_CONFIG 0x200 -#define IDE_INTERRUPT 0x300 - -/* Kauai (U2) ATA has different register setup */ -#define IDE_KAUAI_PIO_CONFIG 0x200 -#define IDE_KAUAI_ULTRA_CONFIG 0x210 -#define IDE_KAUAI_POLL_CONFIG 0x220 - -/* - * Timing configuration register definitions - */ - -/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */ -#define SYSCLK_TICKS(t) (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS) -#define SYSCLK_TICKS_66(t) (((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS) -#define IDE_SYSCLK_NS 30 /* 33Mhz cell */ -#define IDE_SYSCLK_66_NS 15 /* 66Mhz cell */ - -/* 133Mhz cell, found in shasta. - * See comments about 100 Mhz Uninorth 2... - * Note that PIO_MASK and MDMA_MASK seem to overlap - */ -#define TR_133_PIOREG_PIO_MASK 0xff000fff -#define TR_133_PIOREG_MDMA_MASK 0x00fff800 -#define TR_133_UDMAREG_UDMA_MASK 0x0003ffff -#define TR_133_UDMAREG_UDMA_EN 0x00000001 - -/* 100Mhz cell, found in Uninorth 2. I don't have much infos about - * this one yet, it appears as a pci device (106b/0033) on uninorth - * internal PCI bus and it's clock is controlled like gem or fw. It - * appears to be an evolution of keylargo ATA4 with a timing register - * extended to 2 32bits registers and a similar DBDMA channel. Other - * registers seem to exist but I can't tell much about them. - * - * So far, I'm using pre-calculated tables for this extracted from - * the values used by the MacOS X driver. - * - * The "PIO" register controls PIO and MDMA timings, the "ULTRA" - * register controls the UDMA timings. At least, it seems bit 0 - * of this one enables UDMA vs. MDMA, and bits 4..7 are the - * cycle time in units of 10ns. Bits 8..15 are used by I don't - * know their meaning yet - */ -#define TR_100_PIOREG_PIO_MASK 0xff000fff -#define TR_100_PIOREG_MDMA_MASK 0x00fff000 -#define TR_100_UDMAREG_UDMA_MASK 0x0000ffff -#define TR_100_UDMAREG_UDMA_EN 0x00000001 - - -/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on - * 40 connector cable and to 4 on 80 connector one. - * Clock unit is 15ns (66Mhz) - * - * 3 Values can be programmed: - * - Write data setup, which appears to match the cycle time. They - * also call it DIOW setup. - * - Ready to pause time (from spec) - * - Address setup. That one is weird. I don't see where exactly - * it fits in UDMA cycles, I got it's name from an obscure piece - * of commented out code in Darwin. They leave it to 0, we do as - * well, despite a comment that would lead to think it has a - * min value of 45ns. - * Apple also add 60ns to the write data setup (or cycle time ?) on - * reads. - */ -#define TR_66_UDMA_MASK 0xfff00000 -#define TR_66_UDMA_EN 0x00100000 /* Enable Ultra mode for DMA */ -#define TR_66_UDMA_ADDRSETUP_MASK 0xe0000000 /* Address setup */ -#define TR_66_UDMA_ADDRSETUP_SHIFT 29 -#define TR_66_UDMA_RDY2PAUS_MASK 0x1e000000 /* Ready 2 pause time */ -#define TR_66_UDMA_RDY2PAUS_SHIFT 25 -#define TR_66_UDMA_WRDATASETUP_MASK 0x01e00000 /* Write data setup time */ -#define TR_66_UDMA_WRDATASETUP_SHIFT 21 -#define TR_66_MDMA_MASK 0x000ffc00 -#define TR_66_MDMA_RECOVERY_MASK 0x000f8000 -#define TR_66_MDMA_RECOVERY_SHIFT 15 -#define TR_66_MDMA_ACCESS_MASK 0x00007c00 -#define TR_66_MDMA_ACCESS_SHIFT 10 -#define TR_66_PIO_MASK 0x000003ff -#define TR_66_PIO_RECOVERY_MASK 0x000003e0 -#define TR_66_PIO_RECOVERY_SHIFT 5 -#define TR_66_PIO_ACCESS_MASK 0x0000001f -#define TR_66_PIO_ACCESS_SHIFT 0 - -/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo - * Can do pio & mdma modes, clock unit is 30ns (33Mhz) - * - * The access time and recovery time can be programmed. Some older - * Darwin code base limit OHare to 150ns cycle time. I decided to do - * the same here fore safety against broken old hardware ;) - * The HalfTick bit, when set, adds half a clock (15ns) to the access - * time and removes one from recovery. It's not supported on KeyLargo - * implementation afaik. The E bit appears to be set for PIO mode 0 and - * is used to reach long timings used in this mode. - */ -#define TR_33_MDMA_MASK 0x003ff800 -#define TR_33_MDMA_RECOVERY_MASK 0x001f0000 -#define TR_33_MDMA_RECOVERY_SHIFT 16 -#define TR_33_MDMA_ACCESS_MASK 0x0000f800 -#define TR_33_MDMA_ACCESS_SHIFT 11 -#define TR_33_MDMA_HALFTICK 0x00200000 -#define TR_33_PIO_MASK 0x000007ff -#define TR_33_PIO_E 0x00000400 -#define TR_33_PIO_RECOVERY_MASK 0x000003e0 -#define TR_33_PIO_RECOVERY_SHIFT 5 -#define TR_33_PIO_ACCESS_MASK 0x0000001f -#define TR_33_PIO_ACCESS_SHIFT 0 - -/* - * Interrupt register definitions - */ -#define IDE_INTR_DMA 0x80000000 -#define IDE_INTR_DEVICE 0x40000000 - -/* - * FCR Register on Kauai. Not sure what bit 0x4 is ... - */ -#define KAUAI_FCR_UATA_MAGIC 0x00000004 -#define KAUAI_FCR_UATA_RESET_N 0x00000002 -#define KAUAI_FCR_UATA_ENABLE 0x00000001 - -/* Rounded Multiword DMA timings - * - * I gave up finding a generic formula for all controller - * types and instead, built tables based on timing values - * used by Apple in Darwin's implementation. - */ -struct mdma_timings_t { - int accessTime; - int recoveryTime; - int cycleTime; -}; - -struct mdma_timings_t mdma_timings_33[] = -{ - { 240, 240, 480 }, - { 180, 180, 360 }, - { 135, 135, 270 }, - { 120, 120, 240 }, - { 105, 105, 210 }, - { 90, 90, 180 }, - { 75, 75, 150 }, - { 75, 45, 120 }, - { 0, 0, 0 } -}; - -struct mdma_timings_t mdma_timings_33k[] = -{ - { 240, 240, 480 }, - { 180, 180, 360 }, - { 150, 150, 300 }, - { 120, 120, 240 }, - { 90, 120, 210 }, - { 90, 90, 180 }, - { 90, 60, 150 }, - { 90, 30, 120 }, - { 0, 0, 0 } -}; - -struct mdma_timings_t mdma_timings_66[] = -{ - { 240, 240, 480 }, - { 180, 180, 360 }, - { 135, 135, 270 }, - { 120, 120, 240 }, - { 105, 105, 210 }, - { 90, 90, 180 }, - { 90, 75, 165 }, - { 75, 45, 120 }, - { 0, 0, 0 } -}; - -/* KeyLargo ATA-4 Ultra DMA timings (rounded) */ -struct { - int addrSetup; /* ??? */ - int rdy2pause; - int wrDataSetup; -} kl66_udma_timings[] = -{ - { 0, 180, 120 }, /* Mode 0 */ - { 0, 150, 90 }, /* 1 */ - { 0, 120, 60 }, /* 2 */ - { 0, 90, 45 }, /* 3 */ - { 0, 90, 30 } /* 4 */ -}; - -/* UniNorth 2 ATA/100 timings */ -struct kauai_timing { - int cycle_time; - u32 timing_reg; -}; - -static struct kauai_timing kauai_pio_timings[] = -{ - { 930 , 0x08000fff }, - { 600 , 0x08000a92 }, - { 383 , 0x0800060f }, - { 360 , 0x08000492 }, - { 330 , 0x0800048f }, - { 300 , 0x080003cf }, - { 270 , 0x080003cc }, - { 240 , 0x0800038b }, - { 239 , 0x0800030c }, - { 180 , 0x05000249 }, - { 120 , 0x04000148 }, - { 0 , 0 }, -}; - -static struct kauai_timing kauai_mdma_timings[] = -{ - { 1260 , 0x00fff000 }, - { 480 , 0x00618000 }, - { 360 , 0x00492000 }, - { 270 , 0x0038e000 }, - { 240 , 0x0030c000 }, - { 210 , 0x002cb000 }, - { 180 , 0x00249000 }, - { 150 , 0x00209000 }, - { 120 , 0x00148000 }, - { 0 , 0 }, -}; - -static struct kauai_timing kauai_udma_timings[] = -{ - { 120 , 0x000070c0 }, - { 90 , 0x00005d80 }, - { 60 , 0x00004a60 }, - { 45 , 0x00003a50 }, - { 30 , 0x00002a30 }, - { 20 , 0x00002921 }, - { 0 , 0 }, -}; - -static struct kauai_timing shasta_pio_timings[] = -{ - { 930 , 0x08000fff }, - { 600 , 0x0A000c97 }, - { 383 , 0x07000712 }, - { 360 , 0x040003cd }, - { 330 , 0x040003cd }, - { 300 , 0x040003cd }, - { 270 , 0x040003cd }, - { 240 , 0x040003cd }, - { 239 , 0x040003cd }, - { 180 , 0x0400028b }, - { 120 , 0x0400010a }, - { 0 , 0 }, -}; - -static struct kauai_timing shasta_mdma_timings[] = -{ - { 1260 , 0x00fff000 }, - { 480 , 0x00820800 }, - { 360 , 0x00820800 }, - { 270 , 0x00820800 }, - { 240 , 0x00820800 }, - { 210 , 0x00820800 }, - { 180 , 0x00820800 }, - { 150 , 0x0028b000 }, - { 120 , 0x001ca000 }, - { 0 , 0 }, -}; - -static struct kauai_timing shasta_udma133_timings[] = -{ - { 120 , 0x00035901, }, - { 90 , 0x000348b1, }, - { 60 , 0x00033881, }, - { 45 , 0x00033861, }, - { 30 , 0x00033841, }, - { 20 , 0x00033031, }, - { 15 , 0x00033021, }, - { 0 , 0 }, -}; - - -static inline u32 -kauai_lookup_timing(struct kauai_timing* table, int cycle_time) -{ - int i; - - for (i=0; table[i].cycle_time; i++) - if (cycle_time > table[i+1].cycle_time) - return table[i].timing_reg; - BUG(); - return 0; -} - -/* allow up to 256 DBDMA commands per xfer */ -#define MAX_DCMDS 256 - -/* - * Wait 1s for disk to answer on IDE bus after a hard reset - * of the device (via GPIO/FCR). - * - * Some devices seem to "pollute" the bus even after dropping - * the BSY bit (typically some combo drives slave on the UDMA - * bus) after a hard reset. Since we hard reset all drives on - * KeyLargo ATA66, we have to keep that delay around. I may end - * up not hard resetting anymore on these and keep the delay only - * for older interfaces instead (we have to reset when coming - * from MacOS...) --BenH. - */ -#define IDE_WAKEUP_DELAY (1*HZ) - -static int pmac_ide_init_dma(ide_hwif_t *, const struct ide_port_info *); - -#define PMAC_IDE_REG(x) \ - ((void __iomem *)((drive)->hwif->io_ports.data_addr + (x))) - -/* - * Apply the timings of the proper unit (master/slave) to the shared - * timing register when selecting that unit. This version is for - * ASICs with a single timing register - */ -static void pmac_ide_apply_timings(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); - - if (drive->dn & 1) - writel(pmif->timings[1], PMAC_IDE_REG(IDE_TIMING_CONFIG)); - else - writel(pmif->timings[0], PMAC_IDE_REG(IDE_TIMING_CONFIG)); - (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG)); -} - -/* - * Apply the timings of the proper unit (master/slave) to the shared - * timing register when selecting that unit. This version is for - * ASICs with a dual timing register (Kauai) - */ -static void pmac_ide_kauai_apply_timings(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); - - if (drive->dn & 1) { - writel(pmif->timings[1], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG)); - writel(pmif->timings[3], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG)); - } else { - writel(pmif->timings[0], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG)); - writel(pmif->timings[2], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG)); - } - (void)readl(PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG)); -} - -/* - * Force an update of controller timing values for a given drive - */ -static void -pmac_ide_do_update_timings(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); - - if (pmif->kind == controller_sh_ata6 || - pmif->kind == controller_un_ata6 || - pmif->kind == controller_k2_ata6) - pmac_ide_kauai_apply_timings(drive); - else - pmac_ide_apply_timings(drive); -} - -static void pmac_dev_select(ide_drive_t *drive) -{ - pmac_ide_apply_timings(drive); - - writeb(drive->select | ATA_DEVICE_OBS, - (void __iomem *)drive->hwif->io_ports.device_addr); -} - -static void pmac_kauai_dev_select(ide_drive_t *drive) -{ - pmac_ide_kauai_apply_timings(drive); - - writeb(drive->select | ATA_DEVICE_OBS, - (void __iomem *)drive->hwif->io_ports.device_addr); -} - -static void pmac_exec_command(ide_hwif_t *hwif, u8 cmd) -{ - writeb(cmd, (void __iomem *)hwif->io_ports.command_addr); - (void)readl((void __iomem *)(hwif->io_ports.data_addr - + IDE_TIMING_CONFIG)); -} - -static void pmac_write_devctl(ide_hwif_t *hwif, u8 ctl) -{ - writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr); - (void)readl((void __iomem *)(hwif->io_ports.data_addr - + IDE_TIMING_CONFIG)); -} - -/* - * Old tuning functions (called on hdparm -p), sets up drive PIO timings - */ -static void pmac_ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); - const u8 pio = drive->pio_mode - XFER_PIO_0; - struct ide_timing *tim = ide_timing_find_mode(XFER_PIO_0 + pio); - u32 *timings, t; - unsigned accessTicks, recTicks; - unsigned accessTime, recTime; - unsigned int cycle_time; - - /* which drive is it ? */ - timings = &pmif->timings[drive->dn & 1]; - t = *timings; - - cycle_time = ide_pio_cycle_time(drive, pio); - - switch (pmif->kind) { - case controller_sh_ata6: { - /* 133Mhz cell */ - u32 tr = kauai_lookup_timing(shasta_pio_timings, cycle_time); - t = (t & ~TR_133_PIOREG_PIO_MASK) | tr; - break; - } - case controller_un_ata6: - case controller_k2_ata6: { - /* 100Mhz cell */ - u32 tr = kauai_lookup_timing(kauai_pio_timings, cycle_time); - t = (t & ~TR_100_PIOREG_PIO_MASK) | tr; - break; - } - case controller_kl_ata4: - /* 66Mhz cell */ - recTime = cycle_time - tim->active - tim->setup; - recTime = max(recTime, 150U); - accessTime = tim->active; - accessTime = max(accessTime, 150U); - accessTicks = SYSCLK_TICKS_66(accessTime); - accessTicks = min(accessTicks, 0x1fU); - recTicks = SYSCLK_TICKS_66(recTime); - recTicks = min(recTicks, 0x1fU); - t = (t & ~TR_66_PIO_MASK) | - (accessTicks << TR_66_PIO_ACCESS_SHIFT) | - (recTicks << TR_66_PIO_RECOVERY_SHIFT); - break; - default: { - /* 33Mhz cell */ - int ebit = 0; - recTime = cycle_time - tim->active - tim->setup; - recTime = max(recTime, 150U); - accessTime = tim->active; - accessTime = max(accessTime, 150U); - accessTicks = SYSCLK_TICKS(accessTime); - accessTicks = min(accessTicks, 0x1fU); - accessTicks = max(accessTicks, 4U); - recTicks = SYSCLK_TICKS(recTime); - recTicks = min(recTicks, 0x1fU); - recTicks = max(recTicks, 5U) - 4; - if (recTicks > 9) { - recTicks--; /* guess, but it's only for PIO0, so... */ - ebit = 1; - } - t = (t & ~TR_33_PIO_MASK) | - (accessTicks << TR_33_PIO_ACCESS_SHIFT) | - (recTicks << TR_33_PIO_RECOVERY_SHIFT); - if (ebit) - t |= TR_33_PIO_E; - break; - } - } - -#ifdef IDE_PMAC_DEBUG - printk(KERN_ERR "%s: Set PIO timing for mode %d, reg: 0x%08x\n", - drive->name, pio, *timings); -#endif - - *timings = t; - pmac_ide_do_update_timings(drive); -} - -/* - * Calculate KeyLargo ATA/66 UDMA timings - */ -static int -set_timings_udma_ata4(u32 *timings, u8 speed) -{ - unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks; - - if (speed > XFER_UDMA_4) - return 1; - - rdyToPauseTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].rdy2pause); - wrDataSetupTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].wrDataSetup); - addrTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].addrSetup); - - *timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) | - (wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | - (rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) | - (addrTicks < XFER_UDMA_5 || t == NULL) - return 1; - tr = kauai_lookup_timing(kauai_udma_timings, (int)t->udma); - *ultra_timings = ((*ultra_timings) & ~TR_100_UDMAREG_UDMA_MASK) | tr; - *ultra_timings = (*ultra_timings) | TR_100_UDMAREG_UDMA_EN; - - return 0; -} - -/* - * Calculate Shasta ATA/133 UDMA timings - */ -static int -set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed) -{ - struct ide_timing *t = ide_timing_find_mode(speed); - u32 tr; - - if (speed > XFER_UDMA_6 || t == NULL) - return 1; - tr = kauai_lookup_timing(shasta_udma133_timings, (int)t->udma); - *ultra_timings = ((*ultra_timings) & ~TR_133_UDMAREG_UDMA_MASK) | tr; - *ultra_timings = (*ultra_timings) | TR_133_UDMAREG_UDMA_EN; - - return 0; -} - -/* - * Calculate MDMA timings for all cells - */ -static void -set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, - u8 speed) -{ - u16 *id = drive->id; - int cycleTime, accessTime = 0, recTime = 0; - unsigned accessTicks, recTicks; - struct mdma_timings_t* tm = NULL; - int i; - - /* Get default cycle time for mode */ - switch(speed & 0xf) { - case 0: cycleTime = 480; break; - case 1: cycleTime = 150; break; - case 2: cycleTime = 120; break; - default: - BUG(); - break; - } - - /* Check if drive provides explicit DMA cycle time */ - if ((id[ATA_ID_FIELD_VALID] & 2) && id[ATA_ID_EIDE_DMA_TIME]) - cycleTime = max_t(int, id[ATA_ID_EIDE_DMA_TIME], cycleTime); - - /* OHare limits according to some old Apple sources */ - if ((intf_type == controller_ohare) && (cycleTime < 150)) - cycleTime = 150; - /* Get the proper timing array for this controller */ - switch(intf_type) { - case controller_sh_ata6: - case controller_un_ata6: - case controller_k2_ata6: - break; - case controller_kl_ata4: - tm = mdma_timings_66; - break; - case controller_kl_ata3: - tm = mdma_timings_33k; - break; - default: - tm = mdma_timings_33; - break; - } - if (tm != NULL) { - /* Lookup matching access & recovery times */ - i = -1; - for (;;) { - if (tm[i+1].cycleTime < cycleTime) - break; - i++; - } - cycleTime = tm[i].cycleTime; - accessTime = tm[i].accessTime; - recTime = tm[i].recoveryTime; - -#ifdef IDE_PMAC_DEBUG - printk(KERN_ERR "%s: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n", - drive->name, cycleTime, accessTime, recTime); -#endif - } - switch(intf_type) { - case controller_sh_ata6: { - /* 133Mhz cell */ - u32 tr = kauai_lookup_timing(shasta_mdma_timings, cycleTime); - *timings = ((*timings) & ~TR_133_PIOREG_MDMA_MASK) | tr; - *timings2 = (*timings2) & ~TR_133_UDMAREG_UDMA_EN; - } - break; - case controller_un_ata6: - case controller_k2_ata6: { - /* 100Mhz cell */ - u32 tr = kauai_lookup_timing(kauai_mdma_timings, cycleTime); - *timings = ((*timings) & ~TR_100_PIOREG_MDMA_MASK) | tr; - *timings2 = (*timings2) & ~TR_100_UDMAREG_UDMA_EN; - } - break; - case controller_kl_ata4: - /* 66Mhz cell */ - accessTicks = SYSCLK_TICKS_66(accessTime); - accessTicks = min(accessTicks, 0x1fU); - accessTicks = max(accessTicks, 0x1U); - recTicks = SYSCLK_TICKS_66(recTime); - recTicks = min(recTicks, 0x1fU); - recTicks = max(recTicks, 0x3U); - /* Clear out mdma bits and disable udma */ - *timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) | - (accessTicks << TR_66_MDMA_ACCESS_SHIFT) | - (recTicks << TR_66_MDMA_RECOVERY_SHIFT); - break; - case controller_kl_ata3: - /* 33Mhz cell on KeyLargo */ - accessTicks = SYSCLK_TICKS(accessTime); - accessTicks = max(accessTicks, 1U); - accessTicks = min(accessTicks, 0x1fU); - accessTime = accessTicks * IDE_SYSCLK_NS; - recTicks = SYSCLK_TICKS(recTime); - recTicks = max(recTicks, 1U); - recTicks = min(recTicks, 0x1fU); - *timings = ((*timings) & ~TR_33_MDMA_MASK) | - (accessTicks << TR_33_MDMA_ACCESS_SHIFT) | - (recTicks << TR_33_MDMA_RECOVERY_SHIFT); - break; - default: { - /* 33Mhz cell on others */ - int halfTick = 0; - int origAccessTime = accessTime; - int origRecTime = recTime; - - accessTicks = SYSCLK_TICKS(accessTime); - accessTicks = max(accessTicks, 1U); - accessTicks = min(accessTicks, 0x1fU); - accessTime = accessTicks * IDE_SYSCLK_NS; - recTicks = SYSCLK_TICKS(recTime); - recTicks = max(recTicks, 2U) - 1; - recTicks = min(recTicks, 0x1fU); - recTime = (recTicks + 1) * IDE_SYSCLK_NS; - if ((accessTicks > 1) && - ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) && - ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) { - halfTick = 1; - accessTicks--; - } - *timings = ((*timings) & ~TR_33_MDMA_MASK) | - (accessTicks << TR_33_MDMA_ACCESS_SHIFT) | - (recTicks << TR_33_MDMA_RECOVERY_SHIFT); - if (halfTick) - *timings |= TR_33_MDMA_HALFTICK; - } - } -#ifdef IDE_PMAC_DEBUG - printk(KERN_ERR "%s: Set MDMA timing for mode %d, reg: 0x%08x\n", - drive->name, speed & 0xf, *timings); -#endif -} - -static void pmac_ide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); - int ret = 0; - u32 *timings, *timings2, tl[2]; - u8 unit = drive->dn & 1; - const u8 speed = drive->dma_mode; - - timings = &pmif->timings[unit]; - timings2 = &pmif->timings[unit+2]; - - /* Copy timings to local image */ - tl[0] = *timings; - tl[1] = *timings2; - - if (speed >= XFER_UDMA_0) { - if (pmif->kind == controller_kl_ata4) - ret = set_timings_udma_ata4(&tl[0], speed); - else if (pmif->kind == controller_un_ata6 - || pmif->kind == controller_k2_ata6) - ret = set_timings_udma_ata6(&tl[0], &tl[1], speed); - else if (pmif->kind == controller_sh_ata6) - ret = set_timings_udma_shasta(&tl[0], &tl[1], speed); - else - ret = -1; - } else - set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed); - - if (ret) - return; - - /* Apply timings to controller */ - *timings = tl[0]; - *timings2 = tl[1]; - - pmac_ide_do_update_timings(drive); -} - -/* - * Blast some well known "safe" values to the timing registers at init or - * wakeup from sleep time, before we do real calculation - */ -static void -sanitize_timings(pmac_ide_hwif_t *pmif) -{ - unsigned int value, value2 = 0; - - switch(pmif->kind) { - case controller_sh_ata6: - value = 0x0a820c97; - value2 = 0x00033031; - break; - case controller_un_ata6: - case controller_k2_ata6: - value = 0x08618a92; - value2 = 0x00002921; - break; - case controller_kl_ata4: - value = 0x0008438c; - break; - case controller_kl_ata3: - value = 0x00084526; - break; - case controller_heathrow: - case controller_ohare: - default: - value = 0x00074526; - break; - } - pmif->timings[0] = pmif->timings[1] = value; - pmif->timings[2] = pmif->timings[3] = value2; -} - -static int on_media_bay(pmac_ide_hwif_t *pmif) -{ - return pmif->mdev && pmif->mdev->media_bay != NULL; -} - -/* Suspend call back, should be called after the child devices - * have actually been suspended - */ -static int pmac_ide_do_suspend(pmac_ide_hwif_t *pmif) -{ - /* We clear the timings */ - pmif->timings[0] = 0; - pmif->timings[1] = 0; - - disable_irq(pmif->irq); - - /* The media bay will handle itself just fine */ - if (on_media_bay(pmif)) - return 0; - - /* Kauai has bus control FCRs directly here */ - if (pmif->kauai_fcr) { - u32 fcr = readl(pmif->kauai_fcr); - fcr &= ~(KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE); - writel(fcr, pmif->kauai_fcr); - } - - /* Disable the bus on older machines and the cell on kauai */ - ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, - 0); - - return 0; -} - -/* Resume call back, should be called before the child devices - * are resumed - */ -static int pmac_ide_do_resume(pmac_ide_hwif_t *pmif) -{ - /* Hard reset & re-enable controller (do we really need to reset ? -BenH) */ - if (!on_media_bay(pmif)) { - ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 1); - ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 1); - msleep(10); - ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 0); - - /* Kauai has it different */ - if (pmif->kauai_fcr) { - u32 fcr = readl(pmif->kauai_fcr); - fcr |= KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE; - writel(fcr, pmif->kauai_fcr); - } - - msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY)); - } - - /* Sanitize drive timings */ - sanitize_timings(pmif); - - enable_irq(pmif->irq); - - return 0; -} - -static u8 pmac_ide_cable_detect(ide_hwif_t *hwif) -{ - pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); - struct device_node *np = pmif->node; - const char *cable = of_get_property(np, "cable-type", NULL); - struct device_node *root = of_find_node_by_path("/"); - const char *model = of_get_property(root, "model", NULL); - - of_node_put(root); - /* Get cable type from device-tree. */ - if (cable && !strncmp(cable, "80-", 3)) { - /* Some drives fail to detect 80c cable in PowerBook */ - /* These machine use proprietary short IDE cable anyway */ - if (!strncmp(model, "PowerBook", 9)) - return ATA_CBL_PATA40_SHORT; - else - return ATA_CBL_PATA80; - } - - /* - * G5's seem to have incorrect cable type in device-tree. - * Let's assume they have a 80 conductor cable, this seem - * to be always the case unless the user mucked around. - */ - if (of_device_is_compatible(np, "K2-UATA") || - of_device_is_compatible(np, "shasta-ata")) - return ATA_CBL_PATA80; - - return ATA_CBL_PATA40; -} - -static void pmac_ide_init_dev(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); - - if (on_media_bay(pmif)) { - if (check_media_bay(pmif->mdev->media_bay) == MB_CD) { - drive->dev_flags &= ~IDE_DFLAG_NOPROBE; - return; - } - drive->dev_flags |= IDE_DFLAG_NOPROBE; - } -} - -static const struct ide_tp_ops pmac_tp_ops = { - .exec_command = pmac_exec_command, - .read_status = ide_read_status, - .read_altstatus = ide_read_altstatus, - .write_devctl = pmac_write_devctl, - - .dev_select = pmac_dev_select, - .tf_load = ide_tf_load, - .tf_read = ide_tf_read, - - .input_data = ide_input_data, - .output_data = ide_output_data, -}; - -static const struct ide_tp_ops pmac_ata6_tp_ops = { - .exec_command = pmac_exec_command, - .read_status = ide_read_status, - .read_altstatus = ide_read_altstatus, - .write_devctl = pmac_write_devctl, - - .dev_select = pmac_kauai_dev_select, - .tf_load = ide_tf_load, - .tf_read = ide_tf_read, - - .input_data = ide_input_data, - .output_data = ide_output_data, -}; - -static const struct ide_port_ops pmac_ide_ata4_port_ops = { - .init_dev = pmac_ide_init_dev, - .set_pio_mode = pmac_ide_set_pio_mode, - .set_dma_mode = pmac_ide_set_dma_mode, - .cable_detect = pmac_ide_cable_detect, -}; - -static const struct ide_port_ops pmac_ide_port_ops = { - .init_dev = pmac_ide_init_dev, - .set_pio_mode = pmac_ide_set_pio_mode, - .set_dma_mode = pmac_ide_set_dma_mode, -}; - -static const struct ide_dma_ops pmac_dma_ops; - -static const struct ide_port_info pmac_port_info = { - .name = DRV_NAME, - .init_dma = pmac_ide_init_dma, - .chipset = ide_pmac, - .tp_ops = &pmac_tp_ops, - .port_ops = &pmac_ide_port_ops, - .dma_ops = &pmac_dma_ops, - .host_flags = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA | - IDE_HFLAG_POST_SET_MODE | - IDE_HFLAG_MMIO | - IDE_HFLAG_UNMASK_IRQS, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, -}; - -/* - * Setup, register & probe an IDE channel driven by this driver, this is - * called by one of the 2 probe functions (macio or PCI). - */ -static int pmac_ide_setup_device(pmac_ide_hwif_t *pmif, struct ide_hw *hw) -{ - struct device_node *np = pmif->node; - const int *bidp; - struct ide_host *host; - struct ide_hw *hws[] = { hw }; - struct ide_port_info d = pmac_port_info; - int rc; - - pmif->broken_dma = pmif->broken_dma_warn = 0; - if (of_device_is_compatible(np, "shasta-ata")) { - pmif->kind = controller_sh_ata6; - d.tp_ops = &pmac_ata6_tp_ops; - d.port_ops = &pmac_ide_ata4_port_ops; - d.udma_mask = ATA_UDMA6; - } else if (of_device_is_compatible(np, "kauai-ata")) { - pmif->kind = controller_un_ata6; - d.tp_ops = &pmac_ata6_tp_ops; - d.port_ops = &pmac_ide_ata4_port_ops; - d.udma_mask = ATA_UDMA5; - } else if (of_device_is_compatible(np, "K2-UATA")) { - pmif->kind = controller_k2_ata6; - d.tp_ops = &pmac_ata6_tp_ops; - d.port_ops = &pmac_ide_ata4_port_ops; - d.udma_mask = ATA_UDMA5; - } else if (of_device_is_compatible(np, "keylargo-ata")) { - if (of_node_name_eq(np, "ata-4")) { - pmif->kind = controller_kl_ata4; - d.port_ops = &pmac_ide_ata4_port_ops; - d.udma_mask = ATA_UDMA4; - } else - pmif->kind = controller_kl_ata3; - } else if (of_device_is_compatible(np, "heathrow-ata")) { - pmif->kind = controller_heathrow; - } else { - pmif->kind = controller_ohare; - pmif->broken_dma = 1; - } - - bidp = of_get_property(np, "AAPL,bus-id", NULL); - pmif->aapl_bus_id = bidp ? *bidp : 0; - - /* On Kauai-type controllers, we make sure the FCR is correct */ - if (pmif->kauai_fcr) - writel(KAUAI_FCR_UATA_MAGIC | - KAUAI_FCR_UATA_RESET_N | - KAUAI_FCR_UATA_ENABLE, pmif->kauai_fcr); - - /* Make sure we have sane timings */ - sanitize_timings(pmif); - - /* If we are on a media bay, wait for it to settle and lock it */ - if (pmif->mdev) - lock_media_bay(pmif->mdev->media_bay); - - host = ide_host_alloc(&d, hws, 1); - if (host == NULL) { - rc = -ENOMEM; - goto bail; - } - pmif->hwif = host->ports[0]; - - if (on_media_bay(pmif)) { - /* Fixup bus ID for media bay */ - if (!bidp) - pmif->aapl_bus_id = 1; - } else if (pmif->kind == controller_ohare) { - /* The code below is having trouble on some ohare machines - * (timing related ?). Until I can put my hand on one of these - * units, I keep the old way - */ - ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1); - } else { - /* This is necessary to enable IDE when net-booting */ - ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1); - ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1); - msleep(10); - ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0); - msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY)); - } - - printk(KERN_INFO DRV_NAME ": Found Apple %s controller (%s), " - "bus ID %d%s, irq %d\n", model_name[pmif->kind], - pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id, - on_media_bay(pmif) ? " (mediabay)" : "", hw->irq); - - rc = ide_host_register(host, &d, hws); - if (rc) - pmif->hwif = NULL; - - if (pmif->mdev) - unlock_media_bay(pmif->mdev->media_bay); - - bail: - if (rc && host) - ide_host_free(host); - return rc; -} - -static void pmac_ide_init_ports(struct ide_hw *hw, unsigned long base) -{ - int i; - - for (i = 0; i < 8; ++i) - hw->io_ports_array[i] = base + i * 0x10; - - hw->io_ports.ctl_addr = base + 0x160; -} - -/* - * Attach to a macio probed interface - */ -static int pmac_ide_macio_attach(struct macio_dev *mdev, - const struct of_device_id *match) -{ - void __iomem *base; - unsigned long regbase; - pmac_ide_hwif_t *pmif; - int irq, rc; - struct ide_hw hw; - - pmif = kzalloc(sizeof(*pmif), GFP_KERNEL); - if (pmif == NULL) - return -ENOMEM; - - if (macio_resource_count(mdev) == 0) { - printk(KERN_WARNING "ide-pmac: no address for %pOF\n", - mdev->ofdev.dev.of_node); - rc = -ENXIO; - goto out_free_pmif; - } - - /* Request memory resource for IO ports */ - if (macio_request_resource(mdev, 0, "ide-pmac (ports)")) { - printk(KERN_ERR "ide-pmac: can't request MMIO resource for " - "%pOF!\n", mdev->ofdev.dev.of_node); - rc = -EBUSY; - goto out_free_pmif; - } - - /* XXX This is bogus. Should be fixed in the registry by checking - * the kind of host interrupt controller, a bit like gatwick - * fixes in irq.c. That works well enough for the single case - * where that happens though... - */ - if (macio_irq_count(mdev) == 0) { - printk(KERN_WARNING "ide-pmac: no intrs for device %pOF, using " - "13\n", mdev->ofdev.dev.of_node); - irq = irq_create_mapping(NULL, 13); - } else - irq = macio_irq(mdev, 0); - - base = ioremap(macio_resource_start(mdev, 0), 0x400); - regbase = (unsigned long) base; - - pmif->mdev = mdev; - pmif->node = mdev->ofdev.dev.of_node; - pmif->regbase = regbase; - pmif->irq = irq; - pmif->kauai_fcr = NULL; - - if (macio_resource_count(mdev) >= 2) { - if (macio_request_resource(mdev, 1, "ide-pmac (dma)")) - printk(KERN_WARNING "ide-pmac: can't request DMA " - "resource for %pOF!\n", - mdev->ofdev.dev.of_node); - else - pmif->dma_regs = ioremap(macio_resource_start(mdev, 1), 0x1000); - } else - pmif->dma_regs = NULL; - - dev_set_drvdata(&mdev->ofdev.dev, pmif); - - memset(&hw, 0, sizeof(hw)); - pmac_ide_init_ports(&hw, pmif->regbase); - hw.irq = irq; - hw.dev = &mdev->bus->pdev->dev; - hw.parent = &mdev->ofdev.dev; - - rc = pmac_ide_setup_device(pmif, &hw); - if (rc != 0) { - /* The inteface is released to the common IDE layer */ - dev_set_drvdata(&mdev->ofdev.dev, NULL); - iounmap(base); - if (pmif->dma_regs) { - iounmap(pmif->dma_regs); - macio_release_resource(mdev, 1); - } - macio_release_resource(mdev, 0); - kfree(pmif); - } - - return rc; - -out_free_pmif: - kfree(pmif); - return rc; -} - -static int -pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t mesg) -{ - pmac_ide_hwif_t *pmif = dev_get_drvdata(&mdev->ofdev.dev); - int rc = 0; - - if (mesg.event != mdev->ofdev.dev.power.power_state.event - && (mesg.event & PM_EVENT_SLEEP)) { - rc = pmac_ide_do_suspend(pmif); - if (rc == 0) - mdev->ofdev.dev.power.power_state = mesg; - } - - return rc; -} - -static int -pmac_ide_macio_resume(struct macio_dev *mdev) -{ - pmac_ide_hwif_t *pmif = dev_get_drvdata(&mdev->ofdev.dev); - int rc = 0; - - if (mdev->ofdev.dev.power.power_state.event != PM_EVENT_ON) { - rc = pmac_ide_do_resume(pmif); - if (rc == 0) - mdev->ofdev.dev.power.power_state = PMSG_ON; - } - - return rc; -} - -/* - * Attach to a PCI probed interface - */ -static int pmac_ide_pci_attach(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct device_node *np; - pmac_ide_hwif_t *pmif; - void __iomem *base; - unsigned long rbase, rlen; - int rc; - struct ide_hw hw; - - np = pci_device_to_OF_node(pdev); - if (np == NULL) { - printk(KERN_ERR "ide-pmac: cannot find MacIO node for Kauai ATA interface\n"); - return -ENODEV; - } - - pmif = kzalloc(sizeof(*pmif), GFP_KERNEL); - if (pmif == NULL) - return -ENOMEM; - - if (pci_enable_device(pdev)) { - printk(KERN_WARNING "ide-pmac: Can't enable PCI device for " - "%pOF\n", np); - rc = -ENXIO; - goto out_free_pmif; - } - pci_set_master(pdev); - - if (pci_request_regions(pdev, "Kauai ATA")) { - printk(KERN_ERR "ide-pmac: Cannot obtain PCI resources for " - "%pOF\n", np); - rc = -ENXIO; - goto out_free_pmif; - } - - pmif->mdev = NULL; - pmif->node = np; - - rbase = pci_resource_start(pdev, 0); - rlen = pci_resource_len(pdev, 0); - - base = ioremap(rbase, rlen); - pmif->regbase = (unsigned long) base + 0x2000; - pmif->dma_regs = base + 0x1000; - pmif->kauai_fcr = base; - pmif->irq = pdev->irq; - - pci_set_drvdata(pdev, pmif); - - memset(&hw, 0, sizeof(hw)); - pmac_ide_init_ports(&hw, pmif->regbase); - hw.irq = pdev->irq; - hw.dev = &pdev->dev; - - rc = pmac_ide_setup_device(pmif, &hw); - if (rc != 0) { - /* The inteface is released to the common IDE layer */ - iounmap(base); - pci_release_regions(pdev); - kfree(pmif); - } - - return rc; - -out_free_pmif: - kfree(pmif); - return rc; -} - -static int -pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) -{ - pmac_ide_hwif_t *pmif = pci_get_drvdata(pdev); - int rc = 0; - - if (mesg.event != pdev->dev.power.power_state.event - && (mesg.event & PM_EVENT_SLEEP)) { - rc = pmac_ide_do_suspend(pmif); - if (rc == 0) - pdev->dev.power.power_state = mesg; - } - - return rc; -} - -static int -pmac_ide_pci_resume(struct pci_dev *pdev) -{ - pmac_ide_hwif_t *pmif = pci_get_drvdata(pdev); - int rc = 0; - - if (pdev->dev.power.power_state.event != PM_EVENT_ON) { - rc = pmac_ide_do_resume(pmif); - if (rc == 0) - pdev->dev.power.power_state = PMSG_ON; - } - - return rc; -} - -#ifdef CONFIG_PMAC_MEDIABAY -static void pmac_ide_macio_mb_event(struct macio_dev* mdev, int mb_state) -{ - pmac_ide_hwif_t *pmif = dev_get_drvdata(&mdev->ofdev.dev); - - switch(mb_state) { - case MB_CD: - if (!pmif->hwif->present) - ide_port_scan(pmif->hwif); - break; - default: - if (pmif->hwif->present) - ide_port_unregister_devices(pmif->hwif); - } -} -#endif /* CONFIG_PMAC_MEDIABAY */ - - -static struct of_device_id pmac_ide_macio_match[] = -{ - { - .name = "IDE", - }, - { - .name = "ATA", - }, - { - .type = "ide", - }, - { - .type = "ata", - }, - {}, -}; - -static struct macio_driver pmac_ide_macio_driver = -{ - .driver = { - .name = "ide-pmac", - .owner = THIS_MODULE, - .of_match_table = pmac_ide_macio_match, - }, - .probe = pmac_ide_macio_attach, - .suspend = pmac_ide_macio_suspend, - .resume = pmac_ide_macio_resume, -#ifdef CONFIG_PMAC_MEDIABAY - .mediabay_event = pmac_ide_macio_mb_event, -#endif -}; - -static const struct pci_device_id pmac_ide_pci_match[] = { - { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA), 0 }, - { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100), 0 }, - { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100), 0 }, - { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_SH_ATA), 0 }, - { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA), 0 }, - {}, -}; - -static struct pci_driver pmac_ide_pci_driver = { - .name = "ide-pmac", - .id_table = pmac_ide_pci_match, - .probe = pmac_ide_pci_attach, - .suspend = pmac_ide_pci_suspend, - .resume = pmac_ide_pci_resume, -}; -MODULE_DEVICE_TABLE(pci, pmac_ide_pci_match); - -int __init pmac_ide_probe(void) -{ - int error; - - if (!machine_is(powermac)) - return -ENODEV; - -#ifdef CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST - error = pci_register_driver(&pmac_ide_pci_driver); - if (error) - goto out; - error = macio_register_driver(&pmac_ide_macio_driver); - if (error) { - pci_unregister_driver(&pmac_ide_pci_driver); - goto out; - } -#else - error = macio_register_driver(&pmac_ide_macio_driver); - if (error) - goto out; - error = pci_register_driver(&pmac_ide_pci_driver); - if (error) { - macio_unregister_driver(&pmac_ide_macio_driver); - goto out; - } -#endif -out: - return error; -} - -/* - * pmac_ide_build_dmatable builds the DBDMA command list - * for a transfer and sets the DBDMA channel to point to it. - */ -static int pmac_ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) -{ - ide_hwif_t *hwif = drive->hwif; - pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); - struct dbdma_cmd *table; - volatile struct dbdma_regs __iomem *dma = pmif->dma_regs; - struct scatterlist *sg; - int wr = !!(cmd->tf_flags & IDE_TFLAG_WRITE); - int i = cmd->sg_nents, count = 0; - - /* DMA table is already aligned */ - table = (struct dbdma_cmd *) pmif->dma_table_cpu; - - /* Make sure DMA controller is stopped (necessary ?) */ - writel((RUN|PAUSE|FLUSH|WAKE|DEAD) << 16, &dma->control); - while (readl(&dma->status) & RUN) - udelay(1); - - /* Build DBDMA commands list */ - sg = hwif->sg_table; - while (i && sg_dma_len(sg)) { - u32 cur_addr; - u32 cur_len; - - cur_addr = sg_dma_address(sg); - cur_len = sg_dma_len(sg); - - if (pmif->broken_dma && cur_addr & (L1_CACHE_BYTES - 1)) { - if (pmif->broken_dma_warn == 0) { - printk(KERN_WARNING "%s: DMA on non aligned address, " - "switching to PIO on Ohare chipset\n", drive->name); - pmif->broken_dma_warn = 1; - } - return 0; - } - while (cur_len) { - unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00; - - if (count++ >= MAX_DCMDS) { - printk(KERN_WARNING "%s: DMA table too small\n", - drive->name); - return 0; - } - table->command = cpu_to_le16(wr? OUTPUT_MORE: INPUT_MORE); - table->req_count = cpu_to_le16(tc); - table->phy_addr = cpu_to_le32(cur_addr); - table->cmd_dep = 0; - table->xfer_status = 0; - table->res_count = 0; - cur_addr += tc; - cur_len -= tc; - ++table; - } - sg = sg_next(sg); - i--; - } - - /* convert the last command to an input/output last command */ - if (count) { - table[-1].command = cpu_to_le16(wr? OUTPUT_LAST: INPUT_LAST); - /* add the stop command to the end of the list */ - memset(table, 0, sizeof(struct dbdma_cmd)); - table->command = cpu_to_le16(DBDMA_STOP); - mb(); - writel(hwif->dmatable_dma, &dma->cmdptr); - return 1; - } - - printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name); - - return 0; /* revert to PIO for this request */ -} - -/* - * Prepare a DMA transfer. We build the DMA table, adjust the timings for - * a read on KeyLargo ATA/66 and mark us as waiting for DMA completion - */ -static int pmac_ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) -{ - ide_hwif_t *hwif = drive->hwif; - pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); - u8 unit = drive->dn & 1, ata4 = (pmif->kind == controller_kl_ata4); - u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE); - - if (pmac_ide_build_dmatable(drive, cmd) == 0) - return 1; - - /* Apple adds 60ns to wrDataSetup on reads */ - if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) { - writel(pmif->timings[unit] + (write ? 0 : 0x00800000UL), - PMAC_IDE_REG(IDE_TIMING_CONFIG)); - (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG)); - } - - return 0; -} - -/* - * Kick the DMA controller into life after the DMA command has been issued - * to the drive. - */ -static void -pmac_ide_dma_start(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); - volatile struct dbdma_regs __iomem *dma; - - dma = pmif->dma_regs; - - writel((RUN << 16) | RUN, &dma->control); - /* Make sure it gets to the controller right now */ - (void)readl(&dma->control); -} - -/* - * After a DMA transfer, make sure the controller is stopped - */ -static int -pmac_ide_dma_end (ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); - volatile struct dbdma_regs __iomem *dma = pmif->dma_regs; - u32 dstat; - - dstat = readl(&dma->status); - writel(((RUN|WAKE|DEAD) << 16), &dma->control); - - /* verify good dma status. we don't check for ACTIVE beeing 0. We should... - * in theory, but with ATAPI decices doing buffer underruns, that would - * cause us to disable DMA, which isn't what we want - */ - return (dstat & (RUN|DEAD)) != RUN; -} - -/* - * Check out that the interrupt we got was for us. We can't always know this - * for sure with those Apple interfaces (well, we could on the recent ones but - * that's not implemented yet), on the other hand, we don't have shared interrupts - * so it's not really a problem - */ -static int -pmac_ide_dma_test_irq (ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); - volatile struct dbdma_regs __iomem *dma = pmif->dma_regs; - unsigned long status, timeout; - - /* We have to things to deal with here: - * - * - The dbdma won't stop if the command was started - * but completed with an error without transferring all - * datas. This happens when bad blocks are met during - * a multi-block transfer. - * - * - The dbdma fifo hasn't yet finished flushing to - * to system memory when the disk interrupt occurs. - * - */ - - /* If ACTIVE is cleared, the STOP command have passed and - * transfer is complete. - */ - status = readl(&dma->status); - if (!(status & ACTIVE)) - return 1; - - /* If dbdma didn't execute the STOP command yet, the - * active bit is still set. We consider that we aren't - * sharing interrupts (which is hopefully the case with - * those controllers) and so we just try to flush the - * channel for pending data in the fifo - */ - udelay(1); - writel((FLUSH << 16) | FLUSH, &dma->control); - timeout = 0; - for (;;) { - udelay(1); - status = readl(&dma->status); - if ((status & FLUSH) == 0) - break; - if (++timeout > 100) { - printk(KERN_WARNING "ide%d, ide_dma_test_irq timeout flushing channel\n", - hwif->index); - break; - } - } - return 1; -} - -static void pmac_ide_dma_host_set(ide_drive_t *drive, int on) -{ -} - -static void -pmac_ide_dma_lost_irq (ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); - volatile struct dbdma_regs __iomem *dma = pmif->dma_regs; - unsigned long status = readl(&dma->status); - - printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status); -} - -static const struct ide_dma_ops pmac_dma_ops = { - .dma_host_set = pmac_ide_dma_host_set, - .dma_setup = pmac_ide_dma_setup, - .dma_start = pmac_ide_dma_start, - .dma_end = pmac_ide_dma_end, - .dma_test_irq = pmac_ide_dma_test_irq, - .dma_lost_irq = pmac_ide_dma_lost_irq, -}; - -/* - * Allocate the data structures needed for using DMA with an interface - * and fill the proper list of functions pointers - */ -static int pmac_ide_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d) -{ - pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); - struct pci_dev *dev = to_pci_dev(hwif->dev); - - /* We won't need pci_dev if we switch to generic consistent - * DMA routines ... - */ - if (dev == NULL || pmif->dma_regs == 0) - return -ENODEV; - /* - * Allocate space for the DBDMA commands. - * The +2 is +1 for the stop command and +1 to allow for - * aligning the start address to a multiple of 16 bytes. - */ - pmif->dma_table_cpu = dma_alloc_coherent(&dev->dev, - (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), - &hwif->dmatable_dma, GFP_KERNEL); - if (pmif->dma_table_cpu == NULL) { - printk(KERN_ERR "%s: unable to allocate DMA command list\n", - hwif->name); - return -ENOMEM; - } - - hwif->sg_max_nents = MAX_DCMDS; - - return 0; -} - -module_init(pmac_ide_probe); - -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c deleted file mode 100644 index ab79b6289464..000000000000 --- a/drivers/ide/qd65xx.c +++ /dev/null @@ -1,446 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1996-2001 Linus Torvalds & author (see below) - */ - -/* - * Version 0.03 Cleaned auto-tune, added probe - * Version 0.04 Added second channel tuning - * Version 0.05 Enhanced tuning ; added qd6500 support - * Version 0.06 Added dos driver's list - * Version 0.07 Second channel bug fix - * - * QDI QD6500/QD6580 EIDE controller fast support - * - * To activate controller support, use "ide0=qd65xx" - */ - -/* - * Rewritten from the work of Colten Edwards by - * Samuel Thibault - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "qd65xx" - -#include "qd65xx.h" - -/* - * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580) - * or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580) - * -- qd6500 is a single IDE interface - * -- qd6580 is a dual IDE interface - * - * More research on qd6580 being done by willmore@cig.mot.com (David) - * More Information given by Petr Soucek (petr@ryston.cz) - * http://www.ryston.cz/petr/vlb - */ - -/* - * base: Timer1 - * - * - * base+0x01: Config (R/O) - * - * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500) - * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30 - * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz - * bit 3: qd6500: 1 = disabled, 0 = enabled - * qd6580: 1 - * upper nibble: - * qd6500: 1100 - * qd6580: either 1010 or 0101 - * - * - * base+0x02: Timer2 (qd6580 only) - * - * - * base+0x03: Control (qd6580 only) - * - * bits 0-3 must always be set 1 - * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock - * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb - * 0 = Primary and Secondary ports enabled : channel 0 for hda & hdb - * channel 1 for hdc & hdd - * bit 1 : 1 = only disks on primary port - * 0 = disks & ATAPI devices on primary port - * bit 2-4 : always 0 - * bit 5 : status, but of what ? - * bit 6 : always set 1 by dos driver - * bit 7 : set 1 for non-ATAPI devices on primary port - * (maybe read-ahead and post-write buffer ?) - */ - -static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */ - -/* - * qd65xx_select: - * - * This routine is invoked to prepare for access to a given drive. - */ - -static void qd65xx_dev_select(ide_drive_t *drive) -{ - u8 index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) | - (QD_TIMREG(drive) & 0x02); - - if (timings[index] != QD_TIMING(drive)) - outb(timings[index] = QD_TIMING(drive), QD_TIMREG(drive)); - - outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr); -} - -/* - * qd6500_compute_timing - * - * computes the timing value where - * lower nibble represents active time, in count of VLB clocks - * upper nibble represents recovery time, in count of VLB clocks - */ - -static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time) -{ - int clk = ide_vlb_clk ? ide_vlb_clk : 50; - u8 act_cyc, rec_cyc; - - if (clk <= 33) { - act_cyc = 9 - IDE_IN(active_time * clk / 1000 + 1, 2, 9); - rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 0, 15); - } else { - act_cyc = 8 - IDE_IN(active_time * clk / 1000 + 1, 1, 8); - rec_cyc = 18 - IDE_IN(recovery_time * clk / 1000 + 1, 3, 18); - } - - return (rec_cyc << 4) | 0x08 | act_cyc; -} - -/* - * qd6580_compute_timing - * - * idem for qd6580 - */ - -static u8 qd6580_compute_timing (int active_time, int recovery_time) -{ - int clk = ide_vlb_clk ? ide_vlb_clk : 50; - u8 act_cyc, rec_cyc; - - act_cyc = 17 - IDE_IN(active_time * clk / 1000 + 1, 2, 17); - rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 2, 15); - - return (rec_cyc << 4) | act_cyc; -} - -/* - * qd_find_disk_type - * - * tries to find timing from dos driver's table - */ - -static int qd_find_disk_type (ide_drive_t *drive, - int *active_time, int *recovery_time) -{ - struct qd65xx_timing_s *p; - char *m = (char *)&drive->id[ATA_ID_PROD]; - char model[ATA_ID_PROD_LEN]; - - if (*m == 0) - return 0; - - strncpy(model, m, ATA_ID_PROD_LEN); - ide_fixstring(model, ATA_ID_PROD_LEN, 1); /* byte-swap */ - - for (p = qd65xx_timing ; p->offset != -1 ; p++) { - if (!strncmp(p->model, model+p->offset, 4)) { - printk(KERN_DEBUG "%s: listed !\n", drive->name); - *active_time = p->active; - *recovery_time = p->recovery; - return 1; - } - } - return 0; -} - -/* - * qd_set_timing: - * - * records the timing - */ - -static void qd_set_timing (ide_drive_t *drive, u8 timing) -{ - unsigned long data = (unsigned long)ide_get_drivedata(drive); - - data &= 0xff00; - data |= timing; - ide_set_drivedata(drive, (void *)data); - - printk(KERN_DEBUG "%s: %#x\n", drive->name, timing); -} - -static void qd6500_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - u16 *id = drive->id; - int active_time = 175; - int recovery_time = 415; /* worst case values from the dos driver */ - - /* FIXME: use drive->pio_mode value */ - if (!qd_find_disk_type(drive, &active_time, &recovery_time) && - (id[ATA_ID_OLD_PIO_MODES] & 0xff) && (id[ATA_ID_FIELD_VALID] & 2) && - id[ATA_ID_EIDE_PIO] >= 240) { - printk(KERN_INFO "%s: PIO mode%d\n", drive->name, - id[ATA_ID_OLD_PIO_MODES] & 0xff); - active_time = 110; - recovery_time = drive->id[ATA_ID_EIDE_PIO] - 120; - } - - qd_set_timing(drive, qd6500_compute_timing(drive->hwif, - active_time, recovery_time)); -} - -static void qd6580_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - const u8 pio = drive->pio_mode - XFER_PIO_0; - struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); - unsigned int cycle_time; - int active_time = 175; - int recovery_time = 415; /* worst case values from the dos driver */ - u8 base = (hwif->config_data & 0xff00) >> 8; - - if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) { - cycle_time = ide_pio_cycle_time(drive, pio); - - switch (pio) { - case 0: break; - case 3: - if (cycle_time >= 110) { - active_time = 86; - recovery_time = cycle_time - 102; - } else - printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name); - break; - case 4: - if (cycle_time >= 69) { - active_time = 70; - recovery_time = cycle_time - 61; - } else - printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name); - break; - default: - if (cycle_time >= 180) { - active_time = 110; - recovery_time = cycle_time - 120; - } else { - active_time = t->active; - recovery_time = cycle_time - active_time; - } - } - printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio); - } - - if (!hwif->channel && drive->media != ide_disk) { - outb(0x5f, QD_CONTROL_PORT); - printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO " - "and post-write buffer on %s.\n", - drive->name, hwif->name); - } - - qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time)); -} - -/* - * qd_testreg - * - * tests if the given port is a register - */ - -static int __init qd_testreg(int port) -{ - unsigned long flags; - u8 savereg, readreg; - - local_irq_save(flags); - savereg = inb_p(port); - outb_p(QD_TESTVAL, port); /* safe value */ - readreg = inb_p(port); - outb(savereg, port); - local_irq_restore(flags); - - if (savereg == QD_TESTVAL) { - printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n"); - printk(KERN_ERR "Please contact maintainers to tell about your hardware\n"); - printk(KERN_ERR "Assuming qd65xx is not present.\n"); - return 1; - } - - return (readreg != QD_TESTVAL); -} - -static void __init qd6500_init_dev(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u8 base = (hwif->config_data & 0xff00) >> 8; - u8 config = QD_CONFIG(hwif); - - ide_set_drivedata(drive, (void *)QD6500_DEF_DATA); -} - -static void __init qd6580_init_dev(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - unsigned long t1, t2; - u8 base = (hwif->config_data & 0xff00) >> 8; - u8 config = QD_CONFIG(hwif); - - if (hwif->host_flags & IDE_HFLAG_SINGLE) { - t1 = QD6580_DEF_DATA; - t2 = QD6580_DEF_DATA2; - } else - t2 = t1 = hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA; - - ide_set_drivedata(drive, (void *)((drive->dn & 1) ? t2 : t1)); -} - -static const struct ide_tp_ops qd65xx_tp_ops = { - .exec_command = ide_exec_command, - .read_status = ide_read_status, - .read_altstatus = ide_read_altstatus, - .write_devctl = ide_write_devctl, - - .dev_select = qd65xx_dev_select, - .tf_load = ide_tf_load, - .tf_read = ide_tf_read, - - .input_data = ide_input_data, - .output_data = ide_output_data, -}; - -static const struct ide_port_ops qd6500_port_ops = { - .init_dev = qd6500_init_dev, - .set_pio_mode = qd6500_set_pio_mode, -}; - -static const struct ide_port_ops qd6580_port_ops = { - .init_dev = qd6580_init_dev, - .set_pio_mode = qd6580_set_pio_mode, -}; - -static const struct ide_port_info qd65xx_port_info __initconst = { - .name = DRV_NAME, - .tp_ops = &qd65xx_tp_ops, - .chipset = ide_qd65xx, - .host_flags = IDE_HFLAG_IO_32BIT | - IDE_HFLAG_NO_DMA, - .pio_mask = ATA_PIO4, -}; - -/* - * qd_probe: - * - * looks at the specified baseport, and if qd found, registers & initialises it - * return 1 if another qd may be probed - */ - -static int __init qd_probe(int base) -{ - int rc; - u8 config, unit, control; - struct ide_port_info d = qd65xx_port_info; - - config = inb(QD_CONFIG_PORT); - - if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) ) - return -ENODEV; - - unit = ! (config & QD_CONFIG_IDE_BASEPORT); - - if (unit) - d.host_flags |= IDE_HFLAG_QD_2ND_PORT; - - switch (config & 0xf0) { - case QD_CONFIG_QD6500: - if (qd_testreg(base)) - return -ENODEV; /* bad register */ - - if (config & QD_CONFIG_DISABLED) { - printk(KERN_WARNING "qd6500 is disabled !\n"); - return -ENODEV; - } - - printk(KERN_NOTICE "qd6500 at %#x\n", base); - printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n", - config, QD_ID3); - - d.port_ops = &qd6500_port_ops; - d.host_flags |= IDE_HFLAG_SINGLE; - break; - case QD_CONFIG_QD6580_A: - case QD_CONFIG_QD6580_B: - if (qd_testreg(base) || qd_testreg(base + 0x02)) - return -ENODEV; /* bad registers */ - - control = inb(QD_CONTROL_PORT); - - printk(KERN_NOTICE "qd6580 at %#x\n", base); - printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n", - config, control, QD_ID3); - - outb(QD_DEF_CONTR, QD_CONTROL_PORT); - - d.port_ops = &qd6580_port_ops; - if (control & QD_CONTR_SEC_DISABLED) - d.host_flags |= IDE_HFLAG_SINGLE; - - printk(KERN_INFO "qd6580: %s IDE board\n", - (control & QD_CONTR_SEC_DISABLED) ? "single" : "dual"); - break; - default: - return -ENODEV; - } - - rc = ide_legacy_device_add(&d, (base << 8) | config); - - if (d.host_flags & IDE_HFLAG_SINGLE) - return (rc == 0) ? 1 : rc; - - return rc; -} - -static bool probe_qd65xx; - -module_param_named(probe, probe_qd65xx, bool, 0); -MODULE_PARM_DESC(probe, "probe for QD65xx chipsets"); - -static int __init qd65xx_init(void) -{ - int rc1, rc2 = -ENODEV; - - if (probe_qd65xx == 0) - return -ENODEV; - - rc1 = qd_probe(0x30); - if (rc1) - rc2 = qd_probe(0xb0); - - if (rc1 < 0 && rc2 < 0) - return -ENODEV; - - return 0; -} - -module_init(qd65xx_init); - -MODULE_AUTHOR("Samuel Thibault"); -MODULE_DESCRIPTION("support of qd65xx vlb ide chipset"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/qd65xx.h b/drivers/ide/qd65xx.h deleted file mode 100644 index 01a43ab45e0e..000000000000 --- a/drivers/ide/qd65xx.h +++ /dev/null @@ -1,145 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2000 Linus Torvalds & authors - */ - -/* - * Authors: Petr Soucek - * Samuel Thibault - */ - -/* truncates a in [b,c] */ -#define IDE_IN(a,b,c) ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) ) - -#define IDE_IMPLY(a,b) ((!(a)) || (b)) - -#define QD_TIM1_PORT (base) -#define QD_CONFIG_PORT (base+0x01) -#define QD_TIM2_PORT (base+0x02) -#define QD_CONTROL_PORT (base+0x03) - -#define QD_CONFIG_IDE_BASEPORT 0x01 -#define QD_CONFIG_BASEPORT 0x02 -#define QD_CONFIG_ID3 0x04 -#define QD_CONFIG_DISABLED 0x08 -#define QD_CONFIG_QD6500 0xc0 -#define QD_CONFIG_QD6580_A 0xa0 -#define QD_CONFIG_QD6580_B 0x50 - -#define QD_CONTR_SEC_DISABLED 0x01 - -#define QD_ID3 ((config & QD_CONFIG_ID3)!=0) - -#define QD_CONFIG(hwif) ((hwif)->config_data & 0x00ff) - -static inline u8 QD_TIMING(ide_drive_t *drive) -{ - return (unsigned long)ide_get_drivedata(drive) & 0x00ff; -} - -static inline u8 QD_TIMREG(ide_drive_t *drive) -{ - return ((unsigned long)ide_get_drivedata(drive) & 0xff00) >> 8; -} - -#define QD6500_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08)) -#define QD6580_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00)) -#define QD6580_DEF_DATA2 ((QD_TIM2_PORT<<8) | (QD_ID3 ? 0x0a : 0x00)) -#define QD_DEF_CONTR (0x40 | ((control & 0x02) ? 0x9f : 0x1f)) - -#define QD_TESTVAL 0x19 /* safe value */ - -/* Drive specific timing taken from DOS driver v3.7 */ - -static struct qd65xx_timing_s { - s8 offset; /* ofset from the beginning of Model Number" */ - char model[4]; /* 4 chars from Model number, no conversion */ - s16 active; /* active time */ - s16 recovery; /* recovery time */ -} qd65xx_timing [] = { - { 30, "2040", 110, 225 }, /* Conner CP30204 */ - { 30, "2045", 135, 225 }, /* Conner CP30254 */ - { 30, "1040", 155, 325 }, /* Conner CP30104 */ - { 30, "1047", 135, 265 }, /* Conner CP30174 */ - { 30, "5344", 135, 225 }, /* Conner CP3544 */ - { 30, "01 4", 175, 405 }, /* Conner CP-3104 */ - { 27, "C030", 175, 375 }, /* Conner CP3000 */ - { 8, "PL42", 110, 295 }, /* Quantum LP240 */ - { 8, "PL21", 110, 315 }, /* Quantum LP120 */ - { 8, "PL25", 175, 385 }, /* Quantum LP52 */ - { 4, "PA24", 110, 285 }, /* WD Piranha SP4200 */ - { 6, "2200", 110, 260 }, /* WD Caviar AC2200 */ - { 6, "3204", 110, 235 }, /* WD Caviar AC2340 */ - { 6, "1202", 110, 265 }, /* WD Caviar AC2120 */ - { 0, "DS3-", 135, 315 }, /* Teac SD340 */ - { 8, "KM32", 175, 355 }, /* Toshiba MK234 */ - { 2, "53A1", 175, 355 }, /* Seagate ST351A */ - { 2, "4108", 175, 295 }, /* Seagate ST1480A */ - { 2, "1344", 175, 335 }, /* Seagate ST3144A */ - { 6, "7 12", 110, 225 }, /* Maxtor 7213A */ - { 30, "02F4", 145, 295 }, /* Conner 3204F */ - { 2, "1302", 175, 335 }, /* Seagate ST3120A */ - { 2, "2334", 145, 265 }, /* Seagate ST3243A */ - { 2, "2338", 145, 275 }, /* Seagate ST3283A */ - { 2, "3309", 145, 275 }, /* Seagate ST3390A */ - { 2, "5305", 145, 275 }, /* Seagate ST3550A */ - { 2, "4100", 175, 295 }, /* Seagate ST1400A */ - { 2, "4110", 175, 295 }, /* Seagate ST1401A */ - { 2, "6300", 135, 265 }, /* Seagate ST3600A */ - { 2, "5300", 135, 265 }, /* Seagate ST3500A */ - { 6, "7 31", 135, 225 }, /* Maxtor 7131 AT */ - { 6, "7 43", 115, 265 }, /* Maxtor 7345 AT */ - { 6, "7 42", 110, 255 }, /* Maxtor 7245 AT */ - { 6, "3 04", 135, 265 }, /* Maxtor 340 AT */ - { 6, "61 0", 135, 285 }, /* WD AC160 */ - { 6, "1107", 135, 235 }, /* WD AC1170 */ - { 6, "2101", 110, 220 }, /* WD AC1210 */ - { 6, "4202", 135, 245 }, /* WD AC2420 */ - { 6, "41 0", 175, 355 }, /* WD Caviar 140 */ - { 6, "82 0", 175, 355 }, /* WD Caviar 280 */ - { 8, "PL01", 175, 375 }, /* Quantum LP105 */ - { 8, "PL25", 110, 295 }, /* Quantum LP525 */ - { 10, "4S 2", 175, 385 }, /* Quantum ELS42 */ - { 10, "8S 5", 175, 385 }, /* Quantum ELS85 */ - { 10, "1S72", 175, 385 }, /* Quantum ELS127 */ - { 10, "1S07", 175, 385 }, /* Quantum ELS170 */ - { 8, "ZE42", 135, 295 }, /* Quantum EZ240 */ - { 8, "ZE21", 175, 385 }, /* Quantum EZ127 */ - { 8, "ZE58", 175, 385 }, /* Quantum EZ85 */ - { 8, "ZE24", 175, 385 }, /* Quantum EZ42 */ - { 27, "C036", 155, 325 }, /* Conner CP30064 */ - { 27, "C038", 155, 325 }, /* Conner CP30084 */ - { 6, "2205", 110, 255 }, /* WDC AC2250 */ - { 2, " CHA", 140, 415 }, /* WDC AH series; WDC AH260, WDC */ - { 2, " CLA", 140, 415 }, /* WDC AL series: WDC AL2120, 2170, */ - { 4, "UC41", 140, 415 }, /* WDC CU140 */ - { 6, "1207", 130, 275 }, /* WDC AC2170 */ - { 6, "2107", 130, 275 }, /* WDC AC1270 */ - { 6, "5204", 130, 275 }, /* WDC AC2540 */ - { 30, "3004", 110, 235 }, /* Conner CP30340 */ - { 30, "0345", 135, 255 }, /* Conner CP30544 */ - { 12, "12A3", 175, 320 }, /* MAXTOR LXT-213A */ - { 12, "43A0", 145, 240 }, /* MAXTOR LXT-340A */ - { 6, "7 21", 180, 290 }, /* Maxtor 7120 AT */ - { 6, "7 71", 135, 240 }, /* Maxtor 7170 AT */ - { 12, "45\0000", 110, 205 }, /* MAXTOR MXT-540 */ - { 8, "PL11", 180, 290 }, /* QUANTUM LP110A */ - { 8, "OG21", 150, 275 }, /* QUANTUM GO120 */ - { 12, "42A5", 175, 320 }, /* MAXTOR LXT-245A */ - { 2, "2309", 175, 295 }, /* ST3290A */ - { 2, "3358", 180, 310 }, /* ST3385A */ - { 2, "6355", 180, 310 }, /* ST3655A */ - { 2, "1900", 175, 270 }, /* ST9100A */ - { 2, "1954", 175, 270 }, /* ST9145A */ - { 2, "1909", 175, 270 }, /* ST9190AG */ - { 2, "2953", 175, 270 }, /* ST9235A */ - { 2, "1359", 175, 270 }, /* ST3195A */ - { 24, "3R11", 175, 290 }, /* ALPS ELECTRIC Co.,LTD, DR311C */ - { 0, "2M26", 175, 215 }, /* M262XT-0Ah */ - { 4, "2253", 175, 300 }, /* HP C2235A */ - { 4, "-32A", 145, 245 }, /* H3133-A2 */ - { 30, "0326", 150, 270 }, /* Samsung Electronics 120MB */ - { 30, "3044", 110, 195 }, /* Conner CFA340A */ - { 30, "43A0", 110, 195 }, /* Conner CFA340A */ - { -1, " ", 175, 415 } /* unknown disk name */ -}; diff --git a/drivers/ide/rapide.c b/drivers/ide/rapide.c deleted file mode 100644 index 0ab8b86b7ed7..000000000000 --- a/drivers/ide/rapide.c +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 1996-2002 Russell King. - */ - -#include -#include -#include -#include -#include - -#include - -static const struct ide_port_info rapide_port_info = { - .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, - .chipset = ide_generic, -}; - -static void rapide_setup_ports(struct ide_hw *hw, void __iomem *base, - void __iomem *ctrl, unsigned int sz, int irq) -{ - unsigned long port = (unsigned long)base; - int i; - - for (i = 0; i <= 7; i++) { - hw->io_ports_array[i] = port; - port += sz; - } - hw->io_ports.ctl_addr = (unsigned long)ctrl; - hw->irq = irq; -} - -static int rapide_probe(struct expansion_card *ec, const struct ecard_id *id) -{ - void __iomem *base; - struct ide_host *host; - int ret; - struct ide_hw hw, *hws[] = { &hw }; - - ret = ecard_request_resources(ec); - if (ret) - goto out; - - base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0); - if (!base) { - ret = -ENOMEM; - goto release; - } - - memset(&hw, 0, sizeof(hw)); - rapide_setup_ports(&hw, base, base + 0x818, 1 << 6, ec->irq); - hw.dev = &ec->dev; - - ret = ide_host_add(&rapide_port_info, hws, 1, &host); - if (ret) - goto release; - - ecard_set_drvdata(ec, host); - goto out; - - release: - ecard_release_resources(ec); - out: - return ret; -} - -static void rapide_remove(struct expansion_card *ec) -{ - struct ide_host *host = ecard_get_drvdata(ec); - - ecard_set_drvdata(ec, NULL); - - ide_host_remove(host); - - ecard_release_resources(ec); -} - -static struct ecard_id rapide_ids[] = { - { MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 }, - { 0xffff, 0xffff } -}; - -static struct ecard_driver rapide_driver = { - .probe = rapide_probe, - .remove = rapide_remove, - .id_table = rapide_ids, - .drv = { - .name = "rapide", - }, -}; - -static int __init rapide_init(void) -{ - return ecard_register_driver(&rapide_driver); -} - -static void __exit rapide_exit(void) -{ - ecard_remove_driver(&rapide_driver); -} - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Yellowstone RAPIDE driver"); - -module_init(rapide_init); -module_exit(rapide_exit); diff --git a/drivers/ide/rz1000.c b/drivers/ide/rz1000.c deleted file mode 100644 index fce2b7de5a19..000000000000 --- a/drivers/ide/rz1000.c +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1995-1998 Linus Torvalds & author (see below) - */ - -/* - * Principal Author: mlord@pobox.com (Mark Lord) - * - * See linux/MAINTAINERS for address of current maintainer. - * - * This file provides support for disabling the buggy read-ahead - * mode of the RZ1000 IDE chipset, commonly used on Intel motherboards. - * - * Dunno if this fixes both ports, or only the primary port (?). - */ - -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "rz1000" - -static int rz1000_disable_readahead(struct pci_dev *dev) -{ - u16 reg; - - if (!pci_read_config_word (dev, 0x40, ®) && - !pci_write_config_word(dev, 0x40, reg & 0xdfff)) { - printk(KERN_INFO "%s: disabled chipset read-ahead " - "(buggy RZ1000/RZ1001)\n", pci_name(dev)); - return 0; - } else { - printk(KERN_INFO "%s: serialized, disabled unmasking " - "(buggy RZ1000/RZ1001)\n", pci_name(dev)); - return 1; - } -} - -static const struct ide_port_info rz1000_chipset = { - .name = DRV_NAME, - .host_flags = IDE_HFLAG_NO_DMA, -}; - -static int rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct ide_port_info d = rz1000_chipset; - int rc; - - rc = pci_enable_device(dev); - if (rc) - return rc; - - if (rz1000_disable_readahead(dev)) { - d.host_flags |= IDE_HFLAG_SERIALIZE; - d.host_flags |= IDE_HFLAG_NO_UNMASK_IRQS; - } - - return ide_pci_init_one(dev, &d, NULL); -} - -static void rz1000_remove(struct pci_dev *dev) -{ - ide_pci_remove(dev); - pci_disable_device(dev); -} - -static const struct pci_device_id rz1000_pci_tbl[] = { - { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), 0 }, - { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, rz1000_pci_tbl); - -static struct pci_driver rz1000_pci_driver = { - .name = "RZ1000_IDE", - .id_table = rz1000_pci_tbl, - .probe = rz1000_init_one, - .remove = rz1000_remove, -}; - -static int __init rz1000_ide_init(void) -{ - return ide_pci_register_driver(&rz1000_pci_driver); -} - -static void __exit rz1000_ide_exit(void) -{ - pci_unregister_driver(&rz1000_pci_driver); -} - -module_init(rz1000_ide_init); -module_exit(rz1000_ide_exit); - -MODULE_AUTHOR("Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for RZ1000 IDE"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/ide/sc1200.c b/drivers/ide/sc1200.c deleted file mode 100644 index a5b701818405..000000000000 --- a/drivers/ide/sc1200.c +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright (C) 2000-2002 Mark Lord - * Copyright (C) 2007 Bartlomiej Zolnierkiewicz - * - * May be copied or modified under the terms of the GNU General Public License - * - * Development of this chipset driver was funded - * by the nice folks at National Semiconductor. - * - * Documentation: - * Available from National Semiconductor - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "sc1200" - -#define SC1200_REV_A 0x00 -#define SC1200_REV_B1 0x01 -#define SC1200_REV_B3 0x02 -#define SC1200_REV_C1 0x03 -#define SC1200_REV_D1 0x04 - -#define PCI_CLK_33 0x00 -#define PCI_CLK_48 0x01 -#define PCI_CLK_66 0x02 -#define PCI_CLK_33A 0x03 - -static unsigned short sc1200_get_pci_clock (void) -{ - unsigned char chip_id, silicon_revision; - unsigned int pci_clock; - /* - * Check the silicon revision, as not all versions of the chip - * have the register with the fast PCI bus timings. - */ - chip_id = inb (0x903c); - silicon_revision = inb (0x903d); - - // Read the fast pci clock frequency - if (chip_id == 0x04 && silicon_revision < SC1200_REV_B1) { - pci_clock = PCI_CLK_33; - } else { - // check clock generator configuration (cfcc) - // the clock is in bits 8 and 9 of this word - - pci_clock = inw (0x901e); - pci_clock >>= 8; - pci_clock &= 0x03; - if (pci_clock == PCI_CLK_33A) - pci_clock = PCI_CLK_33; - } - return pci_clock; -} - -/* - * Here are the standard PIO mode 0-4 timings for each "format". - * Format-0 uses fast data reg timings, with slower command reg timings. - * Format-1 uses fast timings for all registers, but won't work with all drives. - */ -static const unsigned int sc1200_pio_timings[4][5] = - {{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, // format0 33Mhz - {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}, // format1, 33Mhz - {0xfaa3f4f3, 0xc23232b2, 0x513101c1, 0x31213121, 0x10211021}, // format1, 48Mhz - {0xfff4fff4, 0xf35353d3, 0x814102f1, 0x42314231, 0x11311131}}; // format1, 66Mhz - -/* - * After chip reset, the PIO timings are set to 0x00009172, which is not valid. - */ -//#define SC1200_BAD_PIO(timings) (((timings)&~0x80000000)==0x00009172) - -static void sc1200_tunepio(ide_drive_t *drive, u8 pio) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *pdev = to_pci_dev(hwif->dev); - unsigned int basereg = hwif->channel ? 0x50 : 0x40, format = 0; - - pci_read_config_dword(pdev, basereg + 4, &format); - format = (format >> 31) & 1; - if (format) - format += sc1200_get_pci_clock(); - pci_write_config_dword(pdev, basereg + ((drive->dn & 1) << 3), - sc1200_pio_timings[format][pio]); -} - -/* - * The SC1200 specifies that two drives sharing a cable cannot mix - * UDMA/MDMA. It has to be one or the other, for the pair, though - * different timings can still be chosen for each drive. We could - * set the appropriate timing bits on the fly, but that might be - * a bit confusing. So, for now we statically handle this requirement - * by looking at our mate drive to see what it is capable of, before - * choosing a mode for our own drive. - */ -static u8 sc1200_udma_filter(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - ide_drive_t *mate = ide_get_pair_dev(drive); - u16 *mateid; - u8 mask = hwif->ultra_mask; - - if (mate == NULL) - goto out; - mateid = mate->id; - - if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) { - if ((mateid[ATA_ID_FIELD_VALID] & 4) && - (mateid[ATA_ID_UDMA_MODES] & 7)) - goto out; - if (mateid[ATA_ID_MWDMA_MODES] & 7) - mask = 0; - } -out: - return mask; -} - -static void sc1200_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned int reg, timings; - unsigned short pci_clock; - unsigned int basereg = hwif->channel ? 0x50 : 0x40; - const u8 mode = drive->dma_mode; - - static const u32 udma_timing[3][3] = { - { 0x00921250, 0x00911140, 0x00911030 }, - { 0x00932470, 0x00922260, 0x00922140 }, - { 0x009436a1, 0x00933481, 0x00923261 }, - }; - - static const u32 mwdma_timing[3][3] = { - { 0x00077771, 0x00012121, 0x00002020 }, - { 0x000bbbb2, 0x00024241, 0x00013131 }, - { 0x000ffff3, 0x00035352, 0x00015151 }, - }; - - pci_clock = sc1200_get_pci_clock(); - - /* - * Note that each DMA mode has several timings associated with it. - * The correct timing depends on the fast PCI clock freq. - */ - - if (mode >= XFER_UDMA_0) - timings = udma_timing[pci_clock][mode - XFER_UDMA_0]; - else - timings = mwdma_timing[pci_clock][mode - XFER_MW_DMA_0]; - - if ((drive->dn & 1) == 0) { - pci_read_config_dword(dev, basereg + 4, ®); - timings |= reg & 0x80000000; /* preserve PIO format bit */ - pci_write_config_dword(dev, basereg + 4, timings); - } else - pci_write_config_dword(dev, basereg + 12, timings); -} - -/* Replacement for the standard ide_dma_end action in - * dma_proc. - * - * returns 1 on error, 0 otherwise - */ -static int sc1200_dma_end(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - unsigned long dma_base = hwif->dma_base; - u8 dma_stat; - - dma_stat = inb(dma_base+2); /* get DMA status */ - - if (!(dma_stat & 4)) - printk(" ide_dma_end dma_stat=%0x err=%x newerr=%x\n", - dma_stat, ((dma_stat&7)!=4), ((dma_stat&2)==2)); - - outb(dma_stat|0x1b, dma_base+2); /* clear the INTR & ERROR bits */ - outb(inb(dma_base)&~1, dma_base); /* !! DO THIS HERE !! stop DMA */ - - return (dma_stat & 7) != 4; /* verify good DMA status */ -} - -/* - * sc1200_set_pio_mode() handles setting of PIO modes - * for both the chipset and drive. - * - * All existing BIOSs for this chipset guarantee that all drives - * will have valid default PIO timings set up before we get here. - */ - -static void sc1200_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - int mode = -1; - const u8 pio = drive->pio_mode - XFER_PIO_0; - - /* - * bad abuse of ->set_pio_mode interface - */ - switch (pio) { - case 200: mode = XFER_UDMA_0; break; - case 201: mode = XFER_UDMA_1; break; - case 202: mode = XFER_UDMA_2; break; - case 100: mode = XFER_MW_DMA_0; break; - case 101: mode = XFER_MW_DMA_1; break; - case 102: mode = XFER_MW_DMA_2; break; - } - if (mode != -1) { - printk("SC1200: %s: changing (U)DMA mode\n", drive->name); - ide_dma_off_quietly(drive); - if (ide_set_dma_mode(drive, mode) == 0 && - (drive->dev_flags & IDE_DFLAG_USING_DMA)) - hwif->dma_ops->dma_host_set(drive, 1); - return; - } - - sc1200_tunepio(drive, pio); -} - -#ifdef CONFIG_PM -struct sc1200_saved_state { - u32 regs[8]; -}; - -static int sc1200_suspend (struct pci_dev *dev, pm_message_t state) -{ - printk("SC1200: suspend(%u)\n", state.event); - - /* - * we only save state when going from full power to less - */ - if (state.event == PM_EVENT_ON) { - struct ide_host *host = pci_get_drvdata(dev); - struct sc1200_saved_state *ss = host->host_priv; - unsigned int r; - - /* - * save timing registers - * (this may be unnecessary if BIOS also does it) - */ - for (r = 0; r < 8; r++) - pci_read_config_dword(dev, 0x40 + r * 4, &ss->regs[r]); - } - - pci_disable_device(dev); - pci_set_power_state(dev, pci_choose_state(dev, state)); - return 0; -} - -static int sc1200_resume (struct pci_dev *dev) -{ - struct ide_host *host = pci_get_drvdata(dev); - struct sc1200_saved_state *ss = host->host_priv; - unsigned int r; - int i; - - i = pci_enable_device(dev); - if (i) - return i; - - /* - * restore timing registers - * (this may be unnecessary if BIOS also does it) - */ - for (r = 0; r < 8; r++) - pci_write_config_dword(dev, 0x40 + r * 4, ss->regs[r]); - - return 0; -} -#endif - -static const struct ide_port_ops sc1200_port_ops = { - .set_pio_mode = sc1200_set_pio_mode, - .set_dma_mode = sc1200_set_dma_mode, - .udma_filter = sc1200_udma_filter, -}; - -static const struct ide_dma_ops sc1200_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = ide_dma_start, - .dma_end = sc1200_dma_end, - .dma_test_irq = ide_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = ide_dma_sff_read_status, -}; - -static const struct ide_port_info sc1200_chipset = { - .name = DRV_NAME, - .port_ops = &sc1200_port_ops, - .dma_ops = &sc1200_dma_ops, - .host_flags = IDE_HFLAG_SERIALIZE | - IDE_HFLAG_POST_SET_MODE | - IDE_HFLAG_ABUSE_DMA_MODES, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA2, -}; - -static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct sc1200_saved_state *ss = NULL; - int rc; - -#ifdef CONFIG_PM - ss = kmalloc(sizeof(*ss), GFP_KERNEL); - if (ss == NULL) - return -ENOMEM; -#endif - rc = ide_pci_init_one(dev, &sc1200_chipset, ss); - if (rc) - kfree(ss); - - return rc; -} - -static const struct pci_device_id sc1200_pci_tbl[] = { - { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_IDE), 0}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl); - -static struct pci_driver sc1200_pci_driver = { - .name = "SC1200_IDE", - .id_table = sc1200_pci_tbl, - .probe = sc1200_init_one, - .remove = ide_pci_remove, -#ifdef CONFIG_PM - .suspend = sc1200_suspend, - .resume = sc1200_resume, -#endif -}; - -static int __init sc1200_ide_init(void) -{ - return ide_pci_register_driver(&sc1200_pci_driver); -} - -static void __exit sc1200_ide_exit(void) -{ - pci_unregister_driver(&sc1200_pci_driver); -} - -module_init(sc1200_ide_init); -module_exit(sc1200_ide_exit); - -MODULE_AUTHOR("Mark Lord"); -MODULE_DESCRIPTION("PCI driver module for NS SC1200 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c deleted file mode 100644 index 458e72e034b0..000000000000 --- a/drivers/ide/serverworks.c +++ /dev/null @@ -1,456 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1998-2000 Michel Aubry - * Copyright (C) 1998-2000 Andrzej Krzysztofowicz - * Copyright (C) 1998-2000 Andre Hedrick - * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz - * Portions copyright (c) 2001 Sun Microsystems - * - * - * RCC/ServerWorks IDE driver for Linux - * - * OSB4: `Open South Bridge' IDE Interface (fn 1) - * supports UDMA mode 2 (33 MB/s) - * - * CSB5: `Champion South Bridge' IDE Interface (fn 1) - * all revisions support UDMA mode 4 (66 MB/s) - * revision A2.0 and up support UDMA mode 5 (100 MB/s) - * - * *** The CSB5 does not provide ANY register *** - * *** to detect 80-conductor cable presence. *** - * - * CSB6: `Champion South Bridge' IDE Interface (optional: third channel) - * - * HT1000: AKA BCM5785 - Hypertransport Southbridge for Opteron systems. IDE - * controller same as the CSB6. Single channel ATA100 only. - * - * Documentation: - * Available under NDA only. Errata info very hard to get. - * - */ - -#include -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "serverworks" - -#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ -#define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */ - -/* Seagate Barracuda ATA IV Family drives in UDMA mode 5 - * can overrun their FIFOs when used with the CSB5 */ -static const char *svwks_bad_ata100[] = { - "ST320011A", - "ST340016A", - "ST360021A", - "ST380021A", - NULL -}; - -static int check_in_drive_lists (ide_drive_t *drive, const char **list) -{ - char *m = (char *)&drive->id[ATA_ID_PROD]; - - while (*list) - if (!strcmp(*list++, m)) - return 1; - return 0; -} - -static u8 svwks_udma_filter(ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(drive->hwif->dev); - - if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) { - return 0x1f; - } else if (dev->revision < SVWKS_CSB5_REVISION_NEW) { - return 0x07; - } else { - u8 btr = 0, mode, mask; - - pci_read_config_byte(dev, 0x5A, &btr); - mode = btr & 0x3; - - /* If someone decides to do UDMA133 on CSB5 the same - issue will bite so be inclusive */ - if (mode > 2 && check_in_drive_lists(drive, svwks_bad_ata100)) - mode = 2; - - switch(mode) { - case 3: mask = 0x3f; break; - case 2: mask = 0x1f; break; - case 1: mask = 0x07; break; - default: mask = 0x00; break; - } - - return mask; - } -} - -static u8 svwks_csb_check (struct pci_dev *dev) -{ - switch (dev->device) { - case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: - case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: - case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2: - case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE: - return 1; - default: - break; - } - return 0; -} - -static void svwks_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 }; - static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 }; - - struct pci_dev *dev = to_pci_dev(hwif->dev); - const u8 pio = drive->pio_mode - XFER_PIO_0; - - if (drive->dn >= ARRAY_SIZE(drive_pci)) - return; - - pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]); - - if (svwks_csb_check(dev)) { - u16 csb_pio = 0; - - pci_read_config_word(dev, 0x4a, &csb_pio); - - csb_pio &= ~(0x0f << (4 * drive->dn)); - csb_pio |= (pio << (4 * drive->dn)); - - pci_write_config_word(dev, 0x4a, csb_pio); - } -} - -static void svwks_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - static const u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; - static const u8 dma_modes[] = { 0x77, 0x21, 0x20 }; - static const u8 drive_pci2[] = { 0x45, 0x44, 0x47, 0x46 }; - - struct pci_dev *dev = to_pci_dev(hwif->dev); - const u8 speed = drive->dma_mode; - u8 unit = drive->dn & 1; - - u8 ultra_enable = 0, ultra_timing = 0, dma_timing = 0; - - if (drive->dn >= ARRAY_SIZE(drive_pci2)) - return; - - pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing); - pci_read_config_byte(dev, 0x54, &ultra_enable); - - ultra_timing &= ~(0x0F << (4*unit)); - ultra_enable &= ~(0x01 << drive->dn); - - if (speed >= XFER_UDMA_0) { - dma_timing |= dma_modes[2]; - ultra_timing |= (udma_modes[speed - XFER_UDMA_0] << (4 * unit)); - ultra_enable |= (0x01 << drive->dn); - } else if (speed >= XFER_MW_DMA_0) - dma_timing |= dma_modes[speed - XFER_MW_DMA_0]; - - pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing); - pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing); - pci_write_config_byte(dev, 0x54, ultra_enable); -} - -static int init_chipset_svwks(struct pci_dev *dev) -{ - unsigned int reg; - u8 btr; - - /* force Master Latency Timer value to 64 PCICLKs */ - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); - - /* OSB4 : South Bridge and IDE */ - if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { - struct pci_dev *isa_dev = - pci_get_device(PCI_VENDOR_ID_SERVERWORKS, - PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL); - if (isa_dev) { - pci_read_config_dword(isa_dev, 0x64, ®); - reg &= ~0x00002000; /* disable 600ns interrupt mask */ - if(!(reg & 0x00004000)) - printk(KERN_DEBUG DRV_NAME " %s: UDMA not BIOS " - "enabled.\n", pci_name(dev)); - reg |= 0x00004000; /* enable UDMA/33 support */ - pci_write_config_dword(isa_dev, 0x64, reg); - pci_dev_put(isa_dev); - } - } - - /* setup CSB5/CSB6 : South Bridge and IDE option RAID */ - else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) || - (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || - (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) { - - /* Third Channel Test */ - if (!(PCI_FUNC(dev->devfn) & 1)) { - struct pci_dev * findev = NULL; - u32 reg4c = 0; - findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, - PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL); - if (findev) { - pci_read_config_dword(findev, 0x4C, ®4c); - reg4c &= ~0x000007FF; - reg4c |= 0x00000040; - reg4c |= 0x00000020; - pci_write_config_dword(findev, 0x4C, reg4c); - pci_dev_put(findev); - } - outb_p(0x06, 0x0c00); - dev->irq = inb_p(0x0c01); - } else { - struct pci_dev * findev = NULL; - u8 reg41 = 0; - - findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, - PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL); - if (findev) { - pci_read_config_byte(findev, 0x41, ®41); - reg41 &= ~0x40; - pci_write_config_byte(findev, 0x41, reg41); - pci_dev_put(findev); - } - /* - * This is a device pin issue on CSB6. - * Since there will be a future raid mode, - * early versions of the chipset require the - * interrupt pin to be set, and it is a compatibility - * mode issue. - */ - if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) - dev->irq = 0; - } -// pci_read_config_dword(dev, 0x40, &pioreg) -// pci_write_config_dword(dev, 0x40, 0x99999999); -// pci_read_config_dword(dev, 0x44, &dmareg); -// pci_write_config_dword(dev, 0x44, 0xFFFFFFFF); - /* setup the UDMA Control register - * - * 1. clear bit 6 to enable DMA - * 2. enable DMA modes with bits 0-1 - * 00 : legacy - * 01 : udma2 - * 10 : udma2/udma4 - * 11 : udma2/udma4/udma5 - */ - pci_read_config_byte(dev, 0x5A, &btr); - btr &= ~0x40; - if (!(PCI_FUNC(dev->devfn) & 1)) - btr |= 0x2; - else - btr |= (dev->revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2; - pci_write_config_byte(dev, 0x5A, btr); - } - /* Setup HT1000 SouthBridge Controller - Single Channel Only */ - else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) { - pci_read_config_byte(dev, 0x5A, &btr); - btr &= ~0x40; - btr |= 0x3; - pci_write_config_byte(dev, 0x5A, btr); - } - - return 0; -} - -static u8 ata66_svwks_svwks(ide_hwif_t *hwif) -{ - return ATA_CBL_PATA80; -} - -/* On Dell PowerEdge servers with a CSB5/CSB6, the top two bits - * of the subsystem device ID indicate presence of an 80-pin cable. - * Bit 15 clear = secondary IDE channel does not have 80-pin cable. - * Bit 15 set = secondary IDE channel has 80-pin cable. - * Bit 14 clear = primary IDE channel does not have 80-pin cable. - * Bit 14 set = primary IDE channel has 80-pin cable. - */ -static u8 ata66_svwks_dell(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - - if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL && - dev->vendor == PCI_VENDOR_ID_SERVERWORKS && - (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE || - dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE)) - return ((1 << (hwif->channel + 14)) & - dev->subsystem_device) ? ATA_CBL_PATA80 : ATA_CBL_PATA40; - return ATA_CBL_PATA40; -} - -/* Sun Cobalt Alpine hardware avoids the 80-pin cable - * detect issue by attaching the drives directly to the board. - * This check follows the Dell precedent (how scary is that?!) - * - * WARNING: this only works on Alpine hardware! - */ -static u8 ata66_svwks_cobalt(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - - if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN && - dev->vendor == PCI_VENDOR_ID_SERVERWORKS && - dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) - return ((1 << (hwif->channel + 14)) & - dev->subsystem_device) ? ATA_CBL_PATA80 : ATA_CBL_PATA40; - return ATA_CBL_PATA40; -} - -static u8 svwks_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - - /* Server Works */ - if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS) - return ata66_svwks_svwks (hwif); - - /* Dell PowerEdge */ - if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL) - return ata66_svwks_dell (hwif); - - /* Cobalt Alpine */ - if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN) - return ata66_svwks_cobalt (hwif); - - /* Per Specified Design by OEM, and ASIC Architect */ - if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || - (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) - return ATA_CBL_PATA80; - - return ATA_CBL_PATA40; -} - -static const struct ide_port_ops osb4_port_ops = { - .set_pio_mode = svwks_set_pio_mode, - .set_dma_mode = svwks_set_dma_mode, -}; - -static const struct ide_port_ops svwks_port_ops = { - .set_pio_mode = svwks_set_pio_mode, - .set_dma_mode = svwks_set_dma_mode, - .udma_filter = svwks_udma_filter, - .cable_detect = svwks_cable_detect, -}; - -static const struct ide_port_info serverworks_chipsets[] = { - { /* 0: OSB4 */ - .name = DRV_NAME, - .init_chipset = init_chipset_svwks, - .port_ops = &osb4_port_ops, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = 0x00, /* UDMA is problematic on OSB4 */ - }, - { /* 1: CSB5 */ - .name = DRV_NAME, - .init_chipset = init_chipset_svwks, - .port_ops = &svwks_port_ops, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA5, - }, - { /* 2: CSB6 */ - .name = DRV_NAME, - .init_chipset = init_chipset_svwks, - .port_ops = &svwks_port_ops, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA5, - }, - { /* 3: CSB6-2 */ - .name = DRV_NAME, - .init_chipset = init_chipset_svwks, - .port_ops = &svwks_port_ops, - .host_flags = IDE_HFLAG_SINGLE, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA5, - }, - { /* 4: HT1000 */ - .name = DRV_NAME, - .init_chipset = init_chipset_svwks, - .port_ops = &svwks_port_ops, - .host_flags = IDE_HFLAG_SINGLE, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA5, - } -}; - -/** - * svwks_init_one - called when a OSB/CSB is found - * @dev: the svwks device - * @id: the matching pci id - * - * Called when the PCI registration layer (or the IDE initialization) - * finds a device matching our IDE device tables. - */ - -static int svwks_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct ide_port_info d; - u8 idx = id->driver_data; - - d = serverworks_chipsets[idx]; - - if (idx == 1) - d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX; - else if (idx == 2 || idx == 3) { - if ((PCI_FUNC(dev->devfn) & 1) == 0) { - if (pci_resource_start(dev, 0) != 0x01f1) - d.host_flags |= IDE_HFLAG_NON_BOOTABLE; - d.host_flags |= IDE_HFLAG_SINGLE; - } else - d.host_flags &= ~IDE_HFLAG_SINGLE; - } - - return ide_pci_init_one(dev, &d, NULL); -} - -static const struct pci_device_id svwks_pci_tbl[] = { - { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0 }, - { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 1 }, - { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2 }, - { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 3 }, - { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 4 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, svwks_pci_tbl); - -static struct pci_driver svwks_pci_driver = { - .name = "Serverworks_IDE", - .id_table = svwks_pci_tbl, - .probe = svwks_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init svwks_ide_init(void) -{ - return ide_pci_register_driver(&svwks_pci_driver); -} - -static void __exit svwks_ide_exit(void) -{ - pci_unregister_driver(&svwks_pci_driver); -} - -module_init(svwks_ide_init); -module_exit(svwks_ide_exit); - -MODULE_AUTHOR("Michael Aubry. Andrzej Krzysztofowicz, Andre Hedrick, Bartlomiej Zolnierkiewicz"); -MODULE_DESCRIPTION("PCI driver module for Serverworks OSB4/CSB5/CSB6 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c deleted file mode 100644 index fdc8e813170c..000000000000 --- a/drivers/ide/setup-pci.c +++ /dev/null @@ -1,682 +0,0 @@ -/* - * Copyright (C) 1998-2000 Andre Hedrick - * Copyright (C) 1995-1998 Mark Lord - * Copyright (C) 2007-2009 Bartlomiej Zolnierkiewicz - * - * May be copied or modified under the terms of the GNU General Public License - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/** - * ide_setup_pci_baseregs - place a PCI IDE controller native - * @dev: PCI device of interface to switch native - * @name: Name of interface - * - * We attempt to place the PCI interface into PCI native mode. If - * we succeed the BARs are ok and the controller is in PCI mode. - * Returns 0 on success or an errno code. - * - * FIXME: if we program the interface and then fail to set the BARS - * we don't switch it back to legacy mode. Do we actually care ?? - */ - -static int ide_setup_pci_baseregs(struct pci_dev *dev, const char *name) -{ - u8 progif = 0; - - /* - * Place both IDE interfaces into PCI "native" mode: - */ - if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || - (progif & 5) != 5) { - if ((progif & 0xa) != 0xa) { - printk(KERN_INFO "%s %s: device not capable of full " - "native PCI mode\n", name, pci_name(dev)); - return -EOPNOTSUPP; - } - printk(KERN_INFO "%s %s: placing both ports into native PCI " - "mode\n", name, pci_name(dev)); - (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5); - if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || - (progif & 5) != 5) { - printk(KERN_ERR "%s %s: rewrite of PROGIF failed, " - "wanted 0x%04x, got 0x%04x\n", - name, pci_name(dev), progif | 5, progif); - return -EOPNOTSUPP; - } - } - return 0; -} - -#ifdef CONFIG_BLK_DEV_IDEDMA_PCI -static int ide_pci_clear_simplex(unsigned long dma_base, const char *name) -{ - u8 dma_stat = inb(dma_base + 2); - - outb(dma_stat & 0x60, dma_base + 2); - dma_stat = inb(dma_base + 2); - - return (dma_stat & 0x80) ? 1 : 0; -} - -/** - * ide_pci_dma_base - setup BMIBA - * @hwif: IDE interface - * @d: IDE port info - * - * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space. - */ - -unsigned long ide_pci_dma_base(ide_hwif_t *hwif, const struct ide_port_info *d) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long dma_base = 0; - - if (hwif->host_flags & IDE_HFLAG_MMIO) - return hwif->dma_base; - - if (hwif->mate && hwif->mate->dma_base) { - dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8); - } else { - u8 baridx = (d->host_flags & IDE_HFLAG_CS5520) ? 2 : 4; - - dma_base = pci_resource_start(dev, baridx); - - if (dma_base == 0) { - printk(KERN_ERR "%s %s: DMA base is invalid\n", - d->name, pci_name(dev)); - return 0; - } - } - - if (hwif->channel) - dma_base += 8; - - return dma_base; -} -EXPORT_SYMBOL_GPL(ide_pci_dma_base); - -int ide_pci_check_simplex(ide_hwif_t *hwif, const struct ide_port_info *d) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 dma_stat; - - if (d->host_flags & (IDE_HFLAG_MMIO | IDE_HFLAG_CS5520)) - goto out; - - if (d->host_flags & IDE_HFLAG_CLEAR_SIMPLEX) { - if (ide_pci_clear_simplex(hwif->dma_base, d->name)) - printk(KERN_INFO "%s %s: simplex device: DMA forced\n", - d->name, pci_name(dev)); - goto out; - } - - /* - * If the device claims "simplex" DMA, this means that only one of - * the two interfaces can be trusted with DMA at any point in time - * (so we should enable DMA only on one of the two interfaces). - * - * FIXME: At this point we haven't probed the drives so we can't make - * the appropriate decision. Really we should defer this problem until - * we tune the drive then try to grab DMA ownership if we want to be - * the DMA end. This has to be become dynamic to handle hot-plug. - */ - dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); - if ((dma_stat & 0x80) && hwif->mate && hwif->mate->dma_base) { - printk(KERN_INFO "%s %s: simplex device: DMA disabled\n", - d->name, pci_name(dev)); - return -1; - } -out: - return 0; -} -EXPORT_SYMBOL_GPL(ide_pci_check_simplex); - -/* - * Set up BM-DMA capability (PnP BIOS should have done this) - */ -int ide_pci_set_master(struct pci_dev *dev, const char *name) -{ - u16 pcicmd; - - pci_read_config_word(dev, PCI_COMMAND, &pcicmd); - - if ((pcicmd & PCI_COMMAND_MASTER) == 0) { - pci_set_master(dev); - - if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || - (pcicmd & PCI_COMMAND_MASTER) == 0) { - printk(KERN_ERR "%s %s: error updating PCICMD\n", - name, pci_name(dev)); - return -EIO; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(ide_pci_set_master); -#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ - -void ide_setup_pci_noise(struct pci_dev *dev, const struct ide_port_info *d) -{ - printk(KERN_INFO "%s %s: IDE controller (0x%04x:0x%04x rev 0x%02x)\n", - d->name, pci_name(dev), - dev->vendor, dev->device, dev->revision); -} -EXPORT_SYMBOL_GPL(ide_setup_pci_noise); - - -/** - * ide_pci_enable - do PCI enables - * @dev: PCI device - * @bars: PCI BARs mask - * @d: IDE port info - * - * Enable the IDE PCI device. We attempt to enable the device in full - * but if that fails then we only need IO space. The PCI code should - * have setup the proper resources for us already for controllers in - * legacy mode. - * - * Returns zero on success or an error code - */ - -static int ide_pci_enable(struct pci_dev *dev, int bars, - const struct ide_port_info *d) -{ - int ret; - - if (pci_enable_device(dev)) { - ret = pci_enable_device_io(dev); - if (ret < 0) { - printk(KERN_WARNING "%s %s: couldn't enable device\n", - d->name, pci_name(dev)); - goto out; - } - printk(KERN_WARNING "%s %s: BIOS configuration fixed\n", - d->name, pci_name(dev)); - } - - /* - * assume all devices can do 32-bit DMA for now, we can add - * a DMA mask field to the struct ide_port_info if we need it - * (or let lower level driver set the DMA mask) - */ - ret = dma_set_mask(&dev->dev, DMA_BIT_MASK(32)); - if (ret < 0) { - printk(KERN_ERR "%s %s: can't set DMA mask\n", - d->name, pci_name(dev)); - goto out; - } - - ret = pci_request_selected_regions(dev, bars, d->name); - if (ret < 0) - printk(KERN_ERR "%s %s: can't reserve resources\n", - d->name, pci_name(dev)); -out: - return ret; -} - -/** - * ide_pci_configure - configure an unconfigured device - * @dev: PCI device - * @d: IDE port info - * - * Enable and configure the PCI device we have been passed. - * Returns zero on success or an error code. - */ - -static int ide_pci_configure(struct pci_dev *dev, const struct ide_port_info *d) -{ - u16 pcicmd = 0; - /* - * PnP BIOS was *supposed* to have setup this device, but we - * can do it ourselves, so long as the BIOS has assigned an IRQ - * (or possibly the device is using a "legacy header" for IRQs). - * Maybe the user deliberately *disabled* the device, - * but we'll eventually ignore it again if no drives respond. - */ - if (ide_setup_pci_baseregs(dev, d->name) || - pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_IO)) { - printk(KERN_INFO "%s %s: device disabled (BIOS)\n", - d->name, pci_name(dev)); - return -ENODEV; - } - if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) { - printk(KERN_ERR "%s %s: error accessing PCI regs\n", - d->name, pci_name(dev)); - return -EIO; - } - if (!(pcicmd & PCI_COMMAND_IO)) { - printk(KERN_ERR "%s %s: unable to enable IDE controller\n", - d->name, pci_name(dev)); - return -ENXIO; - } - return 0; -} - -/** - * ide_pci_check_iomem - check a register is I/O - * @dev: PCI device - * @d: IDE port info - * @bar: BAR number - * - * Checks if a BAR is configured and points to MMIO space. If so, - * return an error code. Otherwise return 0 - */ - -static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info *d, - int bar) -{ - ulong flags = pci_resource_flags(dev, bar); - - /* Unconfigured ? */ - if (!flags || pci_resource_len(dev, bar) == 0) - return 0; - - /* I/O space */ - if (flags & IORESOURCE_IO) - return 0; - - /* Bad */ - return -EINVAL; -} - -/** - * ide_hw_configure - configure a struct ide_hw instance - * @dev: PCI device holding interface - * @d: IDE port info - * @port: port number - * @hw: struct ide_hw instance corresponding to this port - * - * Perform the initial set up for the hardware interface structure. This - * is done per interface port rather than per PCI device. There may be - * more than one port per device. - * - * Returns zero on success or an error code. - */ - -static int ide_hw_configure(struct pci_dev *dev, const struct ide_port_info *d, - unsigned int port, struct ide_hw *hw) -{ - unsigned long ctl = 0, base = 0; - - if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) { - if (ide_pci_check_iomem(dev, d, 2 * port) || - ide_pci_check_iomem(dev, d, 2 * port + 1)) { - printk(KERN_ERR "%s %s: I/O baseregs (BIOS) are " - "reported as MEM for port %d!\n", - d->name, pci_name(dev), port); - return -EINVAL; - } - - ctl = pci_resource_start(dev, 2*port+1); - base = pci_resource_start(dev, 2*port); - } else { - /* Use default values */ - ctl = port ? 0x374 : 0x3f4; - base = port ? 0x170 : 0x1f0; - } - - if (!base || !ctl) { - printk(KERN_ERR "%s %s: bad PCI BARs for port %d, skipping\n", - d->name, pci_name(dev), port); - return -EINVAL; - } - - memset(hw, 0, sizeof(*hw)); - hw->dev = &dev->dev; - ide_std_init_ports(hw, base, ctl | 2); - - return 0; -} - -#ifdef CONFIG_BLK_DEV_IDEDMA_PCI -/** - * ide_hwif_setup_dma - configure DMA interface - * @hwif: IDE interface - * @d: IDE port info - * - * Set up the DMA base for the interface. Enable the master bits as - * necessary and attempt to bring the device DMA into a ready to use - * state - */ - -int ide_hwif_setup_dma(ide_hwif_t *hwif, const struct ide_port_info *d) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - - if ((d->host_flags & IDE_HFLAG_NO_AUTODMA) == 0 || - ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && - (dev->class & 0x80))) { - unsigned long base = ide_pci_dma_base(hwif, d); - - if (base == 0) - return -1; - - hwif->dma_base = base; - - if (hwif->dma_ops == NULL) - hwif->dma_ops = &sff_dma_ops; - - if (ide_pci_check_simplex(hwif, d) < 0) - return -1; - - if (ide_pci_set_master(dev, d->name) < 0) - return -1; - - if (hwif->host_flags & IDE_HFLAG_MMIO) - printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name); - else - printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n", - hwif->name, base, base + 7); - - hwif->extra_base = base + (hwif->channel ? 8 : 16); - - if (ide_allocate_dma_engine(hwif)) - return -1; - } - - return 0; -} -#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ - -/** - * ide_setup_pci_controller - set up IDE PCI - * @dev: PCI device - * @bars: PCI BARs mask - * @d: IDE port info - * @noisy: verbose flag - * - * Set up the PCI and controller side of the IDE interface. This brings - * up the PCI side of the device, checks that the device is enabled - * and enables it if need be - */ - -static int ide_setup_pci_controller(struct pci_dev *dev, int bars, - const struct ide_port_info *d, int noisy) -{ - int ret; - u16 pcicmd; - - if (noisy) - ide_setup_pci_noise(dev, d); - - ret = ide_pci_enable(dev, bars, d); - if (ret < 0) - goto out; - - ret = pci_read_config_word(dev, PCI_COMMAND, &pcicmd); - if (ret < 0) { - printk(KERN_ERR "%s %s: error accessing PCI regs\n", - d->name, pci_name(dev)); - goto out_free_bars; - } - if (!(pcicmd & PCI_COMMAND_IO)) { /* is device disabled? */ - ret = ide_pci_configure(dev, d); - if (ret < 0) - goto out_free_bars; - printk(KERN_INFO "%s %s: device enabled (Linux)\n", - d->name, pci_name(dev)); - } - - goto out; - -out_free_bars: - pci_release_selected_regions(dev, bars); -out: - return ret; -} - -/** - * ide_pci_setup_ports - configure ports/devices on PCI IDE - * @dev: PCI device - * @d: IDE port info - * @hw: struct ide_hw instances corresponding to this PCI IDE device - * @hws: struct ide_hw pointers table to update - * - * Scan the interfaces attached to this device and do any - * necessary per port setup. Attach the devices and ask the - * generic DMA layer to do its work for us. - * - * Normally called automaticall from do_ide_pci_setup_device, - * but is also used directly as a helper function by some controllers - * where the chipset setup is not the default PCI IDE one. - */ - -void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, - struct ide_hw *hw, struct ide_hw **hws) -{ - int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port; - u8 tmp; - - /* - * Set up the IDE ports - */ - - for (port = 0; port < channels; ++port) { - const struct ide_pci_enablebit *e = &d->enablebits[port]; - - if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || - (tmp & e->mask) != e->val)) { - printk(KERN_INFO "%s %s: IDE port disabled\n", - d->name, pci_name(dev)); - continue; /* port not enabled */ - } - - if (ide_hw_configure(dev, d, port, hw + port)) - continue; - - *(hws + port) = hw + port; - } -} -EXPORT_SYMBOL_GPL(ide_pci_setup_ports); - -/* - * ide_setup_pci_device() looks at the primary/secondary interfaces - * on a PCI IDE device and, if they are enabled, prepares the IDE driver - * for use with them. This generic code works for most PCI chipsets. - * - * One thing that is not standardized is the location of the - * primary/secondary interface "enable/disable" bits. For chipsets that - * we "know" about, this information is in the struct ide_port_info; - * for all other chipsets, we just assume both interfaces are enabled. - */ -static int do_ide_setup_pci_device(struct pci_dev *dev, - const struct ide_port_info *d, - u8 noisy) -{ - int pciirq, ret; - - /* - * Can we trust the reported IRQ? - */ - pciirq = dev->irq; - - /* - * This allows offboard ide-pci cards the enable a BIOS, - * verify interrupt settings of split-mirror pci-config - * space, place chipset into init-mode, and/or preserve - * an interrupt if the card is not native ide support. - */ - ret = d->init_chipset ? d->init_chipset(dev) : 0; - if (ret < 0) - goto out; - - if (ide_pci_is_in_compatibility_mode(dev)) { - if (noisy) - printk(KERN_INFO "%s %s: not 100%% native mode: will " - "probe irqs later\n", d->name, pci_name(dev)); - pciirq = 0; - } else if (!pciirq && noisy) { - printk(KERN_WARNING "%s %s: bad irq (%d): will probe later\n", - d->name, pci_name(dev), pciirq); - } else if (noisy) { - printk(KERN_INFO "%s %s: 100%% native mode on irq %d\n", - d->name, pci_name(dev), pciirq); - } - - ret = pciirq; -out: - return ret; -} - -int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2, - const struct ide_port_info *d, void *priv) -{ - struct pci_dev *pdev[] = { dev1, dev2 }; - struct ide_host *host; - int ret, i, n_ports = dev2 ? 4 : 2, bars; - struct ide_hw hw[4], *hws[] = { NULL, NULL, NULL, NULL }; - - if (d->host_flags & IDE_HFLAG_SINGLE) - bars = (1 << 2) - 1; - else - bars = (1 << 4) - 1; - - if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) { - if (d->host_flags & IDE_HFLAG_CS5520) - bars |= (1 << 2); - else - bars |= (1 << 4); - } - - for (i = 0; i < n_ports / 2; i++) { - ret = ide_setup_pci_controller(pdev[i], bars, d, !i); - if (ret < 0) { - if (i == 1) - pci_release_selected_regions(pdev[0], bars); - goto out; - } - - ide_pci_setup_ports(pdev[i], d, &hw[i*2], &hws[i*2]); - } - - host = ide_host_alloc(d, hws, n_ports); - if (host == NULL) { - ret = -ENOMEM; - goto out_free_bars; - } - - host->dev[0] = &dev1->dev; - if (dev2) - host->dev[1] = &dev2->dev; - - host->host_priv = priv; - host->irq_flags = IRQF_SHARED; - - pci_set_drvdata(pdev[0], host); - if (dev2) - pci_set_drvdata(pdev[1], host); - - for (i = 0; i < n_ports / 2; i++) { - ret = do_ide_setup_pci_device(pdev[i], d, !i); - - /* - * FIXME: Mom, mom, they stole me the helper function to undo - * do_ide_setup_pci_device() on the first device! - */ - if (ret < 0) - goto out_free_bars; - - /* fixup IRQ */ - if (ide_pci_is_in_compatibility_mode(pdev[i])) { - hw[i*2].irq = pci_get_legacy_ide_irq(pdev[i], 0); - hw[i*2 + 1].irq = pci_get_legacy_ide_irq(pdev[i], 1); - } else - hw[i*2 + 1].irq = hw[i*2].irq = ret; - } - - ret = ide_host_register(host, d, hws); - if (ret) - ide_host_free(host); - else - goto out; - -out_free_bars: - i = n_ports / 2; - while (i--) - pci_release_selected_regions(pdev[i], bars); -out: - return ret; -} -EXPORT_SYMBOL_GPL(ide_pci_init_two); - -int ide_pci_init_one(struct pci_dev *dev, const struct ide_port_info *d, - void *priv) -{ - return ide_pci_init_two(dev, NULL, d, priv); -} -EXPORT_SYMBOL_GPL(ide_pci_init_one); - -void ide_pci_remove(struct pci_dev *dev) -{ - struct ide_host *host = pci_get_drvdata(dev); - struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL; - int bars; - - if (host->host_flags & IDE_HFLAG_SINGLE) - bars = (1 << 2) - 1; - else - bars = (1 << 4) - 1; - - if ((host->host_flags & IDE_HFLAG_NO_DMA) == 0) { - if (host->host_flags & IDE_HFLAG_CS5520) - bars |= (1 << 2); - else - bars |= (1 << 4); - } - - ide_host_remove(host); - - if (dev2) - pci_release_selected_regions(dev2, bars); - pci_release_selected_regions(dev, bars); - - if (dev2) - pci_disable_device(dev2); - pci_disable_device(dev); -} -EXPORT_SYMBOL_GPL(ide_pci_remove); - -#ifdef CONFIG_PM -int ide_pci_suspend(struct pci_dev *dev, pm_message_t state) -{ - pci_save_state(dev); - pci_disable_device(dev); - pci_set_power_state(dev, pci_choose_state(dev, state)); - - return 0; -} -EXPORT_SYMBOL_GPL(ide_pci_suspend); - -int ide_pci_resume(struct pci_dev *dev) -{ - struct ide_host *host = pci_get_drvdata(dev); - int rc; - - pci_set_power_state(dev, PCI_D0); - - rc = pci_enable_device(dev); - if (rc) - return rc; - - pci_restore_state(dev); - pci_set_master(dev); - - if (host->init_chipset) - host->init_chipset(dev); - - return 0; -} -EXPORT_SYMBOL_GPL(ide_pci_resume); -#endif diff --git a/drivers/ide/siimage.c b/drivers/ide/siimage.c deleted file mode 100644 index c4b20f350b84..000000000000 --- a/drivers/ide/siimage.c +++ /dev/null @@ -1,843 +0,0 @@ -/* - * Copyright (C) 2001-2002 Andre Hedrick - * Copyright (C) 2003 Red Hat - * Copyright (C) 2007-2008 MontaVista Software, Inc. - * Copyright (C) 2007-2008 Bartlomiej Zolnierkiewicz - * - * May be copied or modified under the terms of the GNU General Public License - * - * Documentation for CMD680: - * http://gkernel.sourceforge.net/specs/sii/sii-0680a-v1.31.pdf.bz2 - * - * Documentation for SiI 3112: - * http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2 - * - * Errata and other documentation only available under NDA. - * - * - * FAQ Items: - * If you are using Marvell SATA-IDE adapters with Maxtor drives - * ensure the system is set up for ATA100/UDMA5, not UDMA6. - * - * If you are using WD drives with SATA bridges you must set the - * drive to "Single". "Master" will hang. - * - * If you have strange problems with nVidia chipset systems please - * see the SI support documentation and update your system BIOS - * if necessary - * - * The Dell DRAC4 has some interesting features including effectively hot - * unplugging/replugging the virtual CD interface when the DRAC is reset. - * This often causes drivers/ide/siimage to panic but is ok with the rather - * smarter code in libata. - * - * TODO: - * - VDMA support - */ - -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "siimage" - -/** - * pdev_is_sata - check if device is SATA - * @pdev: PCI device to check - * - * Returns true if this is a SATA controller - */ - -static int pdev_is_sata(struct pci_dev *pdev) -{ -#ifdef CONFIG_BLK_DEV_IDE_SATA - switch (pdev->device) { - case PCI_DEVICE_ID_SII_3112: - case PCI_DEVICE_ID_SII_1210SA: - return 1; - case PCI_DEVICE_ID_SII_680: - return 0; - } - BUG(); -#endif - return 0; -} - -/** - * is_sata - check if hwif is SATA - * @hwif: interface to check - * - * Returns true if this is a SATA controller - */ - -static inline int is_sata(ide_hwif_t *hwif) -{ - return pdev_is_sata(to_pci_dev(hwif->dev)); -} - -/** - * siimage_selreg - return register base - * @hwif: interface - * @r: config offset - * - * Turn a config register offset into the right address in either - * PCI space or MMIO space to access the control register in question - * Thankfully this is a configuration operation, so isn't performance - * critical. - */ - -static unsigned long siimage_selreg(ide_hwif_t *hwif, int r) -{ - unsigned long base = (unsigned long)hwif->hwif_data; - - base += 0xA0 + r; - if (hwif->host_flags & IDE_HFLAG_MMIO) - base += hwif->channel << 6; - else - base += hwif->channel << 4; - return base; -} - -/** - * siimage_seldev - return register base - * @hwif: interface - * @r: config offset - * - * Turn a config register offset into the right address in either - * PCI space or MMIO space to access the control register in question - * including accounting for the unit shift. - */ - -static inline unsigned long siimage_seldev(ide_drive_t *drive, int r) -{ - ide_hwif_t *hwif = drive->hwif; - unsigned long base = (unsigned long)hwif->hwif_data; - u8 unit = drive->dn & 1; - - base += 0xA0 + r; - if (hwif->host_flags & IDE_HFLAG_MMIO) - base += hwif->channel << 6; - else - base += hwif->channel << 4; - base |= unit << unit; - return base; -} - -static u8 sil_ioread8(struct pci_dev *dev, unsigned long addr) -{ - struct ide_host *host = pci_get_drvdata(dev); - u8 tmp = 0; - - if (host->host_priv) - tmp = readb((void __iomem *)addr); - else - pci_read_config_byte(dev, addr, &tmp); - - return tmp; -} - -static u16 sil_ioread16(struct pci_dev *dev, unsigned long addr) -{ - struct ide_host *host = pci_get_drvdata(dev); - u16 tmp = 0; - - if (host->host_priv) - tmp = readw((void __iomem *)addr); - else - pci_read_config_word(dev, addr, &tmp); - - return tmp; -} - -static void sil_iowrite8(struct pci_dev *dev, u8 val, unsigned long addr) -{ - struct ide_host *host = pci_get_drvdata(dev); - - if (host->host_priv) - writeb(val, (void __iomem *)addr); - else - pci_write_config_byte(dev, addr, val); -} - -static void sil_iowrite16(struct pci_dev *dev, u16 val, unsigned long addr) -{ - struct ide_host *host = pci_get_drvdata(dev); - - if (host->host_priv) - writew(val, (void __iomem *)addr); - else - pci_write_config_word(dev, addr, val); -} - -static void sil_iowrite32(struct pci_dev *dev, u32 val, unsigned long addr) -{ - struct ide_host *host = pci_get_drvdata(dev); - - if (host->host_priv) - writel(val, (void __iomem *)addr); - else - pci_write_config_dword(dev, addr, val); -} - -/** - * sil_udma_filter - compute UDMA mask - * @drive: IDE device - * - * Compute the available UDMA speeds for the device on the interface. - * - * For the CMD680 this depends on the clocking mode (scsc), for the - * SI3112 SATA controller life is a bit simpler. - */ - -static u8 sil_pata_udma_filter(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long base = (unsigned long)hwif->hwif_data; - u8 scsc, mask = 0; - - base += (hwif->host_flags & IDE_HFLAG_MMIO) ? 0x4A : 0x8A; - - scsc = sil_ioread8(dev, base); - - switch (scsc & 0x30) { - case 0x10: /* 133 */ - mask = ATA_UDMA6; - break; - case 0x20: /* 2xPCI */ - mask = ATA_UDMA6; - break; - case 0x00: /* 100 */ - mask = ATA_UDMA5; - break; - default: /* Disabled ? */ - BUG(); - } - - return mask; -} - -static u8 sil_sata_udma_filter(ide_drive_t *drive) -{ - char *m = (char *)&drive->id[ATA_ID_PROD]; - - return strstr(m, "Maxtor") ? ATA_UDMA5 : ATA_UDMA6; -} - -/** - * sil_set_pio_mode - set host controller for PIO mode - * @hwif: port - * @drive: drive - * - * Load the timing settings for this device mode into the - * controller. - */ - -static void sil_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - static const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 }; - static const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 }; - - struct pci_dev *dev = to_pci_dev(hwif->dev); - ide_drive_t *pair = ide_get_pair_dev(drive); - u32 speedt = 0; - u16 speedp = 0; - unsigned long addr = siimage_seldev(drive, 0x04); - unsigned long tfaddr = siimage_selreg(hwif, 0x02); - unsigned long base = (unsigned long)hwif->hwif_data; - const u8 pio = drive->pio_mode - XFER_PIO_0; - u8 tf_pio = pio; - u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; - u8 addr_mask = hwif->channel ? (mmio ? 0xF4 : 0x84) - : (mmio ? 0xB4 : 0x80); - u8 mode = 0; - u8 unit = drive->dn & 1; - - /* trim *taskfile* PIO to the slowest of the master/slave */ - if (pair) { - u8 pair_pio = pair->pio_mode - XFER_PIO_0; - - if (pair_pio < tf_pio) - tf_pio = pair_pio; - } - - /* cheat for now and use the docs */ - speedp = data_speed[pio]; - speedt = tf_speed[tf_pio]; - - sil_iowrite16(dev, speedp, addr); - sil_iowrite16(dev, speedt, tfaddr); - - /* now set up IORDY */ - speedp = sil_ioread16(dev, tfaddr - 2); - speedp &= ~0x200; - - mode = sil_ioread8(dev, base + addr_mask); - mode &= ~(unit ? 0x30 : 0x03); - - if (ide_pio_need_iordy(drive, pio)) { - speedp |= 0x200; - mode |= unit ? 0x10 : 0x01; - } - - sil_iowrite16(dev, speedp, tfaddr - 2); - sil_iowrite8(dev, mode, base + addr_mask); -} - -/** - * sil_set_dma_mode - set host controller for DMA mode - * @hwif: port - * @drive: drive - * - * Tune the SiI chipset for the desired DMA mode. - */ - -static void sil_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - static const u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }; - static const u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 }; - static const u16 dma[] = { 0x2208, 0x10C2, 0x10C1 }; - - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long base = (unsigned long)hwif->hwif_data; - u16 ultra = 0, multi = 0; - u8 mode = 0, unit = drive->dn & 1; - u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; - u8 scsc = 0, addr_mask = hwif->channel ? (mmio ? 0xF4 : 0x84) - : (mmio ? 0xB4 : 0x80); - unsigned long ma = siimage_seldev(drive, 0x08); - unsigned long ua = siimage_seldev(drive, 0x0C); - const u8 speed = drive->dma_mode; - - scsc = sil_ioread8 (dev, base + (mmio ? 0x4A : 0x8A)); - mode = sil_ioread8 (dev, base + addr_mask); - multi = sil_ioread16(dev, ma); - ultra = sil_ioread16(dev, ua); - - mode &= ~(unit ? 0x30 : 0x03); - ultra &= ~0x3F; - scsc = ((scsc & 0x30) == 0x00) ? 0 : 1; - - scsc = is_sata(hwif) ? 1 : scsc; - - if (speed >= XFER_UDMA_0) { - multi = dma[2]; - ultra |= scsc ? ultra6[speed - XFER_UDMA_0] : - ultra5[speed - XFER_UDMA_0]; - mode |= unit ? 0x30 : 0x03; - } else { - multi = dma[speed - XFER_MW_DMA_0]; - mode |= unit ? 0x20 : 0x02; - } - - sil_iowrite8 (dev, mode, base + addr_mask); - sil_iowrite16(dev, multi, ma); - sil_iowrite16(dev, ultra, ua); -} - -static int sil_test_irq(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long addr = siimage_selreg(hwif, 1); - u8 val = sil_ioread8(dev, addr); - - /* Return 1 if INTRQ asserted */ - return (val & 8) ? 1 : 0; -} - -/** - * siimage_mmio_dma_test_irq - check we caused an IRQ - * @drive: drive we are testing - * - * Check if we caused an IDE DMA interrupt. We may also have caused - * SATA status interrupts, if so we clean them up and continue. - */ - -static int siimage_mmio_dma_test_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - void __iomem *sata_error_addr - = (void __iomem *)hwif->sata_scr[SATA_ERROR_OFFSET]; - - if (sata_error_addr) { - unsigned long base = (unsigned long)hwif->hwif_data; - u32 ext_stat = readl((void __iomem *)(base + 0x10)); - u8 watchdog = 0; - - if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) { - u32 sata_error = readl(sata_error_addr); - - writel(sata_error, sata_error_addr); - watchdog = (sata_error & 0x00680000) ? 1 : 0; - printk(KERN_WARNING "%s: sata_error = 0x%08x, " - "watchdog = %d, %s\n", - drive->name, sata_error, watchdog, __func__); - } else - watchdog = (ext_stat & 0x8000) ? 1 : 0; - - ext_stat >>= 16; - if (!(ext_stat & 0x0404) && !watchdog) - return 0; - } - - /* return 1 if INTR asserted */ - if (readb((void __iomem *)(hwif->dma_base + ATA_DMA_STATUS)) & 4) - return 1; - - return 0; -} - -static int siimage_dma_test_irq(ide_drive_t *drive) -{ - if (drive->hwif->host_flags & IDE_HFLAG_MMIO) - return siimage_mmio_dma_test_irq(drive); - else - return ide_dma_test_irq(drive); -} - -/** - * sil_sata_reset_poll - wait for SATA reset - * @drive: drive we are resetting - * - * Poll the SATA phy and see whether it has come back from the dead - * yet. - */ - -static blk_status_t sil_sata_reset_poll(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - void __iomem *sata_status_addr - = (void __iomem *)hwif->sata_scr[SATA_STATUS_OFFSET]; - - if (sata_status_addr) { - /* SATA Status is available only when in MMIO mode */ - u32 sata_stat = readl(sata_status_addr); - - if ((sata_stat & 0x03) != 0x03) { - printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n", - hwif->name, sata_stat); - return BLK_STS_IOERR; - } - } - - return BLK_STS_OK; -} - -/** - * sil_sata_pre_reset - reset hook - * @drive: IDE device being reset - * - * For the SATA devices we need to handle recalibration/geometry - * differently - */ - -static void sil_sata_pre_reset(ide_drive_t *drive) -{ - if (drive->media == ide_disk) { - drive->special_flags &= - ~(IDE_SFLAG_SET_GEOMETRY | IDE_SFLAG_RECALIBRATE); - } -} - -/** - * init_chipset_siimage - set up an SI device - * @dev: PCI device - * - * Perform the initial PCI set up for this device. Attempt to switch - * to 133 MHz clocking if the system isn't already set up to do it. - */ - -static int init_chipset_siimage(struct pci_dev *dev) -{ - struct ide_host *host = pci_get_drvdata(dev); - void __iomem *ioaddr = host->host_priv; - unsigned long base, scsc_addr; - u8 rev = dev->revision, tmp; - - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, rev ? 1 : 255); - - if (ioaddr) - pci_set_master(dev); - - base = (unsigned long)ioaddr; - - if (ioaddr && pdev_is_sata(dev)) { - u32 tmp32, irq_mask; - - /* make sure IDE0/1 interrupts are not masked */ - irq_mask = (1 << 22) | (1 << 23); - tmp32 = readl(ioaddr + 0x48); - if (tmp32 & irq_mask) { - tmp32 &= ~irq_mask; - writel(tmp32, ioaddr + 0x48); - readl(ioaddr + 0x48); /* flush */ - } - writel(0, ioaddr + 0x148); - writel(0, ioaddr + 0x1C8); - } - - sil_iowrite8(dev, 0, base ? (base + 0xB4) : 0x80); - sil_iowrite8(dev, 0, base ? (base + 0xF4) : 0x84); - - scsc_addr = base ? (base + 0x4A) : 0x8A; - tmp = sil_ioread8(dev, scsc_addr); - - switch (tmp & 0x30) { - case 0x00: - /* On 100 MHz clocking, try and switch to 133 MHz */ - sil_iowrite8(dev, tmp | 0x10, scsc_addr); - break; - case 0x30: - /* Clocking is disabled, attempt to force 133MHz clocking. */ - sil_iowrite8(dev, tmp & ~0x20, scsc_addr); - case 0x10: - /* On 133Mhz clocking. */ - break; - case 0x20: - /* On PCIx2 clocking. */ - break; - } - - tmp = sil_ioread8(dev, scsc_addr); - - sil_iowrite8 (dev, 0x72, base + 0xA1); - sil_iowrite16(dev, 0x328A, base + 0xA2); - sil_iowrite32(dev, 0x62DD62DD, base + 0xA4); - sil_iowrite32(dev, 0x43924392, base + 0xA8); - sil_iowrite32(dev, 0x40094009, base + 0xAC); - sil_iowrite8 (dev, 0x72, base ? (base + 0xE1) : 0xB1); - sil_iowrite16(dev, 0x328A, base ? (base + 0xE2) : 0xB2); - sil_iowrite32(dev, 0x62DD62DD, base ? (base + 0xE4) : 0xB4); - sil_iowrite32(dev, 0x43924392, base ? (base + 0xE8) : 0xB8); - sil_iowrite32(dev, 0x40094009, base ? (base + 0xEC) : 0xBC); - - if (base && pdev_is_sata(dev)) { - writel(0xFFFF0000, ioaddr + 0x108); - writel(0xFFFF0000, ioaddr + 0x188); - writel(0x00680000, ioaddr + 0x148); - writel(0x00680000, ioaddr + 0x1C8); - } - - /* report the clocking mode of the controller */ - if (!pdev_is_sata(dev)) { - static const char *clk_str[] = - { "== 100", "== 133", "== 2X PCI", "DISABLED!" }; - - tmp >>= 4; - printk(KERN_INFO DRV_NAME " %s: BASE CLOCK %s\n", - pci_name(dev), clk_str[tmp & 3]); - } - - return 0; -} - -/** - * init_mmio_iops_siimage - set up the iops for MMIO - * @hwif: interface to set up - * - * The basic setup here is fairly simple, we can use standard MMIO - * operations. However we do have to set the taskfile register offsets - * by hand as there isn't a standard defined layout for them this time. - * - * The hardware supports buffered taskfiles and also some rather nice - * extended PRD tables. For better SI3112 support use the libata driver - */ - -static void init_mmio_iops_siimage(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - struct ide_host *host = pci_get_drvdata(dev); - void *addr = host->host_priv; - u8 ch = hwif->channel; - struct ide_io_ports *io_ports = &hwif->io_ports; - unsigned long base; - - /* - * Fill in the basic hwif bits - */ - hwif->host_flags |= IDE_HFLAG_MMIO; - - hwif->hwif_data = addr; - - /* - * Now set up the hw. We have to do this ourselves as the - * MMIO layout isn't the same as the standard port based I/O. - */ - memset(io_ports, 0, sizeof(*io_ports)); - - base = (unsigned long)addr; - if (ch) - base += 0xC0; - else - base += 0x80; - - /* - * The buffered task file doesn't have status/control, so we - * can't currently use it sanely since we want to use LBA48 mode. - */ - io_ports->data_addr = base; - io_ports->error_addr = base + 1; - io_ports->nsect_addr = base + 2; - io_ports->lbal_addr = base + 3; - io_ports->lbam_addr = base + 4; - io_ports->lbah_addr = base + 5; - io_ports->device_addr = base + 6; - io_ports->status_addr = base + 7; - io_ports->ctl_addr = base + 10; - - if (pdev_is_sata(dev)) { - base = (unsigned long)addr; - if (ch) - base += 0x80; - hwif->sata_scr[SATA_STATUS_OFFSET] = base + 0x104; - hwif->sata_scr[SATA_ERROR_OFFSET] = base + 0x108; - hwif->sata_scr[SATA_CONTROL_OFFSET] = base + 0x100; - } - - hwif->irq = dev->irq; - - hwif->dma_base = (unsigned long)addr + (ch ? 0x08 : 0x00); -} - -static int is_dev_seagate_sata(ide_drive_t *drive) -{ - const char *s = (const char *)&drive->id[ATA_ID_PROD]; - unsigned len = strnlen(s, ATA_ID_PROD_LEN); - - if ((len > 4) && (!memcmp(s, "ST", 2))) - if ((!memcmp(s + len - 2, "AS", 2)) || - (!memcmp(s + len - 3, "ASL", 3))) { - printk(KERN_INFO "%s: applying pessimistic Seagate " - "errata fix\n", drive->name); - return 1; - } - - return 0; -} - -/** - * sil_quirkproc - post probe fixups - * @drive: drive - * - * Called after drive probe we use this to decide whether the - * Seagate fixup must be applied. This used to be in init_iops but - * that can occur before we know what drives are present. - */ - -static void sil_quirkproc(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - - /* Try and rise the rqsize */ - if (!is_sata(hwif) || !is_dev_seagate_sata(drive)) - hwif->rqsize = 128; -} - -/** - * init_iops_siimage - set up iops - * @hwif: interface to set up - * - * Do the basic setup for the SIIMAGE hardware interface - * and then do the MMIO setup if we can. This is the first - * look in we get for setting up the hwif so that we - * can get the iops right before using them. - */ - -static void init_iops_siimage(ide_hwif_t *hwif) -{ - struct ide_host *host = dev_get_drvdata(hwif->dev); - - hwif->hwif_data = NULL; - - /* Pessimal until we finish probing */ - hwif->rqsize = 15; - - if (host->host_priv) - init_mmio_iops_siimage(hwif); -} - -/** - * sil_cable_detect - cable detection - * @hwif: interface to check - * - * Check for the presence of an ATA66 capable cable on the interface. - */ - -static u8 sil_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long addr = siimage_selreg(hwif, 0); - u8 ata66 = sil_ioread8(dev, addr); - - return (ata66 & 0x01) ? ATA_CBL_PATA80 : ATA_CBL_PATA40; -} - -static const struct ide_port_ops sil_pata_port_ops = { - .set_pio_mode = sil_set_pio_mode, - .set_dma_mode = sil_set_dma_mode, - .quirkproc = sil_quirkproc, - .test_irq = sil_test_irq, - .udma_filter = sil_pata_udma_filter, - .cable_detect = sil_cable_detect, -}; - -static const struct ide_port_ops sil_sata_port_ops = { - .set_pio_mode = sil_set_pio_mode, - .set_dma_mode = sil_set_dma_mode, - .reset_poll = sil_sata_reset_poll, - .pre_reset = sil_sata_pre_reset, - .quirkproc = sil_quirkproc, - .test_irq = sil_test_irq, - .udma_filter = sil_sata_udma_filter, - .cable_detect = sil_cable_detect, -}; - -static const struct ide_dma_ops sil_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = ide_dma_start, - .dma_end = ide_dma_end, - .dma_test_irq = siimage_dma_test_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_lost_irq = ide_dma_lost_irq, - .dma_sff_read_status = ide_dma_sff_read_status, -}; - -#define DECLARE_SII_DEV(p_ops) \ - { \ - .name = DRV_NAME, \ - .init_chipset = init_chipset_siimage, \ - .init_iops = init_iops_siimage, \ - .port_ops = p_ops, \ - .dma_ops = &sil_dma_ops, \ - .pio_mask = ATA_PIO4, \ - .mwdma_mask = ATA_MWDMA2, \ - .udma_mask = ATA_UDMA6, \ - } - -static const struct ide_port_info siimage_chipsets[] = { - /* 0: SiI680 */ DECLARE_SII_DEV(&sil_pata_port_ops), - /* 1: SiI3112 */ DECLARE_SII_DEV(&sil_sata_port_ops) -}; - -/** - * siimage_init_one - PCI layer discovery entry - * @dev: PCI device - * @id: ident table entry - * - * Called by the PCI code when it finds an SiI680 or SiI3112 controller. - * We then use the IDE PCI generic helper to do most of the work. - */ - -static int siimage_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - void __iomem *ioaddr = NULL; - resource_size_t bar5 = pci_resource_start(dev, 5); - unsigned long barsize = pci_resource_len(dev, 5); - int rc; - struct ide_port_info d; - u8 idx = id->driver_data; - u8 BA5_EN; - - d = siimage_chipsets[idx]; - - if (idx) { - static int first = 1; - - if (first) { - printk(KERN_INFO DRV_NAME ": For full SATA support you " - "should use the libata sata_sil module.\n"); - first = 0; - } - - d.host_flags |= IDE_HFLAG_NO_ATAPI_DMA; - } - - rc = pci_enable_device(dev); - if (rc) - return rc; - - pci_read_config_byte(dev, 0x8A, &BA5_EN); - if ((BA5_EN & 0x01) || bar5) { - /* - * Drop back to PIO if we can't map the MMIO. Some systems - * seem to get terminally confused in the PCI spaces. - */ - if (!request_mem_region(bar5, barsize, d.name)) { - printk(KERN_WARNING DRV_NAME " %s: MMIO ports not " - "available\n", pci_name(dev)); - } else { - ioaddr = pci_ioremap_bar(dev, 5); - if (ioaddr == NULL) - release_mem_region(bar5, barsize); - } - } - - rc = ide_pci_init_one(dev, &d, ioaddr); - if (rc) { - if (ioaddr) { - iounmap(ioaddr); - release_mem_region(bar5, barsize); - } - pci_disable_device(dev); - } - - return rc; -} - -static void siimage_remove(struct pci_dev *dev) -{ - struct ide_host *host = pci_get_drvdata(dev); - void __iomem *ioaddr = host->host_priv; - - ide_pci_remove(dev); - - if (ioaddr) { - resource_size_t bar5 = pci_resource_start(dev, 5); - unsigned long barsize = pci_resource_len(dev, 5); - - iounmap(ioaddr); - release_mem_region(bar5, barsize); - } - - pci_disable_device(dev); -} - -static const struct pci_device_id siimage_pci_tbl[] = { - { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), 0 }, -#ifdef CONFIG_BLK_DEV_IDE_SATA - { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_3112), 1 }, - { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_1210SA), 1 }, -#endif - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, siimage_pci_tbl); - -static struct pci_driver siimage_pci_driver = { - .name = "SiI_IDE", - .id_table = siimage_pci_tbl, - .probe = siimage_init_one, - .remove = siimage_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init siimage_ide_init(void) -{ - return ide_pci_register_driver(&siimage_pci_driver); -} - -static void __exit siimage_ide_exit(void) -{ - pci_unregister_driver(&siimage_pci_driver); -} - -module_init(siimage_ide_init); -module_exit(siimage_ide_exit); - -MODULE_AUTHOR("Andre Hedrick, Alan Cox"); -MODULE_DESCRIPTION("PCI driver module for SiI IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c deleted file mode 100644 index 1a700bef6c56..000000000000 --- a/drivers/ide/sis5513.c +++ /dev/null @@ -1,637 +0,0 @@ -/* - * Copyright (C) 1999-2000 Andre Hedrick - * Copyright (C) 2002 Lionel Bouton , Maintainer - * Copyright (C) 2003 Vojtech Pavlik - * Copyright (C) 2007-2009 Bartlomiej Zolnierkiewicz - * - * May be copied or modified under the terms of the GNU General Public License - * - * - * Thanks : - * - * SiS Taiwan : for direct support and hardware. - * Daniela Engert : for initial ATA100 advices and numerous others. - * John Fremlin, Manfred Spraul, Dave Morgan, Peter Kjellerstedt : - * for checking code correctness, providing patches. - * - * - * Original tests and design on the SiS620 chipset. - * ATA100 tests and design on the SiS735 chipset. - * ATA16/33 support from specs - * ATA133 support for SiS961/962 by L.C. Chang - * ATA133 961/962/963 fixes by Vojtech Pavlik - * - * Documentation: - * SiS chipset documentation available under NDA to companies only - * (not to individuals). - */ - -/* - * The original SiS5513 comes from a SiS5511/55112/5513 chipset. The original - * SiS5513 was also used in the SiS5596/5513 chipset. Thus if we see a SiS5511 - * or SiS5596, we can assume we see the first MWDMA-16 capable SiS5513 chip. - * - * Later SiS chipsets integrated the 5513 functionality into the NorthBridge, - * starting with SiS5571 and up to SiS745. The PCI ID didn't change, though. We - * can figure out that we have a more modern and more capable 5513 by looking - * for the respective NorthBridge IDs. - * - * Even later (96x family) SiS chipsets use the MuTIOL link and place the 5513 - * into the SouthBrige. Here we cannot rely on looking up the NorthBridge PCI - * ID, while the now ATA-133 capable 5513 still has the same PCI ID. - * Fortunately the 5513 can be 'unmasked' by fiddling with some config space - * bits, changing its device id to the true one - 5517 for 961 and 5518 for - * 962/963. - */ - -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "sis5513" - -/* registers layout and init values are chipset family dependent */ -#undef ATA_16 -#define ATA_16 0x01 -#define ATA_33 0x02 -#define ATA_66 0x03 -#define ATA_100a 0x04 /* SiS730/SiS550 is ATA100 with ATA66 layout */ -#define ATA_100 0x05 -#define ATA_133a 0x06 /* SiS961b with 133 support */ -#define ATA_133 0x07 /* SiS962/963 */ - -static u8 chipset_family; - -/* - * Devices supported - */ -static const struct { - const char *name; - u16 host_id; - u8 chipset_family; - u8 flags; -} SiSHostChipInfo[] = { - { "SiS968", PCI_DEVICE_ID_SI_968, ATA_133 }, - { "SiS966", PCI_DEVICE_ID_SI_966, ATA_133 }, - { "SiS965", PCI_DEVICE_ID_SI_965, ATA_133 }, - { "SiS745", PCI_DEVICE_ID_SI_745, ATA_100 }, - { "SiS735", PCI_DEVICE_ID_SI_735, ATA_100 }, - { "SiS733", PCI_DEVICE_ID_SI_733, ATA_100 }, - { "SiS635", PCI_DEVICE_ID_SI_635, ATA_100 }, - { "SiS633", PCI_DEVICE_ID_SI_633, ATA_100 }, - - { "SiS730", PCI_DEVICE_ID_SI_730, ATA_100a }, - { "SiS550", PCI_DEVICE_ID_SI_550, ATA_100a }, - - { "SiS640", PCI_DEVICE_ID_SI_640, ATA_66 }, - { "SiS630", PCI_DEVICE_ID_SI_630, ATA_66 }, - { "SiS620", PCI_DEVICE_ID_SI_620, ATA_66 }, - { "SiS540", PCI_DEVICE_ID_SI_540, ATA_66 }, - { "SiS530", PCI_DEVICE_ID_SI_530, ATA_66 }, - - { "SiS5600", PCI_DEVICE_ID_SI_5600, ATA_33 }, - { "SiS5598", PCI_DEVICE_ID_SI_5598, ATA_33 }, - { "SiS5597", PCI_DEVICE_ID_SI_5597, ATA_33 }, - { "SiS5591/2", PCI_DEVICE_ID_SI_5591, ATA_33 }, - { "SiS5582", PCI_DEVICE_ID_SI_5582, ATA_33 }, - { "SiS5581", PCI_DEVICE_ID_SI_5581, ATA_33 }, - - { "SiS5596", PCI_DEVICE_ID_SI_5596, ATA_16 }, - { "SiS5571", PCI_DEVICE_ID_SI_5571, ATA_16 }, - { "SiS5517", PCI_DEVICE_ID_SI_5517, ATA_16 }, - { "SiS551x", PCI_DEVICE_ID_SI_5511, ATA_16 }, -}; - -/* Cycle time bits and values vary across chip dma capabilities - These three arrays hold the register layout and the values to set. - Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */ - -/* {0, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */ -static u8 cycle_time_offset[] = { 0, 0, 5, 4, 4, 0, 0 }; -static u8 cycle_time_range[] = { 0, 0, 2, 3, 3, 4, 4 }; -static u8 cycle_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = { - { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */ - { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */ - { 3, 2, 1, 0, 0, 0, 0 }, /* ATA_33 */ - { 7, 5, 3, 2, 1, 0, 0 }, /* ATA_66 */ - { 7, 5, 3, 2, 1, 0, 0 }, /* ATA_100a (730 specific), - different cycle_time range and offset */ - { 11, 7, 5, 4, 2, 1, 0 }, /* ATA_100 */ - { 15, 10, 7, 5, 3, 2, 1 }, /* ATA_133a (earliest 691 southbridges) */ - { 15, 10, 7, 5, 3, 2, 1 }, /* ATA_133 */ -}; -/* CRC Valid Setup Time vary across IDE clock setting 33/66/100/133 - See SiS962 data sheet for more detail */ -static u8 cvs_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = { - { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */ - { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */ - { 2, 1, 1, 0, 0, 0, 0 }, - { 4, 3, 2, 1, 0, 0, 0 }, - { 4, 3, 2, 1, 0, 0, 0 }, - { 6, 4, 3, 1, 1, 1, 0 }, - { 9, 6, 4, 2, 2, 2, 2 }, - { 9, 6, 4, 2, 2, 2, 2 }, -}; -/* Initialize time, Active time, Recovery time vary across - IDE clock settings. These 3 arrays hold the register value - for PIO0/1/2/3/4 and DMA0/1/2 mode in order */ -static u8 ini_time_value[][8] = { - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 2, 1, 0, 0, 0, 1, 0, 0 }, - { 4, 3, 1, 1, 1, 3, 1, 1 }, - { 4, 3, 1, 1, 1, 3, 1, 1 }, - { 6, 4, 2, 2, 2, 4, 2, 2 }, - { 9, 6, 3, 3, 3, 6, 3, 3 }, - { 9, 6, 3, 3, 3, 6, 3, 3 }, -}; -static u8 act_time_value[][8] = { - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 9, 9, 9, 2, 2, 7, 2, 2 }, - { 19, 19, 19, 5, 4, 14, 5, 4 }, - { 19, 19, 19, 5, 4, 14, 5, 4 }, - { 28, 28, 28, 7, 6, 21, 7, 6 }, - { 38, 38, 38, 10, 9, 28, 10, 9 }, - { 38, 38, 38, 10, 9, 28, 10, 9 }, -}; -static u8 rco_time_value[][8] = { - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 9, 2, 0, 2, 0, 7, 1, 1 }, - { 19, 5, 1, 5, 2, 16, 3, 2 }, - { 19, 5, 1, 5, 2, 16, 3, 2 }, - { 30, 9, 3, 9, 4, 25, 6, 4 }, - { 40, 12, 4, 12, 5, 34, 12, 5 }, - { 40, 12, 4, 12, 5, 34, 12, 5 }, -}; - -/* - * Printing configuration - */ -/* Used for chipset type printing at boot time */ -static char *chipset_capability[] = { - "ATA", "ATA 16", - "ATA 33", "ATA 66", - "ATA 100 (1st gen)", "ATA 100 (2nd gen)", - "ATA 133 (1st gen)", "ATA 133 (2nd gen)" -}; - -/* - * Configuration functions - */ - -static u8 sis_ata133_get_base(ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(drive->hwif->dev); - u32 reg54 = 0; - - pci_read_config_dword(dev, 0x54, ®54); - - return ((reg54 & 0x40000000) ? 0x70 : 0x40) + drive->dn * 4; -} - -static void sis_ata16_program_timings(ide_drive_t *drive, const u8 mode) -{ - struct pci_dev *dev = to_pci_dev(drive->hwif->dev); - u16 t1 = 0; - u8 drive_pci = 0x40 + drive->dn * 2; - - const u16 pio_timings[] = { 0x000, 0x607, 0x404, 0x303, 0x301 }; - const u16 mwdma_timings[] = { 0x008, 0x302, 0x301 }; - - pci_read_config_word(dev, drive_pci, &t1); - - /* clear active/recovery timings */ - t1 &= ~0x070f; - if (mode >= XFER_MW_DMA_0) { - if (chipset_family > ATA_16) - t1 &= ~0x8000; /* disable UDMA */ - t1 |= mwdma_timings[mode - XFER_MW_DMA_0]; - } else - t1 |= pio_timings[mode - XFER_PIO_0]; - - pci_write_config_word(dev, drive_pci, t1); -} - -static void sis_ata100_program_timings(ide_drive_t *drive, const u8 mode) -{ - struct pci_dev *dev = to_pci_dev(drive->hwif->dev); - u8 t1, drive_pci = 0x40 + drive->dn * 2; - - /* timing bits: 7:4 active 3:0 recovery */ - const u8 pio_timings[] = { 0x00, 0x67, 0x44, 0x33, 0x31 }; - const u8 mwdma_timings[] = { 0x08, 0x32, 0x31 }; - - if (mode >= XFER_MW_DMA_0) { - u8 t2 = 0; - - pci_read_config_byte(dev, drive_pci, &t2); - t2 &= ~0x80; /* disable UDMA */ - pci_write_config_byte(dev, drive_pci, t2); - - t1 = mwdma_timings[mode - XFER_MW_DMA_0]; - } else - t1 = pio_timings[mode - XFER_PIO_0]; - - pci_write_config_byte(dev, drive_pci + 1, t1); -} - -static void sis_ata133_program_timings(ide_drive_t *drive, const u8 mode) -{ - struct pci_dev *dev = to_pci_dev(drive->hwif->dev); - u32 t1 = 0; - u8 drive_pci = sis_ata133_get_base(drive), clk, idx; - - pci_read_config_dword(dev, drive_pci, &t1); - - t1 &= 0xc0c00fff; - clk = (t1 & 0x08) ? ATA_133 : ATA_100; - if (mode >= XFER_MW_DMA_0) { - t1 &= ~0x04; /* disable UDMA */ - idx = mode - XFER_MW_DMA_0 + 5; - } else - idx = mode - XFER_PIO_0; - t1 |= ini_time_value[clk][idx] << 12; - t1 |= act_time_value[clk][idx] << 16; - t1 |= rco_time_value[clk][idx] << 24; - - pci_write_config_dword(dev, drive_pci, t1); -} - -static void sis_program_timings(ide_drive_t *drive, const u8 mode) -{ - if (chipset_family < ATA_100) /* ATA_16/33/66/100a */ - sis_ata16_program_timings(drive, mode); - else if (chipset_family < ATA_133) /* ATA_100/133a */ - sis_ata100_program_timings(drive, mode); - else /* ATA_133 */ - sis_ata133_program_timings(drive, mode); -} - -static void config_drive_art_rwp(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 reg4bh = 0; - u8 rw_prefetch = 0; - - pci_read_config_byte(dev, 0x4b, ®4bh); - - rw_prefetch = reg4bh & ~(0x11 << drive->dn); - - if (drive->media == ide_disk) - rw_prefetch |= 0x11 << drive->dn; - - if (reg4bh != rw_prefetch) - pci_write_config_byte(dev, 0x4b, rw_prefetch); -} - -static void sis_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - config_drive_art_rwp(drive); - sis_program_timings(drive, drive->pio_mode); -} - -static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode) -{ - struct pci_dev *dev = to_pci_dev(drive->hwif->dev); - u32 regdw = 0; - u8 drive_pci = sis_ata133_get_base(drive), clk, idx; - - pci_read_config_dword(dev, drive_pci, ®dw); - - regdw |= 0x04; - regdw &= 0xfffff00f; - /* check if ATA133 enable */ - clk = (regdw & 0x08) ? ATA_133 : ATA_100; - idx = mode - XFER_UDMA_0; - regdw |= cycle_time_value[clk][idx] << 4; - regdw |= cvs_time_value[clk][idx] << 8; - - pci_write_config_dword(dev, drive_pci, regdw); -} - -static void sis_ata33_program_udma_timings(ide_drive_t *drive, const u8 mode) -{ - struct pci_dev *dev = to_pci_dev(drive->hwif->dev); - u8 drive_pci = 0x40 + drive->dn * 2, reg = 0, i = chipset_family; - - pci_read_config_byte(dev, drive_pci + 1, ®); - - /* force the UDMA bit on if we want to use UDMA */ - reg |= 0x80; - /* clean reg cycle time bits */ - reg &= ~((0xff >> (8 - cycle_time_range[i])) << cycle_time_offset[i]); - /* set reg cycle time bits */ - reg |= cycle_time_value[i][mode - XFER_UDMA_0] << cycle_time_offset[i]; - - pci_write_config_byte(dev, drive_pci + 1, reg); -} - -static void sis_program_udma_timings(ide_drive_t *drive, const u8 mode) -{ - if (chipset_family >= ATA_133) /* ATA_133 */ - sis_ata133_program_udma_timings(drive, mode); - else /* ATA_33/66/100a/100/133a */ - sis_ata33_program_udma_timings(drive, mode); -} - -static void sis_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - const u8 speed = drive->dma_mode; - - if (speed >= XFER_UDMA_0) - sis_program_udma_timings(drive, speed); - else - sis_program_timings(drive, speed); -} - -static u8 sis_ata133_udma_filter(ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(drive->hwif->dev); - u32 regdw = 0; - u8 drive_pci = sis_ata133_get_base(drive); - - pci_read_config_dword(dev, drive_pci, ®dw); - - /* if ATA133 disable, we should not set speed above UDMA5 */ - return (regdw & 0x08) ? ATA_UDMA6 : ATA_UDMA5; -} - -static int sis_find_family(struct pci_dev *dev) -{ - struct pci_dev *host; - int i = 0; - - chipset_family = 0; - - for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !chipset_family; i++) { - - host = pci_get_device(PCI_VENDOR_ID_SI, SiSHostChipInfo[i].host_id, NULL); - - if (!host) - continue; - - chipset_family = SiSHostChipInfo[i].chipset_family; - - /* Special case for SiS630 : 630S/ET is ATA_100a */ - if (SiSHostChipInfo[i].host_id == PCI_DEVICE_ID_SI_630) { - if (host->revision >= 0x30) - chipset_family = ATA_100a; - } - pci_dev_put(host); - - printk(KERN_INFO DRV_NAME " %s: %s %s controller\n", - pci_name(dev), SiSHostChipInfo[i].name, - chipset_capability[chipset_family]); - } - - if (!chipset_family) { /* Belongs to pci-quirks */ - - u32 idemisc; - u16 trueid; - - /* Disable ID masking and register remapping */ - pci_read_config_dword(dev, 0x54, &idemisc); - pci_write_config_dword(dev, 0x54, (idemisc & 0x7fffffff)); - pci_read_config_word(dev, PCI_DEVICE_ID, &trueid); - pci_write_config_dword(dev, 0x54, idemisc); - - if (trueid == 0x5518) { - printk(KERN_INFO DRV_NAME " %s: SiS 962/963 MuTIOL IDE UDMA133 controller\n", - pci_name(dev)); - chipset_family = ATA_133; - - /* Check for 5513 compatibility mapping - * We must use this, else the port enabled code will fail, - * as it expects the enablebits at 0x4a. - */ - if ((idemisc & 0x40000000) == 0) { - pci_write_config_dword(dev, 0x54, idemisc | 0x40000000); - printk(KERN_INFO DRV_NAME " %s: Switching to 5513 register mapping\n", - pci_name(dev)); - } - } - } - - if (!chipset_family) { /* Belongs to pci-quirks */ - - struct pci_dev *lpc_bridge; - u16 trueid; - u8 prefctl; - u8 idecfg; - - pci_read_config_byte(dev, 0x4a, &idecfg); - pci_write_config_byte(dev, 0x4a, idecfg | 0x10); - pci_read_config_word(dev, PCI_DEVICE_ID, &trueid); - pci_write_config_byte(dev, 0x4a, idecfg); - - if (trueid == 0x5517) { /* SiS 961/961B */ - - lpc_bridge = pci_get_slot(dev->bus, 0x10); /* Bus 0, Dev 2, Fn 0 */ - pci_read_config_byte(dev, 0x49, &prefctl); - pci_dev_put(lpc_bridge); - - if (lpc_bridge->revision == 0x10 && (prefctl & 0x80)) { - printk(KERN_INFO DRV_NAME " %s: SiS 961B MuTIOL IDE UDMA133 controller\n", - pci_name(dev)); - chipset_family = ATA_133a; - } else { - printk(KERN_INFO DRV_NAME " %s: SiS 961 MuTIOL IDE UDMA100 controller\n", - pci_name(dev)); - chipset_family = ATA_100; - } - } - } - - return chipset_family; -} - -static int init_chipset_sis5513(struct pci_dev *dev) -{ - /* Make general config ops here - 1/ tell IDE channels to operate in Compatibility mode only - 2/ tell old chips to allow per drive IDE timings */ - - u8 reg; - u16 regw; - - switch (chipset_family) { - case ATA_133: - /* SiS962 operation mode */ - pci_read_config_word(dev, 0x50, ®w); - if (regw & 0x08) - pci_write_config_word(dev, 0x50, regw&0xfff7); - pci_read_config_word(dev, 0x52, ®w); - if (regw & 0x08) - pci_write_config_word(dev, 0x52, regw&0xfff7); - break; - case ATA_133a: - case ATA_100: - /* Fixup latency */ - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80); - /* Set compatibility bit */ - pci_read_config_byte(dev, 0x49, ®); - if (!(reg & 0x01)) - pci_write_config_byte(dev, 0x49, reg|0x01); - break; - case ATA_100a: - case ATA_66: - /* Fixup latency */ - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10); - - /* On ATA_66 chips the bit was elsewhere */ - pci_read_config_byte(dev, 0x52, ®); - if (!(reg & 0x04)) - pci_write_config_byte(dev, 0x52, reg|0x04); - break; - case ATA_33: - /* On ATA_33 we didn't have a single bit to set */ - pci_read_config_byte(dev, 0x09, ®); - if ((reg & 0x0f) != 0x00) - pci_write_config_byte(dev, 0x09, reg&0xf0); - fallthrough; - case ATA_16: - /* force per drive recovery and active timings - needed on ATA_33 and below chips */ - pci_read_config_byte(dev, 0x52, ®); - if (!(reg & 0x08)) - pci_write_config_byte(dev, 0x52, reg|0x08); - break; - } - - return 0; -} - -struct sis_laptop { - u16 device; - u16 subvendor; - u16 subdevice; -}; - -static const struct sis_laptop sis_laptop[] = { - /* devid, subvendor, subdev */ - { 0x5513, 0x1043, 0x1107 }, /* ASUS A6K */ - { 0x5513, 0x1734, 0x105f }, /* FSC Amilo A1630 */ - { 0x5513, 0x1071, 0x8640 }, /* EasyNote K5305 */ - /* end marker */ - { 0, } -}; - -static u8 sis_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *pdev = to_pci_dev(hwif->dev); - const struct sis_laptop *lap = &sis_laptop[0]; - u8 ata66 = 0; - - while (lap->device) { - if (lap->device == pdev->device && - lap->subvendor == pdev->subsystem_vendor && - lap->subdevice == pdev->subsystem_device) - return ATA_CBL_PATA40_SHORT; - lap++; - } - - if (chipset_family >= ATA_133) { - u16 regw = 0; - u16 reg_addr = hwif->channel ? 0x52: 0x50; - pci_read_config_word(pdev, reg_addr, ®w); - ata66 = (regw & 0x8000) ? 0 : 1; - } else if (chipset_family >= ATA_66) { - u8 reg48h = 0; - u8 mask = hwif->channel ? 0x20 : 0x10; - pci_read_config_byte(pdev, 0x48, ®48h); - ata66 = (reg48h & mask) ? 0 : 1; - } - - return ata66 ? ATA_CBL_PATA80 : ATA_CBL_PATA40; -} - -static const struct ide_port_ops sis_port_ops = { - .set_pio_mode = sis_set_pio_mode, - .set_dma_mode = sis_set_dma_mode, - .cable_detect = sis_cable_detect, -}; - -static const struct ide_port_ops sis_ata133_port_ops = { - .set_pio_mode = sis_set_pio_mode, - .set_dma_mode = sis_set_dma_mode, - .udma_filter = sis_ata133_udma_filter, - .cable_detect = sis_cable_detect, -}; - -static const struct ide_port_info sis5513_chipset = { - .name = DRV_NAME, - .init_chipset = init_chipset_sis5513, - .enablebits = { {0x4a, 0x02, 0x02}, {0x4a, 0x04, 0x04} }, - .host_flags = IDE_HFLAG_NO_AUTODMA, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, -}; - -static int sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct ide_port_info d = sis5513_chipset; - u8 udma_rates[] = { 0x00, 0x00, 0x07, 0x1f, 0x3f, 0x3f, 0x7f, 0x7f }; - int rc; - - rc = pci_enable_device(dev); - if (rc) - return rc; - - if (sis_find_family(dev) == 0) - return -ENOTSUPP; - - if (chipset_family >= ATA_133) - d.port_ops = &sis_ata133_port_ops; - else - d.port_ops = &sis_port_ops; - - d.udma_mask = udma_rates[chipset_family]; - - return ide_pci_init_one(dev, &d, NULL); -} - -static void sis5513_remove(struct pci_dev *dev) -{ - ide_pci_remove(dev); - pci_disable_device(dev); -} - -static const struct pci_device_id sis5513_pci_tbl[] = { - { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_5513), 0 }, - { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_5518), 0 }, - { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_1180), 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, sis5513_pci_tbl); - -static struct pci_driver sis5513_pci_driver = { - .name = "SIS_IDE", - .id_table = sis5513_pci_tbl, - .probe = sis5513_init_one, - .remove = sis5513_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init sis5513_ide_init(void) -{ - return ide_pci_register_driver(&sis5513_pci_driver); -} - -static void __exit sis5513_ide_exit(void) -{ - pci_unregister_driver(&sis5513_pci_driver); -} - -module_init(sis5513_ide_init); -module_exit(sis5513_ide_exit); - -MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick, Vojtech Pavlik"); -MODULE_DESCRIPTION("PCI driver module for SIS IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c deleted file mode 100644 index 5c24c420c438..000000000000 --- a/drivers/ide/sl82c105.c +++ /dev/null @@ -1,367 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * SL82C105/Winbond 553 IDE driver - * - * Maintainer unknown. - * - * Drive tuning added from Rebel.com's kernel sources - * -- Russell King (15/11/98) linux@arm.linux.org.uk - * - * Merge in Russell's HW workarounds, fix various problems - * with the timing registers setup. - * -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org - * - * Copyright (C) 2006-2007,2009 MontaVista Software, Inc. - * Copyright (C) 2007 Bartlomiej Zolnierkiewicz - */ - -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "sl82c105" - -/* - * SL82C105 PCI config register 0x40 bits. - */ -#define CTRL_IDE_IRQB (1 << 30) -#define CTRL_IDE_IRQA (1 << 28) -#define CTRL_LEGIRQ (1 << 11) -#define CTRL_P1F16 (1 << 5) -#define CTRL_P1EN (1 << 4) -#define CTRL_P0F16 (1 << 1) -#define CTRL_P0EN (1 << 0) - -/* - * Convert a PIO mode and cycle time to the required on/off times - * for the interface. This has protection against runaway timings. - */ -static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio) -{ - struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); - unsigned int cmd_on, cmd_off; - u8 iordy = 0; - - cmd_on = (t->active + 29) / 30; - cmd_off = (ide_pio_cycle_time(drive, pio) - 30 * cmd_on + 29) / 30; - - if (cmd_on == 0) - cmd_on = 1; - - if (cmd_off == 0) - cmd_off = 1; - - if (ide_pio_need_iordy(drive, pio)) - iordy = 0x40; - - return (cmd_on - 1) << 8 | (cmd_off - 1) | iordy; -} - -/* - * Configure the chipset for PIO mode. - */ -static void sl82c105_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long timings = (unsigned long)ide_get_drivedata(drive); - int reg = 0x44 + drive->dn * 4; - u16 drv_ctrl; - const u8 pio = drive->pio_mode - XFER_PIO_0; - - drv_ctrl = get_pio_timings(drive, pio); - - /* - * Store the PIO timings so that we can restore them - * in case DMA will be turned off... - */ - timings &= 0xffff0000; - timings |= drv_ctrl; - ide_set_drivedata(drive, (void *)timings); - - pci_write_config_word(dev, reg, drv_ctrl); - pci_read_config_word (dev, reg, &drv_ctrl); - - printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name, - ide_xfer_verbose(pio + XFER_PIO_0), - ide_pio_cycle_time(drive, pio), drv_ctrl); -} - -/* - * Configure the chipset for DMA mode. - */ -static void sl82c105_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - static u16 mwdma_timings[] = {0x0707, 0x0201, 0x0200}; - unsigned long timings = (unsigned long)ide_get_drivedata(drive); - u16 drv_ctrl; - const u8 speed = drive->dma_mode; - - drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0]; - - /* - * Store the DMA timings so that we can actually program - * them when DMA will be turned on... - */ - timings &= 0x0000ffff; - timings |= (unsigned long)drv_ctrl << 16; - ide_set_drivedata(drive, (void *)timings); -} - -static int sl82c105_test_irq(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA; - - pci_read_config_dword(dev, 0x40, &val); - - return (val & mask) ? 1 : 0; -} - -/* - * The SL82C105 holds off all IDE interrupts while in DMA mode until - * all DMA activity is completed. Sometimes this causes problems (eg, - * when the drive wants to report an error condition). - * - * 0x7e is a "chip testing" register. Bit 2 resets the DMA controller - * state machine. We need to kick this to work around various bugs. - */ -static inline void sl82c105_reset_host(struct pci_dev *dev) -{ - u16 val; - - pci_read_config_word(dev, 0x7e, &val); - pci_write_config_word(dev, 0x7e, val | (1 << 2)); - pci_write_config_word(dev, 0x7e, val & ~(1 << 2)); -} - -/* - * If we get an IRQ timeout, it might be that the DMA state machine - * got confused. Fix from Todd Inglett. Details from Winbond. - * - * This function is called when the IDE timer expires, the drive - * indicates that it is READY, and we were waiting for DMA to complete. - */ -static void sl82c105_dma_lost_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA; - u8 dma_cmd; - - printk(KERN_WARNING "sl82c105: lost IRQ, resetting host\n"); - - /* - * Check the raw interrupt from the drive. - */ - pci_read_config_dword(dev, 0x40, &val); - if (val & mask) - printk(KERN_INFO "sl82c105: drive was requesting IRQ, " - "but host lost it\n"); - - /* - * Was DMA enabled? If so, disable it - we're resetting the - * host. The IDE layer will be handling the drive for us. - */ - dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); - if (dma_cmd & 1) { - outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD); - printk(KERN_INFO "sl82c105: DMA was enabled\n"); - } - - sl82c105_reset_host(dev); -} - -/* - * ATAPI devices can cause the SL82C105 DMA state machine to go gaga. - * Winbond recommend that the DMA state machine is reset prior to - * setting the bus master DMA enable bit. - * - * The generic IDE core will have disabled the BMEN bit before this - * function is called. - */ -static void sl82c105_dma_start(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - int reg = 0x44 + drive->dn * 4; - - pci_write_config_word(dev, reg, - (unsigned long)ide_get_drivedata(drive) >> 16); - - sl82c105_reset_host(dev); - ide_dma_start(drive); -} - -static void sl82c105_dma_clear(ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(drive->hwif->dev); - - sl82c105_reset_host(dev); -} - -static int sl82c105_dma_end(ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(drive->hwif->dev); - int reg = 0x44 + drive->dn * 4; - int ret = ide_dma_end(drive); - - pci_write_config_word(dev, reg, - (unsigned long)ide_get_drivedata(drive)); - - return ret; -} - -/* - * ATA reset will clear the 16 bits mode in the control - * register, we need to reprogram it - */ -static void sl82c105_resetproc(ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(drive->hwif->dev); - u32 val; - - pci_read_config_dword(dev, 0x40, &val); - val |= (CTRL_P1F16 | CTRL_P0F16); - pci_write_config_dword(dev, 0x40, val); -} - -/* - * Return the revision of the Winbond bridge - * which this function is part of. - */ -static u8 sl82c105_bridge_revision(struct pci_dev *dev) -{ - struct pci_dev *bridge; - - /* - * The bridge should be part of the same device, but function 0. - */ - bridge = pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus), - dev->bus->number, - PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); - if (!bridge) - return -1; - - /* - * Make sure it is a Winbond 553 and is an ISA bridge. - */ - if (bridge->vendor != PCI_VENDOR_ID_WINBOND || - bridge->device != PCI_DEVICE_ID_WINBOND_83C553 || - bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA) { - pci_dev_put(bridge); - return -1; - } - /* - * We need to find function 0's revision, not function 1 - */ - pci_dev_put(bridge); - - return bridge->revision; -} - -/* - * Enable the PCI device - * - * --BenH: It's arch fixup code that should enable channels that - * have not been enabled by firmware. I decided we can still enable - * channel 0 here at least, but channel 1 has to be enabled by - * firmware or arch code. We still set both to 16 bits mode. - */ -static int init_chipset_sl82c105(struct pci_dev *dev) -{ - u32 val; - - pci_read_config_dword(dev, 0x40, &val); - val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16; - pci_write_config_dword(dev, 0x40, val); - - return 0; -} - -static const struct ide_port_ops sl82c105_port_ops = { - .set_pio_mode = sl82c105_set_pio_mode, - .set_dma_mode = sl82c105_set_dma_mode, - .resetproc = sl82c105_resetproc, - .test_irq = sl82c105_test_irq, -}; - -static const struct ide_dma_ops sl82c105_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = sl82c105_dma_start, - .dma_end = sl82c105_dma_end, - .dma_test_irq = ide_dma_test_irq, - .dma_lost_irq = sl82c105_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_clear = sl82c105_dma_clear, - .dma_sff_read_status = ide_dma_sff_read_status, -}; - -static const struct ide_port_info sl82c105_chipset = { - .name = DRV_NAME, - .init_chipset = init_chipset_sl82c105, - .enablebits = {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, - .port_ops = &sl82c105_port_ops, - .dma_ops = &sl82c105_dma_ops, - .host_flags = IDE_HFLAG_IO_32BIT | - IDE_HFLAG_UNMASK_IRQS | - IDE_HFLAG_SERIALIZE_DMA | - IDE_HFLAG_NO_AUTODMA, - .pio_mask = ATA_PIO5, - .mwdma_mask = ATA_MWDMA2, -}; - -static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct ide_port_info d = sl82c105_chipset; - u8 rev = sl82c105_bridge_revision(dev); - - if (rev <= 5) { - /* - * Never ever EVER under any circumstances enable - * DMA when the bridge is this old. - */ - printk(KERN_INFO DRV_NAME ": Winbond W83C553 bridge " - "revision %d, BM-DMA disabled\n", rev); - d.dma_ops = NULL; - d.mwdma_mask = 0; - d.host_flags &= ~IDE_HFLAG_SERIALIZE_DMA; - } - - return ide_pci_init_one(dev, &d, NULL); -} - -static const struct pci_device_id sl82c105_pci_tbl[] = { - { PCI_VDEVICE(WINBOND, PCI_DEVICE_ID_WINBOND_82C105), 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl); - -static struct pci_driver sl82c105_pci_driver = { - .name = "W82C105_IDE", - .id_table = sl82c105_pci_tbl, - .probe = sl82c105_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init sl82c105_ide_init(void) -{ - return ide_pci_register_driver(&sl82c105_pci_driver); -} - -static void __exit sl82c105_ide_exit(void) -{ - pci_unregister_driver(&sl82c105_pci_driver); -} - -module_init(sl82c105_ide_init); -module_exit(sl82c105_ide_exit); - -MODULE_DESCRIPTION("PCI driver module for W82C105 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/slc90e66.c b/drivers/ide/slc90e66.c deleted file mode 100644 index f521d5ebf916..000000000000 --- a/drivers/ide/slc90e66.c +++ /dev/null @@ -1,182 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2000-2002 Andre Hedrick - * Copyright (C) 2006-2007 MontaVista Software, Inc. - * - * This is a look-alike variation of the ICH0 PIIX4 Ultra-66, - * but this keeps the ISA-Bridge and slots alive. - * - */ - -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "slc90e66" - -static DEFINE_SPINLOCK(slc90e66_lock); - -static void slc90e66_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - int is_slave = drive->dn & 1; - int master_port = hwif->channel ? 0x42 : 0x40; - int slave_port = 0x44; - unsigned long flags; - u16 master_data; - u8 slave_data; - int control = 0; - const u8 pio = drive->pio_mode - XFER_PIO_0; - - /* ISP RTC */ - static const u8 timings[][2] = { - { 0, 0 }, - { 0, 0 }, - { 1, 0 }, - { 2, 1 }, - { 2, 3 }, }; - - spin_lock_irqsave(&slc90e66_lock, flags); - pci_read_config_word(dev, master_port, &master_data); - - if (pio > 1) - control |= 1; /* Programmable timing on */ - if (drive->media == ide_disk) - control |= 4; /* Prefetch, post write */ - if (ide_pio_need_iordy(drive, pio)) - control |= 2; /* IORDY */ - if (is_slave) { - master_data |= 0x4000; - master_data &= ~0x0070; - if (pio > 1) { - /* Set PPE, IE and TIME */ - master_data |= control << 4; - } - pci_read_config_byte(dev, slave_port, &slave_data); - slave_data &= hwif->channel ? 0x0f : 0xf0; - slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << - (hwif->channel ? 4 : 0); - } else { - master_data &= ~0x3307; - if (pio > 1) { - /* enable PPE, IE and TIME */ - master_data |= control; - } - master_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8); - } - pci_write_config_word(dev, master_port, master_data); - if (is_slave) - pci_write_config_byte(dev, slave_port, slave_data); - spin_unlock_irqrestore(&slc90e66_lock, flags); -} - -static void slc90e66_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 maslave = hwif->channel ? 0x42 : 0x40; - int sitre = 0, a_speed = 7 << (drive->dn * 4); - int u_speed = 0, u_flag = 1 << drive->dn; - u16 reg4042, reg44, reg48, reg4a; - const u8 speed = drive->dma_mode; - - pci_read_config_word(dev, maslave, ®4042); - sitre = (reg4042 & 0x4000) ? 1 : 0; - pci_read_config_word(dev, 0x44, ®44); - pci_read_config_word(dev, 0x48, ®48); - pci_read_config_word(dev, 0x4a, ®4a); - - if (speed >= XFER_UDMA_0) { - u_speed = (speed - XFER_UDMA_0) << (drive->dn * 4); - - if (!(reg48 & u_flag)) - pci_write_config_word(dev, 0x48, reg48|u_flag); - if ((reg4a & a_speed) != u_speed) { - pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - pci_read_config_word(dev, 0x4a, ®4a); - pci_write_config_word(dev, 0x4a, reg4a|u_speed); - } - } else { - const u8 mwdma_to_pio[] = { 0, 3, 4 }; - - if (reg48 & u_flag) - pci_write_config_word(dev, 0x48, reg48 & ~u_flag); - if (reg4a & a_speed) - pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - - if (speed >= XFER_MW_DMA_0) - drive->pio_mode = - mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0; - else - drive->pio_mode = XFER_PIO_2; /* for SWDMA2 */ - - slc90e66_set_pio_mode(hwif, drive); - } -} - -static u8 slc90e66_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 reg47 = 0, mask = hwif->channel ? 0x01 : 0x02; - - pci_read_config_byte(dev, 0x47, ®47); - - /* bit[0(1)]: 0:80, 1:40 */ - return (reg47 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; -} - -static const struct ide_port_ops slc90e66_port_ops = { - .set_pio_mode = slc90e66_set_pio_mode, - .set_dma_mode = slc90e66_set_dma_mode, - .cable_detect = slc90e66_cable_detect, -}; - -static const struct ide_port_info slc90e66_chipset = { - .name = DRV_NAME, - .enablebits = { {0x41, 0x80, 0x80}, {0x43, 0x80, 0x80} }, - .port_ops = &slc90e66_port_ops, - .pio_mask = ATA_PIO4, - .swdma_mask = ATA_SWDMA2_ONLY, - .mwdma_mask = ATA_MWDMA12_ONLY, - .udma_mask = ATA_UDMA4, -}; - -static int slc90e66_init_one(struct pci_dev *dev, - const struct pci_device_id *id) -{ - return ide_pci_init_one(dev, &slc90e66_chipset, NULL); -} - -static const struct pci_device_id slc90e66_pci_tbl[] = { - { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1), 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl); - -static struct pci_driver slc90e66_pci_driver = { - .name = "SLC90e66_IDE", - .id_table = slc90e66_pci_tbl, - .probe = slc90e66_init_one, - .remove = ide_pci_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init slc90e66_ide_init(void) -{ - return ide_pci_register_driver(&slc90e66_pci_driver); -} - -static void __exit slc90e66_ide_exit(void) -{ - pci_unregister_driver(&slc90e66_pci_driver); -} - -module_init(slc90e66_ide_init); -module_exit(slc90e66_ide_exit); - -MODULE_AUTHOR("Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for SLC90E66 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/tc86c001.c b/drivers/ide/tc86c001.c deleted file mode 100644 index 17e6132b99bf..000000000000 --- a/drivers/ide/tc86c001.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (C) 2002 Toshiba Corporation - * Copyright (C) 2005-2006 MontaVista Software, Inc. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include -#include -#include -#include - -#define DRV_NAME "tc86c001" - -static void tc86c001_set_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00); - u16 mode, scr = inw(scr_port); - const u8 speed = drive->dma_mode; - - switch (speed) { - case XFER_UDMA_4: mode = 0x00c0; break; - case XFER_UDMA_3: mode = 0x00b0; break; - case XFER_UDMA_2: mode = 0x00a0; break; - case XFER_UDMA_1: mode = 0x0090; break; - case XFER_UDMA_0: mode = 0x0080; break; - case XFER_MW_DMA_2: mode = 0x0070; break; - case XFER_MW_DMA_1: mode = 0x0060; break; - case XFER_MW_DMA_0: mode = 0x0050; break; - case XFER_PIO_4: mode = 0x0400; break; - case XFER_PIO_3: mode = 0x0300; break; - case XFER_PIO_2: mode = 0x0200; break; - case XFER_PIO_1: mode = 0x0100; break; - case XFER_PIO_0: - default: mode = 0x0000; break; - } - - scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f; - scr |= mode; - outw(scr, scr_port); -} - -static void tc86c001_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - drive->dma_mode = drive->pio_mode; - tc86c001_set_mode(hwif, drive); -} - -/* - * HACKITY HACK - * - * This is a workaround for the limitation 5 of the TC86C001 IDE controller: - * if a DMA transfer terminates prematurely, the controller leaves the device's - * interrupt request (INTRQ) pending and does not generate a PCI interrupt (or - * set the interrupt bit in the DMA status register), thus no PCI interrupt - * will occur until a DMA transfer has been successfully completed. - * - * We work around this by initiating dummy, zero-length DMA transfer on - * a DMA timeout expiration. I found no better way to do this with the current - * IDE core than to temporarily replace a higher level driver's timer expiry - * handler with our own backing up to that handler in case our recovery fails. - */ -static int tc86c001_timer_expiry(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - ide_expiry_t *expiry = ide_get_hwifdata(hwif); - u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); - - /* Restore a higher level driver's expiry handler first. */ - hwif->expiry = expiry; - - if ((dma_stat & 5) == 1) { /* DMA active and no interrupt */ - unsigned long sc_base = hwif->config_data; - unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04); - u8 dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); - - printk(KERN_WARNING "%s: DMA interrupt possibly stuck, " - "attempting recovery...\n", drive->name); - - /* Stop DMA */ - outb(dma_cmd & ~0x01, hwif->dma_base + ATA_DMA_CMD); - - /* Setup the dummy DMA transfer */ - outw(0, sc_base + 0x0a); /* Sector Count */ - outw(0, twcr_port); /* Transfer Word Count 1 or 2 */ - - /* Start the dummy DMA transfer */ - - /* clear R_OR_WCTR for write */ - outb(0x00, hwif->dma_base + ATA_DMA_CMD); - /* set START_STOPBM */ - outb(0x01, hwif->dma_base + ATA_DMA_CMD); - - /* - * If an interrupt was pending, it should come thru shortly. - * If not, a higher level driver's expiry handler should - * eventually cause some kind of recovery from the DMA stall. - */ - return WAIT_MIN_SLEEP; - } - - /* Chain to the restored expiry handler if DMA wasn't active. */ - if (likely(expiry != NULL)) - return expiry(drive); - - /* If there was no handler, "emulate" that for ide_timer_expiry()... */ - return -1; -} - -static void tc86c001_dma_start(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - unsigned long sc_base = hwif->config_data; - unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04); - unsigned long nsectors = blk_rq_sectors(hwif->rq); - - /* - * We have to manually load the sector count and size into - * the appropriate system control registers for DMA to work - * with LBA48 and ATAPI devices... - */ - outw(nsectors, sc_base + 0x0a); /* Sector Count */ - outw(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */ - - /* Install our timeout expiry hook, saving the current handler... */ - ide_set_hwifdata(hwif, hwif->expiry); - hwif->expiry = &tc86c001_timer_expiry; - - ide_dma_start(drive); -} - -static u8 tc86c001_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long sc_base = pci_resource_start(dev, 5); - u16 scr1 = inw(sc_base + 0x00); - - /* - * System Control 1 Register bit 13 (PDIAGN): - * 0=80-pin cable, 1=40-pin cable - */ - return (scr1 & 0x2000) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; -} - -static void init_hwif_tc86c001(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long sc_base = pci_resource_start(dev, 5); - u16 scr1 = inw(sc_base + 0x00); - - /* System Control 1 Register bit 15 (Soft Reset) set */ - outw(scr1 | 0x8000, sc_base + 0x00); - - /* System Control 1 Register bit 14 (FIFO Reset) set */ - outw(scr1 | 0x4000, sc_base + 0x00); - - /* System Control 1 Register: reset clear */ - outw(scr1 & ~0xc000, sc_base + 0x00); - - /* Store the system control register base for convenience... */ - hwif->config_data = sc_base; - - if (!hwif->dma_base) - return; - - /* - * Sector Count Control Register bits 0 and 1 set: - * software sets Sector Count Register for master and slave device - */ - outw(0x0003, sc_base + 0x0c); - - /* Sector Count Register limit */ - hwif->rqsize = 0xffff; -} - -static const struct ide_port_ops tc86c001_port_ops = { - .set_pio_mode = tc86c001_set_pio_mode, - .set_dma_mode = tc86c001_set_mode, - .cable_detect = tc86c001_cable_detect, -}; - -static const struct ide_dma_ops tc86c001_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = tc86c001_dma_start, - .dma_end = ide_dma_end, - .dma_test_irq = ide_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = ide_dma_sff_read_status, -}; - -static const struct ide_port_info tc86c001_chipset = { - .name = DRV_NAME, - .init_hwif = init_hwif_tc86c001, - .port_ops = &tc86c001_port_ops, - .dma_ops = &tc86c001_dma_ops, - .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA4, -}; - -static int tc86c001_init_one(struct pci_dev *dev, - const struct pci_device_id *id) -{ - int rc; - - rc = pci_enable_device(dev); - if (rc) - goto out; - - rc = pci_request_region(dev, 5, DRV_NAME); - if (rc) { - printk(KERN_ERR DRV_NAME ": system control regs already in use"); - goto out_disable; - } - - rc = ide_pci_init_one(dev, &tc86c001_chipset, NULL); - if (rc) - goto out_release; - - goto out; - -out_release: - pci_release_region(dev, 5); -out_disable: - pci_disable_device(dev); -out: - return rc; -} - -static void tc86c001_remove(struct pci_dev *dev) -{ - ide_pci_remove(dev); - pci_release_region(dev, 5); - pci_disable_device(dev); -} - -static const struct pci_device_id tc86c001_pci_tbl[] = { - { PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE), 0 }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl); - -static struct pci_driver tc86c001_pci_driver = { - .name = "TC86C001", - .id_table = tc86c001_pci_tbl, - .probe = tc86c001_init_one, - .remove = tc86c001_remove, -}; - -static int __init tc86c001_ide_init(void) -{ - return ide_pci_register_driver(&tc86c001_pci_driver); -} - -static void __exit tc86c001_ide_exit(void) -{ - pci_unregister_driver(&tc86c001_pci_driver); -} - -module_init(tc86c001_ide_init); -module_exit(tc86c001_ide_exit); - -MODULE_AUTHOR("MontaVista Software, Inc. "); -MODULE_DESCRIPTION("PCI driver module for TC86C001 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/triflex.c b/drivers/ide/triflex.c deleted file mode 100644 index 16ddd0956832..000000000000 --- a/drivers/ide/triflex.c +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * IDE Chipset driver for the Compaq TriFlex IDE controller. - * - * Known to work with the Compaq Workstation 5x00 series. - * - * Copyright (C) 2002 Hewlett-Packard Development Group, L.P. - * Author: Torben Mathiasen - * - * Loosely based on the piix & svwks drivers. - * - * Documentation: - * Not publicly available. - */ - -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "triflex" - -static void triflex_set_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - u32 triflex_timings = 0; - u16 timing = 0; - u8 channel_offset = hwif->channel ? 0x74 : 0x70, unit = drive->dn & 1; - - pci_read_config_dword(dev, channel_offset, &triflex_timings); - - switch (drive->dma_mode) { - case XFER_MW_DMA_2: - timing = 0x0103; - break; - case XFER_MW_DMA_1: - timing = 0x0203; - break; - case XFER_MW_DMA_0: - timing = 0x0808; - break; - case XFER_SW_DMA_2: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - timing = 0x0f0f; - break; - case XFER_PIO_4: - timing = 0x0202; - break; - case XFER_PIO_3: - timing = 0x0204; - break; - case XFER_PIO_2: - timing = 0x0404; - break; - case XFER_PIO_1: - timing = 0x0508; - break; - case XFER_PIO_0: - timing = 0x0808; - break; - } - - triflex_timings &= ~(0xFFFF << (16 * unit)); - triflex_timings |= (timing << (16 * unit)); - - pci_write_config_dword(dev, channel_offset, triflex_timings); -} - -static void triflex_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - drive->dma_mode = drive->pio_mode; - triflex_set_mode(hwif, drive); -} - -static const struct ide_port_ops triflex_port_ops = { - .set_pio_mode = triflex_set_pio_mode, - .set_dma_mode = triflex_set_mode, -}; - -static const struct ide_port_info triflex_device = { - .name = DRV_NAME, - .enablebits = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}}, - .port_ops = &triflex_port_ops, - .pio_mask = ATA_PIO4, - .swdma_mask = ATA_SWDMA2, - .mwdma_mask = ATA_MWDMA2, -}; - -static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_pci_init_one(dev, &triflex_device, NULL); -} - -static const struct pci_device_id triflex_pci_tbl[] = { - { PCI_VDEVICE(COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE), 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, triflex_pci_tbl); - -#ifdef CONFIG_PM -static int triflex_ide_pci_suspend(struct pci_dev *dev, pm_message_t state) -{ - /* - * We must not disable or powerdown the device. - * APM bios refuses to suspend if IDE is not accessible. - */ - pci_save_state(dev); - return 0; -} -#else -#define triflex_ide_pci_suspend NULL -#endif - -static struct pci_driver triflex_pci_driver = { - .name = "TRIFLEX_IDE", - .id_table = triflex_pci_tbl, - .probe = triflex_init_one, - .remove = ide_pci_remove, - .suspend = triflex_ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init triflex_ide_init(void) -{ - return ide_pci_register_driver(&triflex_pci_driver); -} - -static void __exit triflex_ide_exit(void) -{ - pci_unregister_driver(&triflex_pci_driver); -} - -module_init(triflex_ide_init); -module_exit(triflex_ide_exit); - -MODULE_AUTHOR("Torben Mathiasen"); -MODULE_DESCRIPTION("PCI driver module for Compaq Triflex IDE"); -MODULE_LICENSE("GPL"); - - diff --git a/drivers/ide/trm290.c b/drivers/ide/trm290.c deleted file mode 100644 index d550b379b0f1..000000000000 --- a/drivers/ide/trm290.c +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (c) 1997-1998 Mark Lord - * Copyright (c) 2007 MontaVista Software, Inc. - * - * May be copied or modified under the terms of the GNU General Public License - * - * June 22, 2004 - get rid of check_region - * - Jesper Juhl - * - */ - -/* - * This module provides support for the bus-master IDE DMA function - * of the Tekram TRM290 chip, used on a variety of PCI IDE add-on boards, - * including a "Precision Instruments" board. The TRM290 pre-dates - * the sff-8038 standard (ide-dma.c) by a few months, and differs - * significantly enough to warrant separate routines for some functions, - * while re-using others from ide-dma.c. - * - * EXPERIMENTAL! It works for me (a sample of one). - * - * Works reliably for me in DMA mode (READs only), - * DMA WRITEs are disabled by default (see #define below); - * - * DMA is not enabled automatically for this chipset, - * but can be turned on manually (with "hdparm -d1") at run time. - * - * I need volunteers with "spare" drives for further testing - * and development, and maybe to help figure out the peculiarities. - * Even knowing the registers (below), some things behave strangely. - */ - -#define TRM290_NO_DMA_WRITES /* DMA writes seem unreliable sometimes */ - -/* - * TRM-290 PCI-IDE2 Bus Master Chip - * ================================ - * The configuration registers are addressed in normal I/O port space - * and are used as follows: - * - * trm290_base depends on jumper settings, and is probed for by ide-dma.c - * - * trm290_base+2 when WRITTEN: chiptest register (byte, write-only) - * bit7 must always be written as "1" - * bits6-2 undefined - * bit1 1=legacy_compatible_mode, 0=native_pci_mode - * bit0 1=test_mode, 0=normal(default) - * - * trm290_base+2 when READ: status register (byte, read-only) - * bits7-2 undefined - * bit1 channel0 busmaster interrupt status 0=none, 1=asserted - * bit0 channel0 interrupt status 0=none, 1=asserted - * - * trm290_base+3 Interrupt mask register - * bits7-5 undefined - * bit4 legacy_header: 1=present, 0=absent - * bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only) - * bit2 channel1 interrupt status 0=none, 1=asserted (read only) - * bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default) - * bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default) - * - * trm290_base+1 "CPR" Config Pointer Register (byte) - * bit7 1=autoincrement CPR bits 2-0 after each access of CDR - * bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state - * bit5 0=enabled master burst access (default), 1=disable (write only) - * bit4 PCI DEVSEL# timing select: 1=medium(default), 0=fast - * bit3 0=primary IDE channel, 1=secondary IDE channel - * bits2-0 register index for accesses through CDR port - * - * trm290_base+0 "CDR" Config Data Register (word) - * two sets of seven config registers, - * selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6), - * each index defined below: - * - * Index-0 Base address register for command block (word) - * defaults: 0x1f0 for primary, 0x170 for secondary - * - * Index-1 general config register (byte) - * bit7 1=DMA enable, 0=DMA disable - * bit6 1=activate IDE_RESET, 0=no action (default) - * bit5 1=enable IORDY, 0=disable IORDY (default) - * bit4 0=16-bit data port(default), 1=8-bit (XT) data port - * bit3 interrupt polarity: 1=active_low, 0=active_high(default) - * bit2 power-saving-mode(?): 1=enable, 0=disable(default) (write only) - * bit1 bus_master_mode(?): 1=enable, 0=disable(default) - * bit0 enable_io_ports: 1=enable(default), 0=disable - * - * Index-2 read-ahead counter preload bits 0-7 (byte, write only) - * bits7-0 bits7-0 of readahead count - * - * Index-3 read-ahead config register (byte, write only) - * bit7 1=enable_readahead, 0=disable_readahead(default) - * bit6 1=clear_FIFO, 0=no_action - * bit5 undefined - * bit4 mode4 timing control: 1=enable, 0=disable(default) - * bit3 undefined - * bit2 undefined - * bits1-0 bits9-8 of read-ahead count - * - * Index-4 base address register for control block (word) - * defaults: 0x3f6 for primary, 0x376 for secondary - * - * Index-5 data port timings (shared by both drives) (byte) - * standard PCI "clk" (clock) counts, default value = 0xf5 - * - * bits7-6 setup time: 00=1clk, 01=2clk, 10=3clk, 11=4clk - * bits5-3 hold time: 000=1clk, 001=2clk, 010=3clk, - * 011=4clk, 100=5clk, 101=6clk, - * 110=8clk, 111=12clk - * bits2-0 active time: 000=2clk, 001=3clk, 010=4clk, - * 011=5clk, 100=6clk, 101=8clk, - * 110=12clk, 111=16clk - * - * Index-6 command/control port timings (shared by both drives) (byte) - * same layout as Index-5, default value = 0xde - * - * Suggested CDR programming for PIO mode0 (600ns): - * 0x01f0,0x21,0xff,0x80,0x03f6,0xf5,0xde ; primary - * 0x0170,0x21,0xff,0x80,0x0376,0xf5,0xde ; secondary - * - * Suggested CDR programming for PIO mode3 (180ns): - * 0x01f0,0x21,0xff,0x80,0x03f6,0x09,0xde ; primary - * 0x0170,0x21,0xff,0x80,0x0376,0x09,0xde ; secondary - * - * Suggested CDR programming for PIO mode4 (120ns): - * 0x01f0,0x21,0xff,0x80,0x03f6,0x00,0xde ; primary - * 0x0170,0x21,0xff,0x80,0x0376,0x00,0xde ; secondary - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "trm290" - -static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma) -{ - ide_hwif_t *hwif = drive->hwif; - u16 reg = 0; - unsigned long flags; - - /* select PIO or DMA */ - reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82); - - local_irq_save(flags); - - if (reg != hwif->select_data) { - hwif->select_data = reg; - /* set PIO/DMA */ - outb(0x51 | (hwif->channel << 3), hwif->config_data + 1); - outw(reg & 0xff, hwif->config_data); - } - - /* enable IRQ if not probing */ - if (drive->dev_flags & IDE_DFLAG_PRESENT) { - reg = inw(hwif->config_data + 3); - reg &= 0x13; - reg &= ~(1 << hwif->channel); - outw(reg, hwif->config_data + 3); - } - - local_irq_restore(flags); -} - -static void trm290_dev_select(ide_drive_t *drive) -{ - trm290_prepare_drive(drive, !!(drive->dev_flags & IDE_DFLAG_USING_DMA)); - - outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr); -} - -static int trm290_dma_check(ide_drive_t *drive, struct ide_cmd *cmd) -{ - if (cmd->tf_flags & IDE_TFLAG_WRITE) { -#ifdef TRM290_NO_DMA_WRITES - /* always use PIO for writes */ - return 1; -#endif - } - return 0; -} - -static int trm290_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) -{ - ide_hwif_t *hwif = drive->hwif; - unsigned int count, rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 1 : 2; - - count = ide_build_dmatable(drive, cmd); - if (count == 0) - /* try PIO instead of DMA */ - return 1; - - outl(hwif->dmatable_dma | rw, hwif->dma_base); - /* start DMA */ - outw(count * 2 - 1, hwif->dma_base + 2); - - return 0; -} - -static void trm290_dma_start(ide_drive_t *drive) -{ - trm290_prepare_drive(drive, 1); -} - -static int trm290_dma_end(ide_drive_t *drive) -{ - u16 status = inw(drive->hwif->dma_base + 2); - - trm290_prepare_drive(drive, 0); - - return status != 0x00ff; -} - -static int trm290_dma_test_irq(ide_drive_t *drive) -{ - u16 status = inw(drive->hwif->dma_base + 2); - - return status == 0x00ff; -} - -static void trm290_dma_host_set(ide_drive_t *drive, int on) -{ -} - -static void init_hwif_trm290(ide_hwif_t *hwif) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned int cfg_base = pci_resource_start(dev, 4); - unsigned long flags; - u8 reg = 0; - - if ((dev->class & 5) && cfg_base) - printk(KERN_INFO DRV_NAME " %s: chip", pci_name(dev)); - else { - cfg_base = 0x3df0; - printk(KERN_INFO DRV_NAME " %s: using default", pci_name(dev)); - } - printk(KERN_CONT " config base at 0x%04x\n", cfg_base); - hwif->config_data = cfg_base; - hwif->dma_base = (cfg_base + 4) ^ (hwif->channel ? 0x80 : 0); - - printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n", - hwif->name, hwif->dma_base, hwif->dma_base + 3); - - if (ide_allocate_dma_engine(hwif)) - return; - - local_irq_save(flags); - /* put config reg into first byte of hwif->select_data */ - outb(0x51 | (hwif->channel << 3), hwif->config_data + 1); - /* select PIO as default */ - hwif->select_data = 0x21; - outb(hwif->select_data, hwif->config_data); - /* get IRQ info */ - reg = inb(hwif->config_data + 3); - /* mask IRQs for both ports */ - reg = (reg & 0x10) | 0x03; - outb(reg, hwif->config_data + 3); - local_irq_restore(flags); - - if (reg & 0x10) - /* legacy mode */ - hwif->irq = hwif->channel ? 15 : 14; - -#if 1 - { - /* - * My trm290-based card doesn't seem to work with all possible values - * for the control basereg, so this kludge ensures that we use only - * values that are known to work. Ugh. -ml - */ - u16 new, old, compat = hwif->channel ? 0x374 : 0x3f4; - static u16 next_offset = 0; - u8 old_mask; - - outb(0x54 | (hwif->channel << 3), hwif->config_data + 1); - old = inw(hwif->config_data); - old &= ~1; - old_mask = inb(old + 2); - if (old != compat && old_mask == 0xff) { - /* leave lower 10 bits untouched */ - compat += (next_offset += 0x400); - hwif->io_ports.ctl_addr = compat + 2; - outw(compat | 1, hwif->config_data); - new = inw(hwif->config_data); - printk(KERN_INFO "%s: control basereg workaround: " - "old=0x%04x, new=0x%04x\n", - hwif->name, old, new & ~1); - } - } -#endif -} - -static const struct ide_tp_ops trm290_tp_ops = { - .exec_command = ide_exec_command, - .read_status = ide_read_status, - .read_altstatus = ide_read_altstatus, - .write_devctl = ide_write_devctl, - - .dev_select = trm290_dev_select, - .tf_load = ide_tf_load, - .tf_read = ide_tf_read, - - .input_data = ide_input_data, - .output_data = ide_output_data, -}; - -static const struct ide_dma_ops trm290_dma_ops = { - .dma_host_set = trm290_dma_host_set, - .dma_setup = trm290_dma_setup, - .dma_start = trm290_dma_start, - .dma_end = trm290_dma_end, - .dma_test_irq = trm290_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_check = trm290_dma_check, -}; - -static const struct ide_port_info trm290_chipset = { - .name = DRV_NAME, - .init_hwif = init_hwif_trm290, - .tp_ops = &trm290_tp_ops, - .dma_ops = &trm290_dma_ops, - .host_flags = IDE_HFLAG_TRM290 | - IDE_HFLAG_NO_ATAPI_DMA | -#if 0 /* play it safe for now */ - IDE_HFLAG_TRUST_BIOS_FOR_DMA | -#endif - IDE_HFLAG_NO_AUTODMA | - IDE_HFLAG_NO_LBA48, -}; - -static int trm290_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_pci_init_one(dev, &trm290_chipset, NULL); -} - -static const struct pci_device_id trm290_pci_tbl[] = { - { PCI_VDEVICE(TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290), 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, trm290_pci_tbl); - -static struct pci_driver trm290_pci_driver = { - .name = "TRM290_IDE", - .id_table = trm290_pci_tbl, - .probe = trm290_init_one, - .remove = ide_pci_remove, -}; - -static int __init trm290_ide_init(void) -{ - return ide_pci_register_driver(&trm290_pci_driver); -} - -static void __exit trm290_ide_exit(void) -{ - pci_unregister_driver(&trm290_pci_driver); -} - -module_init(trm290_ide_init); -module_exit(trm290_ide_exit); - -MODULE_AUTHOR("Mark Lord"); -MODULE_DESCRIPTION("PCI driver module for Tekram TRM290 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/tx4938ide.c b/drivers/ide/tx4938ide.c deleted file mode 100644 index 962eb92501b5..000000000000 --- a/drivers/ide/tx4938ide.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * TX4938 internal IDE driver - * Based on tx4939ide.c. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * (C) Copyright TOSHIBA CORPORATION 2005-2007 - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -static void tx4938ide_tune_ebusc(unsigned int ebus_ch, - unsigned int gbus_clock, - u8 pio) -{ - struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); - u64 cr = __raw_readq(&tx4938_ebuscptr->cr[ebus_ch]); - unsigned int sp = (cr >> 4) & 3; - unsigned int clock = gbus_clock / (4 - sp); - unsigned int cycle = 1000000000 / clock; - unsigned int shwt; - int wt; - - /* Minimum DIOx- active time */ - wt = DIV_ROUND_UP(t->act8b, cycle) - 2; - /* IORDY setup time: 35ns */ - wt = max_t(int, wt, DIV_ROUND_UP(35, cycle)); - /* actual wait-cycle is max(wt & ~1, 1) */ - if (wt > 2 && (wt & 1)) - wt++; - wt &= ~1; - /* Address-valid to DIOR/DIOW setup */ - shwt = DIV_ROUND_UP(t->setup, cycle); - - /* -DIOx recovery time (SHWT * 4) and cycle time requirement */ - while ((shwt * 4 + wt + (wt ? 2 : 3)) * cycle < t->cycle) - shwt++; - if (shwt > 7) { - pr_warn("tx4938ide: SHWT violation (%d)\n", shwt); - shwt = 7; - } - pr_debug("tx4938ide: ebus %d, bus cycle %dns, WT %d, SHWT %d\n", - ebus_ch, cycle, wt, shwt); - - __raw_writeq((cr & ~0x3f007ull) | (wt << 12) | shwt, - &tx4938_ebuscptr->cr[ebus_ch]); -} - -static void tx4938ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct tx4938ide_platform_info *pdata = dev_get_platdata(hwif->dev); - u8 safe = drive->pio_mode - XFER_PIO_0; - ide_drive_t *pair; - - pair = ide_get_pair_dev(drive); - if (pair) - safe = min_t(u8, safe, pair->pio_mode - XFER_PIO_0); - tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, safe); -} - -#ifdef __BIG_ENDIAN - -/* custom iops (independent from SWAP_IO_SPACE) */ -static void tx4938ide_input_data_swap(ide_drive_t *drive, struct ide_cmd *cmd, - void *buf, unsigned int len) -{ - unsigned long port = drive->hwif->io_ports.data_addr; - unsigned short *ptr = buf; - unsigned int count = (len + 1) / 2; - - while (count--) - *ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port)); - __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2)); -} - -static void tx4938ide_output_data_swap(ide_drive_t *drive, struct ide_cmd *cmd, - void *buf, unsigned int len) -{ - unsigned long port = drive->hwif->io_ports.data_addr; - unsigned short *ptr = buf; - unsigned int count = (len + 1) / 2; - - while (count--) { - __raw_writew(le16_to_cpu(*ptr), (void __iomem *)port); - ptr++; - } - __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2)); -} - -static const struct ide_tp_ops tx4938ide_tp_ops = { - .exec_command = ide_exec_command, - .read_status = ide_read_status, - .read_altstatus = ide_read_altstatus, - .write_devctl = ide_write_devctl, - - .dev_select = ide_dev_select, - .tf_load = ide_tf_load, - .tf_read = ide_tf_read, - - .input_data = tx4938ide_input_data_swap, - .output_data = tx4938ide_output_data_swap, -}; - -#endif /* __BIG_ENDIAN */ - -static const struct ide_port_ops tx4938ide_port_ops = { - .set_pio_mode = tx4938ide_set_pio_mode, -}; - -static const struct ide_port_info tx4938ide_port_info __initconst = { - .port_ops = &tx4938ide_port_ops, -#ifdef __BIG_ENDIAN - .tp_ops = &tx4938ide_tp_ops, -#endif - .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, - .pio_mask = ATA_PIO5, - .chipset = ide_generic, -}; - -static int __init tx4938ide_probe(struct platform_device *pdev) -{ - struct ide_hw hw, *hws[] = { &hw }; - struct ide_host *host; - struct resource *res; - struct tx4938ide_platform_info *pdata = dev_get_platdata(&pdev->dev); - int irq, ret, i; - unsigned long mapbase, mapctl; - struct ide_port_info d = tx4938ide_port_info; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return -ENODEV; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), "tx4938ide")) - return -EBUSY; - mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start, - 8 << pdata->ioport_shift); - mapctl = (unsigned long)devm_ioremap(&pdev->dev, - res->start + 0x10000 + - (6 << pdata->ioport_shift), - 1 << pdata->ioport_shift); - if (!mapbase || !mapctl) - return -EBUSY; - - memset(&hw, 0, sizeof(hw)); - if (pdata->ioport_shift) { - unsigned long port = mapbase; - unsigned long ctl = mapctl; - - hw.io_ports_array[0] = port; -#ifdef __BIG_ENDIAN - port++; - ctl++; -#endif - for (i = 1; i <= 7; i++) - hw.io_ports_array[i] = - port + (i << pdata->ioport_shift); - hw.io_ports.ctl_addr = ctl; - } else - ide_std_init_ports(&hw, mapbase, mapctl); - hw.irq = irq; - hw.dev = &pdev->dev; - - pr_info("TX4938 IDE interface (base %#lx, ctl %#lx, irq %d)\n", - mapbase, mapctl, hw.irq); - if (pdata->gbus_clock) - tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, 0); - else - d.port_ops = NULL; - ret = ide_host_add(&d, hws, 1, &host); - if (!ret) - platform_set_drvdata(pdev, host); - return ret; -} - -static int __exit tx4938ide_remove(struct platform_device *pdev) -{ - struct ide_host *host = platform_get_drvdata(pdev); - - ide_host_remove(host); - return 0; -} - -static struct platform_driver tx4938ide_driver = { - .driver = { - .name = "tx4938ide", - }, - .remove = __exit_p(tx4938ide_remove), -}; - -module_platform_driver_probe(tx4938ide_driver, tx4938ide_probe); - -MODULE_DESCRIPTION("TX4938 internal IDE driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:tx4938ide"); diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c deleted file mode 100644 index b1bbf807bb3d..000000000000 --- a/drivers/ide/tx4939ide.c +++ /dev/null @@ -1,628 +0,0 @@ -/* - * TX4939 internal IDE driver - * Based on RBTX49xx patch from CELF patch archive. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * (C) Copyright TOSHIBA CORPORATION 2005-2007 - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define MODNAME "tx4939ide" - -/* ATA Shadow Registers (8-bit except for Data which is 16-bit) */ -#define TX4939IDE_Data 0x000 -#define TX4939IDE_Error_Feature 0x001 -#define TX4939IDE_Sec 0x002 -#define TX4939IDE_LBA0 0x003 -#define TX4939IDE_LBA1 0x004 -#define TX4939IDE_LBA2 0x005 -#define TX4939IDE_DevHead 0x006 -#define TX4939IDE_Stat_Cmd 0x007 -#define TX4939IDE_AltStat_DevCtl 0x402 -/* H/W DMA Registers */ -#define TX4939IDE_DMA_Cmd 0x800 /* 8-bit */ -#define TX4939IDE_DMA_Stat 0x802 /* 8-bit */ -#define TX4939IDE_PRD_Ptr 0x804 /* 32-bit */ -/* ATA100 CORE Registers (16-bit) */ -#define TX4939IDE_Sys_Ctl 0xc00 -#define TX4939IDE_Xfer_Cnt_1 0xc08 -#define TX4939IDE_Xfer_Cnt_2 0xc0a -#define TX4939IDE_Sec_Cnt 0xc10 -#define TX4939IDE_Start_Lo_Addr 0xc18 -#define TX4939IDE_Start_Up_Addr 0xc20 -#define TX4939IDE_Add_Ctl 0xc28 -#define TX4939IDE_Lo_Burst_Cnt 0xc30 -#define TX4939IDE_Up_Burst_Cnt 0xc38 -#define TX4939IDE_PIO_Addr 0xc88 -#define TX4939IDE_H_Rst_Tim 0xc90 -#define TX4939IDE_Int_Ctl 0xc98 -#define TX4939IDE_Pkt_Cmd 0xcb8 -#define TX4939IDE_Bxfer_Cnt_Hi 0xcc0 -#define TX4939IDE_Bxfer_Cnt_Lo 0xcc8 -#define TX4939IDE_Dev_TErr 0xcd0 -#define TX4939IDE_Pkt_Xfer_Ctl 0xcd8 -#define TX4939IDE_Start_TAddr 0xce0 - -/* bits for Int_Ctl */ -#define TX4939IDE_INT_ADDRERR 0x80 -#define TX4939IDE_INT_REACHMUL 0x40 -#define TX4939IDE_INT_DEVTIMING 0x20 -#define TX4939IDE_INT_UDMATERM 0x10 -#define TX4939IDE_INT_TIMER 0x08 -#define TX4939IDE_INT_BUSERR 0x04 -#define TX4939IDE_INT_XFEREND 0x02 -#define TX4939IDE_INT_HOST 0x01 - -#define TX4939IDE_IGNORE_INTS \ - (TX4939IDE_INT_ADDRERR | TX4939IDE_INT_REACHMUL | \ - TX4939IDE_INT_DEVTIMING | TX4939IDE_INT_UDMATERM | \ - TX4939IDE_INT_TIMER | TX4939IDE_INT_XFEREND) - -#ifdef __BIG_ENDIAN -#define tx4939ide_swizzlel(a) ((a) ^ 4) -#define tx4939ide_swizzlew(a) ((a) ^ 6) -#define tx4939ide_swizzleb(a) ((a) ^ 7) -#else -#define tx4939ide_swizzlel(a) (a) -#define tx4939ide_swizzlew(a) (a) -#define tx4939ide_swizzleb(a) (a) -#endif - -static u16 tx4939ide_readw(void __iomem *base, u32 reg) -{ - return __raw_readw(base + tx4939ide_swizzlew(reg)); -} -static u8 tx4939ide_readb(void __iomem *base, u32 reg) -{ - return __raw_readb(base + tx4939ide_swizzleb(reg)); -} -static void tx4939ide_writel(u32 val, void __iomem *base, u32 reg) -{ - __raw_writel(val, base + tx4939ide_swizzlel(reg)); -} -static void tx4939ide_writew(u16 val, void __iomem *base, u32 reg) -{ - __raw_writew(val, base + tx4939ide_swizzlew(reg)); -} -static void tx4939ide_writeb(u8 val, void __iomem *base, u32 reg) -{ - __raw_writeb(val, base + tx4939ide_swizzleb(reg)); -} - -#define TX4939IDE_BASE(hwif) ((void __iomem *)(hwif)->extra_base) - -static void tx4939ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - int is_slave = drive->dn; - u32 mask, val; - const u8 pio = drive->pio_mode - XFER_PIO_0; - u8 safe = pio; - ide_drive_t *pair; - - pair = ide_get_pair_dev(drive); - if (pair) - safe = min_t(u8, safe, pair->pio_mode - XFER_PIO_0); - /* - * Update Command Transfer Mode for master/slave and Data - * Transfer Mode for this drive. - */ - mask = is_slave ? 0x07f00000 : 0x000007f0; - val = ((safe << 8) | (pio << 4)) << (is_slave ? 16 : 0); - hwif->select_data = (hwif->select_data & ~mask) | val; - /* tx4939ide_tf_load_fixup() will set the Sys_Ctl register */ -} - -static void tx4939ide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - u32 mask, val; - const u8 mode = drive->dma_mode; - - /* Update Data Transfer Mode for this drive. */ - if (mode >= XFER_UDMA_0) - val = mode - XFER_UDMA_0 + 8; - else - val = mode - XFER_MW_DMA_0 + 5; - if (drive->dn) { - mask = 0x00f00000; - val <<= 20; - } else { - mask = 0x000000f0; - val <<= 4; - } - hwif->select_data = (hwif->select_data & ~mask) | val; - /* tx4939ide_tf_load_fixup() will set the Sys_Ctl register */ -} - -static u16 tx4939ide_check_error_ints(ide_hwif_t *hwif) -{ - void __iomem *base = TX4939IDE_BASE(hwif); - u16 ctl = tx4939ide_readw(base, TX4939IDE_Int_Ctl); - - if (ctl & TX4939IDE_INT_BUSERR) { - /* reset FIFO */ - u16 sysctl = tx4939ide_readw(base, TX4939IDE_Sys_Ctl); - - tx4939ide_writew(sysctl | 0x4000, base, TX4939IDE_Sys_Ctl); - /* wait 12GBUSCLK (typ. 60ns @ GBUS200MHz, max 270ns) */ - ndelay(270); - tx4939ide_writew(sysctl, base, TX4939IDE_Sys_Ctl); - } - if (ctl & (TX4939IDE_INT_ADDRERR | - TX4939IDE_INT_DEVTIMING | TX4939IDE_INT_BUSERR)) - pr_err("%s: Error interrupt %#x (%s%s%s )\n", - hwif->name, ctl, - ctl & TX4939IDE_INT_ADDRERR ? " Address-Error" : "", - ctl & TX4939IDE_INT_DEVTIMING ? " DEV-Timing" : "", - ctl & TX4939IDE_INT_BUSERR ? " Bus-Error" : ""); - return ctl; -} - -static void tx4939ide_clear_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif; - void __iomem *base; - u16 ctl; - - /* - * tx4939ide_dma_test_irq() and tx4939ide_dma_end() do all job - * for DMA case. - */ - if (drive->waiting_for_dma) - return; - hwif = drive->hwif; - base = TX4939IDE_BASE(hwif); - ctl = tx4939ide_check_error_ints(hwif); - tx4939ide_writew(ctl, base, TX4939IDE_Int_Ctl); -} - -static u8 tx4939ide_cable_detect(ide_hwif_t *hwif) -{ - void __iomem *base = TX4939IDE_BASE(hwif); - - return tx4939ide_readw(base, TX4939IDE_Sys_Ctl) & 0x2000 ? - ATA_CBL_PATA40 : ATA_CBL_PATA80; -} - -#ifdef __BIG_ENDIAN -static void tx4939ide_dma_host_set(ide_drive_t *drive, int on) -{ - ide_hwif_t *hwif = drive->hwif; - u8 unit = drive->dn; - void __iomem *base = TX4939IDE_BASE(hwif); - u8 dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat); - - if (on) - dma_stat |= (1 << (5 + unit)); - else - dma_stat &= ~(1 << (5 + unit)); - - tx4939ide_writeb(dma_stat, base, TX4939IDE_DMA_Stat); -} -#else -#define tx4939ide_dma_host_set ide_dma_host_set -#endif - -static u8 tx4939ide_clear_dma_status(void __iomem *base) -{ - u8 dma_stat; - - /* read DMA status for INTR & ERROR flags */ - dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat); - /* clear INTR & ERROR flags */ - tx4939ide_writeb(dma_stat | ATA_DMA_INTR | ATA_DMA_ERR, base, - TX4939IDE_DMA_Stat); - /* recover intmask cleared by writing to bit2 of DMA_Stat */ - tx4939ide_writew(TX4939IDE_IGNORE_INTS << 8, base, TX4939IDE_Int_Ctl); - return dma_stat; -} - -#ifdef __BIG_ENDIAN -/* custom ide_build_dmatable to handle swapped layout */ -static int tx4939ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) -{ - ide_hwif_t *hwif = drive->hwif; - u32 *table = (u32 *)hwif->dmatable_cpu; - unsigned int count = 0; - int i; - struct scatterlist *sg; - - for_each_sg(hwif->sg_table, sg, cmd->sg_nents, i) { - u32 cur_addr, cur_len, bcount; - - cur_addr = sg_dma_address(sg); - cur_len = sg_dma_len(sg); - - /* - * Fill in the DMA table, without crossing any 64kB boundaries. - */ - - while (cur_len) { - if (count++ >= PRD_ENTRIES) - goto use_pio_instead; - - bcount = 0x10000 - (cur_addr & 0xffff); - if (bcount > cur_len) - bcount = cur_len; - /* - * This workaround for zero count seems required. - * (standard ide_build_dmatable does it too) - */ - if (bcount == 0x10000) - bcount = 0x8000; - *table++ = bcount & 0xffff; - *table++ = cur_addr; - cur_addr += bcount; - cur_len -= bcount; - } - } - - if (count) { - *(table - 2) |= 0x80000000; - return count; - } - -use_pio_instead: - printk(KERN_ERR "%s: %s\n", drive->name, - count ? "DMA table too small" : "empty DMA table?"); - - return 0; /* revert to PIO for this request */ -} -#else -#define tx4939ide_build_dmatable ide_build_dmatable -#endif - -static int tx4939ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) -{ - ide_hwif_t *hwif = drive->hwif; - void __iomem *base = TX4939IDE_BASE(hwif); - u8 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR; - - /* fall back to PIO! */ - if (tx4939ide_build_dmatable(drive, cmd) == 0) - return 1; - - /* PRD table */ - tx4939ide_writel(hwif->dmatable_dma, base, TX4939IDE_PRD_Ptr); - - /* specify r/w */ - tx4939ide_writeb(rw, base, TX4939IDE_DMA_Cmd); - - /* clear INTR & ERROR flags */ - tx4939ide_clear_dma_status(base); - - tx4939ide_writew(SECTOR_SIZE / 2, base, drive->dn ? - TX4939IDE_Xfer_Cnt_2 : TX4939IDE_Xfer_Cnt_1); - - tx4939ide_writew(blk_rq_sectors(cmd->rq), base, TX4939IDE_Sec_Cnt); - - return 0; -} - -static int tx4939ide_dma_end(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - u8 dma_stat, dma_cmd; - void __iomem *base = TX4939IDE_BASE(hwif); - u16 ctl = tx4939ide_readw(base, TX4939IDE_Int_Ctl); - - /* get DMA command mode */ - dma_cmd = tx4939ide_readb(base, TX4939IDE_DMA_Cmd); - /* stop DMA */ - tx4939ide_writeb(dma_cmd & ~ATA_DMA_START, base, TX4939IDE_DMA_Cmd); - - /* read and clear the INTR & ERROR bits */ - dma_stat = tx4939ide_clear_dma_status(base); - -#define CHECK_DMA_MASK (ATA_DMA_ACTIVE | ATA_DMA_ERR | ATA_DMA_INTR) - - /* verify good DMA status */ - if ((dma_stat & CHECK_DMA_MASK) == 0 && - (ctl & (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST)) == - (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST)) - /* INT_IDE lost... bug? */ - return 0; - return ((dma_stat & CHECK_DMA_MASK) != - ATA_DMA_INTR) ? 0x10 | dma_stat : 0; -} - -/* returns 1 if DMA IRQ issued, 0 otherwise */ -static int tx4939ide_dma_test_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - void __iomem *base = TX4939IDE_BASE(hwif); - u16 ctl, ide_int; - u8 dma_stat, stat; - int found = 0; - - ctl = tx4939ide_check_error_ints(hwif); - ide_int = ctl & (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST); - switch (ide_int) { - case TX4939IDE_INT_HOST: - /* On error, XFEREND might not be asserted. */ - stat = tx4939ide_readb(base, TX4939IDE_AltStat_DevCtl); - if ((stat & (ATA_BUSY | ATA_DRQ | ATA_ERR)) == ATA_ERR) - found = 1; - else - /* Wait for XFEREND (Mask HOST and unmask XFEREND) */ - ctl &= ~TX4939IDE_INT_XFEREND << 8; - ctl |= ide_int << 8; - break; - case TX4939IDE_INT_HOST | TX4939IDE_INT_XFEREND: - dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat); - if (!(dma_stat & ATA_DMA_INTR)) - pr_warn("%s: weird interrupt status. " - "DMA_Stat %#02x int_ctl %#04x\n", - hwif->name, dma_stat, ctl); - found = 1; - break; - } - /* - * Do not clear XFEREND, HOST now. They will be cleared by - * clearing bit2 of DMA_Stat. - */ - ctl &= ~ide_int; - tx4939ide_writew(ctl, base, TX4939IDE_Int_Ctl); - return found; -} - -#ifdef __BIG_ENDIAN -static u8 tx4939ide_dma_sff_read_status(ide_hwif_t *hwif) -{ - void __iomem *base = TX4939IDE_BASE(hwif); - - return tx4939ide_readb(base, TX4939IDE_DMA_Stat); -} -#else -#define tx4939ide_dma_sff_read_status ide_dma_sff_read_status -#endif - -static void tx4939ide_init_hwif(ide_hwif_t *hwif) -{ - void __iomem *base = TX4939IDE_BASE(hwif); - - /* Soft Reset */ - tx4939ide_writew(0x8000, base, TX4939IDE_Sys_Ctl); - /* at least 20 GBUSCLK (typ. 100ns @ GBUS200MHz, max 450ns) */ - ndelay(450); - tx4939ide_writew(0x0000, base, TX4939IDE_Sys_Ctl); - /* mask some interrupts and clear all interrupts */ - tx4939ide_writew((TX4939IDE_IGNORE_INTS << 8) | 0xff, base, - TX4939IDE_Int_Ctl); - - tx4939ide_writew(0x0008, base, TX4939IDE_Lo_Burst_Cnt); - tx4939ide_writew(0, base, TX4939IDE_Up_Burst_Cnt); -} - -static int tx4939ide_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d) -{ - hwif->dma_base = - hwif->extra_base + tx4939ide_swizzleb(TX4939IDE_DMA_Cmd); - /* - * Note that we cannot use ATA_DMA_TABLE_OFS, ATA_DMA_STATUS - * for big endian. - */ - return ide_allocate_dma_engine(hwif); -} - -static void tx4939ide_tf_load_fixup(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - void __iomem *base = TX4939IDE_BASE(hwif); - u16 sysctl = hwif->select_data >> (drive->dn ? 16 : 0); - - /* - * Fix ATA100 CORE System Control Register. (The write to the - * Device/Head register may write wrong data to the System - * Control Register) - * While Sys_Ctl is written here, dev_select() is not needed. - */ - tx4939ide_writew(sysctl, base, TX4939IDE_Sys_Ctl); -} - -static void tx4939ide_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, - u8 valid) -{ - ide_tf_load(drive, tf, valid); - - if (valid & IDE_VALID_DEVICE) - tx4939ide_tf_load_fixup(drive); -} - -#ifdef __BIG_ENDIAN - -/* custom iops (independent from SWAP_IO_SPACE) */ -static void tx4939ide_input_data_swap(ide_drive_t *drive, struct ide_cmd *cmd, - void *buf, unsigned int len) -{ - unsigned long port = drive->hwif->io_ports.data_addr; - unsigned short *ptr = buf; - unsigned int count = (len + 1) / 2; - - while (count--) - *ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port)); - __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2)); -} - -static void tx4939ide_output_data_swap(ide_drive_t *drive, struct ide_cmd *cmd, - void *buf, unsigned int len) -{ - unsigned long port = drive->hwif->io_ports.data_addr; - unsigned short *ptr = buf; - unsigned int count = (len + 1) / 2; - - while (count--) { - __raw_writew(le16_to_cpu(*ptr), (void __iomem *)port); - ptr++; - } - __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2)); -} - -static const struct ide_tp_ops tx4939ide_tp_ops = { - .exec_command = ide_exec_command, - .read_status = ide_read_status, - .read_altstatus = ide_read_altstatus, - .write_devctl = ide_write_devctl, - - .dev_select = ide_dev_select, - .tf_load = tx4939ide_tf_load, - .tf_read = ide_tf_read, - - .input_data = tx4939ide_input_data_swap, - .output_data = tx4939ide_output_data_swap, -}; - -#else /* __LITTLE_ENDIAN */ - -static const struct ide_tp_ops tx4939ide_tp_ops = { - .exec_command = ide_exec_command, - .read_status = ide_read_status, - .read_altstatus = ide_read_altstatus, - .write_devctl = ide_write_devctl, - - .dev_select = ide_dev_select, - .tf_load = tx4939ide_tf_load, - .tf_read = ide_tf_read, - - .input_data = ide_input_data, - .output_data = ide_output_data, -}; - -#endif /* __LITTLE_ENDIAN */ - -static const struct ide_port_ops tx4939ide_port_ops = { - .set_pio_mode = tx4939ide_set_pio_mode, - .set_dma_mode = tx4939ide_set_dma_mode, - .clear_irq = tx4939ide_clear_irq, - .cable_detect = tx4939ide_cable_detect, -}; - -static const struct ide_dma_ops tx4939ide_dma_ops = { - .dma_host_set = tx4939ide_dma_host_set, - .dma_setup = tx4939ide_dma_setup, - .dma_start = ide_dma_start, - .dma_end = tx4939ide_dma_end, - .dma_test_irq = tx4939ide_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = tx4939ide_dma_sff_read_status, -}; - -static const struct ide_port_info tx4939ide_port_info __initconst = { - .init_hwif = tx4939ide_init_hwif, - .init_dma = tx4939ide_init_dma, - .port_ops = &tx4939ide_port_ops, - .dma_ops = &tx4939ide_dma_ops, - .tp_ops = &tx4939ide_tp_ops, - .host_flags = IDE_HFLAG_MMIO, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA5, - .chipset = ide_generic, -}; - -static int __init tx4939ide_probe(struct platform_device *pdev) -{ - struct ide_hw hw, *hws[] = { &hw }; - struct ide_host *host; - struct resource *res; - int irq, ret; - unsigned long mapbase; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return -ENODEV; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), MODNAME)) - return -EBUSY; - mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!mapbase) - return -EBUSY; - memset(&hw, 0, sizeof(hw)); - hw.io_ports.data_addr = - mapbase + tx4939ide_swizzlew(TX4939IDE_Data); - hw.io_ports.error_addr = - mapbase + tx4939ide_swizzleb(TX4939IDE_Error_Feature); - hw.io_ports.nsect_addr = - mapbase + tx4939ide_swizzleb(TX4939IDE_Sec); - hw.io_ports.lbal_addr = - mapbase + tx4939ide_swizzleb(TX4939IDE_LBA0); - hw.io_ports.lbam_addr = - mapbase + tx4939ide_swizzleb(TX4939IDE_LBA1); - hw.io_ports.lbah_addr = - mapbase + tx4939ide_swizzleb(TX4939IDE_LBA2); - hw.io_ports.device_addr = - mapbase + tx4939ide_swizzleb(TX4939IDE_DevHead); - hw.io_ports.command_addr = - mapbase + tx4939ide_swizzleb(TX4939IDE_Stat_Cmd); - hw.io_ports.ctl_addr = - mapbase + tx4939ide_swizzleb(TX4939IDE_AltStat_DevCtl); - hw.irq = irq; - hw.dev = &pdev->dev; - - pr_info("TX4939 IDE interface (base %#lx, irq %d)\n", mapbase, irq); - host = ide_host_alloc(&tx4939ide_port_info, hws, 1); - if (!host) - return -ENOMEM; - /* use extra_base for base address of the all registers */ - host->ports[0]->extra_base = mapbase; - ret = ide_host_register(host, &tx4939ide_port_info, hws); - if (ret) { - ide_host_free(host); - return ret; - } - platform_set_drvdata(pdev, host); - return 0; -} - -static int __exit tx4939ide_remove(struct platform_device *pdev) -{ - struct ide_host *host = platform_get_drvdata(pdev); - - ide_host_remove(host); - return 0; -} - -#ifdef CONFIG_PM -static int tx4939ide_resume(struct platform_device *dev) -{ - struct ide_host *host = platform_get_drvdata(dev); - ide_hwif_t *hwif = host->ports[0]; - - tx4939ide_init_hwif(hwif); - return 0; -} -#else -#define tx4939ide_resume NULL -#endif - -static struct platform_driver tx4939ide_driver = { - .driver = { - .name = MODNAME, - }, - .remove = __exit_p(tx4939ide_remove), - .resume = tx4939ide_resume, -}; - -module_platform_driver_probe(tx4939ide_driver, tx4939ide_probe); - -MODULE_DESCRIPTION("TX4939 internal IDE driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:tx4939ide"); diff --git a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c deleted file mode 100644 index cf996f788292..000000000000 --- a/drivers/ide/umc8672.c +++ /dev/null @@ -1,184 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1995-1996 Linus Torvalds & author (see below) - */ - -/* - * Principal Author/Maintainer: PODIEN@hml2.atlas.de (Wolfram Podien) - * - * This file provides support for the advanced features - * of the UMC 8672 IDE interface. - * - * Version 0.01 Initial version, hacked out of ide.c, - * and #include'd rather than compiled separately. - * This will get cleaned up in a subsequent release. - * - * Version 0.02 now configs/compiles separate from ide.c -ml - * Version 0.03 enhanced auto-tune, fix display bug - * Version 0.05 replace sti() with restore_flags() -ml - * add detection of possible race condition -ml - */ - -/* - * VLB Controller Support from - * Wolfram Podien - * Rohoefe 3 - * D28832 Achim - * Germany - * - * To enable UMC8672 support there must a lilo line like - * append="ide0=umc8672"... - * To set the speed according to the abilities of the hardware there must be a - * line like - * #define UMC_DRIVE0 11 - * in the beginning of the driver, which sets the speed of drive 0 to 11 (there - * are some lines present). 0 - 11 are allowed speed values. These values are - * the results from the DOS speed test program supplied from UMC. 11 is the - * highest speed (about PIO mode 3) - */ -#define REALLY_SLOW_IO /* some systems can safely undef this */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define DRV_NAME "umc8672" - -/* - * Default speeds. These can be changed with "auto-tune" and/or hdparm. - */ -#define UMC_DRIVE0 1 /* DOS measured drive speeds */ -#define UMC_DRIVE1 1 /* 0 to 11 allowed */ -#define UMC_DRIVE2 1 /* 11 = Fastest Speed */ -#define UMC_DRIVE3 1 /* In case of crash reduce speed */ - -static u8 current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3}; -static const u8 pio_to_umc [5] = {0, 3, 7, 10, 11}; /* rough guesses */ - -/* 0 1 2 3 4 5 6 7 8 9 10 11 */ -static const u8 speedtab [3][12] = { - {0x0f, 0x0b, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1}, - {0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1}, - {0xff, 0xcb, 0xc0, 0x58, 0x36, 0x33, 0x23, 0x22, 0x21, 0x11, 0x10, 0x0} -}; - -static void out_umc(char port, char wert) -{ - outb_p(port, 0x108); - outb_p(wert, 0x109); -} - -static inline u8 in_umc(char port) -{ - outb_p(port, 0x108); - return inb_p(0x109); -} - -static void umc_set_speeds(u8 speeds[]) -{ - int i, tmp; - - outb_p(0x5A, 0x108); /* enable umc */ - - out_umc(0xd7, (speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4))); - out_umc(0xd6, (speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4))); - tmp = 0; - for (i = 3; i >= 0; i--) - tmp = (tmp << 2) | speedtab[1][speeds[i]]; - out_umc(0xdc, tmp); - for (i = 0; i < 4; i++) { - out_umc(0xd0 + i, speedtab[2][speeds[i]]); - out_umc(0xd8 + i, speedtab[2][speeds[i]]); - } - outb_p(0xa5, 0x108); /* disable umc */ - - printk("umc8672: drive speeds [0 to 11]: %d %d %d %d\n", - speeds[0], speeds[1], speeds[2], speeds[3]); -} - -static void umc_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - ide_hwif_t *mate = hwif->mate; - unsigned long flags; - const u8 pio = drive->pio_mode - XFER_PIO_0; - - printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", - drive->name, pio, pio_to_umc[pio]); - if (mate) - spin_lock_irqsave(&mate->lock, flags); - if (mate && mate->handler) { - printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n"); - } else { - current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio]; - umc_set_speeds(current_speeds); - } - if (mate) - spin_unlock_irqrestore(&mate->lock, flags); -} - -static const struct ide_port_ops umc8672_port_ops = { - .set_pio_mode = umc_set_pio_mode, -}; - -static const struct ide_port_info umc8672_port_info __initconst = { - .name = DRV_NAME, - .chipset = ide_umc8672, - .port_ops = &umc8672_port_ops, - .host_flags = IDE_HFLAG_NO_DMA, - .pio_mask = ATA_PIO4, -}; - -static int __init umc8672_probe(void) -{ - unsigned long flags; - - if (!request_region(0x108, 2, "umc8672")) { - printk(KERN_ERR "umc8672: ports 0x108-0x109 already in use.\n"); - return 1; - } - local_irq_save(flags); - outb_p(0x5A, 0x108); /* enable umc */ - if (in_umc (0xd5) != 0xa0) { - local_irq_restore(flags); - printk(KERN_ERR "umc8672: not found\n"); - release_region(0x108, 2); - return 1; - } - outb_p(0xa5, 0x108); /* disable umc */ - - umc_set_speeds(current_speeds); - local_irq_restore(flags); - - return ide_legacy_device_add(&umc8672_port_info, 0); -} - -static bool probe_umc8672; - -module_param_named(probe, probe_umc8672, bool, 0); -MODULE_PARM_DESC(probe, "probe for UMC8672 chipset"); - -static int __init umc8672_init(void) -{ - if (probe_umc8672 == 0) - goto out; - - if (umc8672_probe() == 0) - return 0; -out: - return -ENODEV; -} - -module_init(umc8672_init); - -MODULE_AUTHOR("Wolfram Podien"); -MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c deleted file mode 100644 index 63a3aca506fc..000000000000 --- a/drivers/ide/via82cxxx.c +++ /dev/null @@ -1,532 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * VIA IDE driver for Linux. Supported southbridges: - * - * vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b, - * vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a, - * vt8235, vt8237, vt8237a - * - * Copyright (c) 2000-2002 Vojtech Pavlik - * Copyright (c) 2007-2010 Bartlomiej Zolnierkiewicz - * - * Based on the work of: - * Michel Aubry - * Jeff Garzik - * Andre Hedrick - * - * Documentation: - * Obsolete device documentation publicly available from via.com.tw - * Current device documentation available under NDA only - */ - - -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_PPC_CHRP -#include -#endif - -#define DRV_NAME "via82cxxx" - -#define VIA_IDE_ENABLE 0x40 -#define VIA_IDE_CONFIG 0x41 -#define VIA_FIFO_CONFIG 0x43 -#define VIA_MISC_1 0x44 -#define VIA_MISC_2 0x45 -#define VIA_MISC_3 0x46 -#define VIA_DRIVE_TIMING 0x48 -#define VIA_8BIT_TIMING 0x4e -#define VIA_ADDRESS_SETUP 0x4c -#define VIA_UDMA_TIMING 0x50 - -#define VIA_BAD_PREQ 0x01 /* Crashes if PREQ# till DDACK# set */ -#define VIA_BAD_CLK66 0x02 /* 66 MHz clock doesn't work correctly */ -#define VIA_SET_FIFO 0x04 /* Needs to have FIFO split set */ -#define VIA_NO_UNMASK 0x08 /* Doesn't work with IRQ unmasking on */ -#define VIA_BAD_ID 0x10 /* Has wrong vendor ID (0x1107) */ -#define VIA_BAD_AST 0x20 /* Don't touch Address Setup Timing */ -#define VIA_SATA_PATA 0x80 /* SATA/PATA combined configuration */ - -enum { - VIA_IDFLAG_SINGLE = (1 << 1), /* single channel controller */ -}; - -/* - * VIA SouthBridge chips. - */ - -static struct via_isa_bridge { - char *name; - u16 id; - u8 rev_min; - u8 rev_max; - u8 udma_mask; - u8 flags; -} via_isa_bridges[] = { - { "vx855", PCI_DEVICE_ID_VIA_VX855, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA }, - { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA }, - { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA }, - { "vt8261", PCI_DEVICE_ID_VIA_8261, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, - { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, - { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, - { "vt6415", PCI_DEVICE_ID_VIA_6415, 0x00, 0xff, ATA_UDMA6, VIA_BAD_AST }, - { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, - { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, - { "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, - { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, - { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, - { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, ATA_UDMA5, }, - { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, ATA_UDMA5, }, - { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, ATA_UDMA5, }, - { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, ATA_UDMA5, }, - { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, ATA_UDMA4, }, - { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 }, - { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, ATA_UDMA4, }, - { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 }, - { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, ATA_UDMA2, VIA_SET_FIFO }, - { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, ATA_UDMA2, VIA_SET_FIFO | VIA_BAD_PREQ }, - { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, ATA_UDMA2, VIA_SET_FIFO }, - { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, ATA_UDMA2, VIA_SET_FIFO }, - { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, 0x00, VIA_SET_FIFO }, - { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, 0x00, VIA_SET_FIFO | VIA_NO_UNMASK }, - { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, 0x00, VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID }, - { "vtxxxx", PCI_DEVICE_ID_VIA_ANON, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, - { NULL } -}; - -static unsigned int via_clock; -static char *via_dma[] = { "16", "25", "33", "44", "66", "100", "133" }; - -struct via82cxxx_dev -{ - struct via_isa_bridge *via_config; - unsigned int via_80w; -}; - -/** - * via_set_speed - write timing registers - * @dev: PCI device - * @dn: device - * @timing: IDE timing data to use - * - * via_set_speed writes timing values to the chipset registers - */ - -static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing) -{ - struct pci_dev *dev = to_pci_dev(hwif->dev); - struct ide_host *host = pci_get_drvdata(dev); - struct via82cxxx_dev *vdev = host->host_priv; - u8 t; - - if (~vdev->via_config->flags & VIA_BAD_AST) { - pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t); - t = (t & ~(3 << ((3 - dn) << 1))) | ((clamp_val(timing->setup, 1, 4) - 1) << ((3 - dn) << 1)); - pci_write_config_byte(dev, VIA_ADDRESS_SETUP, t); - } - - pci_write_config_byte(dev, VIA_8BIT_TIMING + (1 - (dn >> 1)), - ((clamp_val(timing->act8b, 1, 16) - 1) << 4) | (clamp_val(timing->rec8b, 1, 16) - 1)); - - pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn), - ((clamp_val(timing->active, 1, 16) - 1) << 4) | (clamp_val(timing->recover, 1, 16) - 1)); - - switch (vdev->via_config->udma_mask) { - case ATA_UDMA2: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 5) - 2)) : 0x03; break; - case ATA_UDMA4: t = timing->udma ? (0xe8 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x0f; break; - case ATA_UDMA5: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x07; break; - case ATA_UDMA6: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x07; break; - } - - /* Set UDMA unless device is not UDMA capable */ - if (vdev->via_config->udma_mask) { - u8 udma_etc; - - pci_read_config_byte(dev, VIA_UDMA_TIMING + 3 - dn, &udma_etc); - - /* clear transfer mode bit */ - udma_etc &= ~0x20; - - if (timing->udma) { - /* preserve 80-wire cable detection bit */ - udma_etc &= 0x10; - udma_etc |= t; - } - - pci_write_config_byte(dev, VIA_UDMA_TIMING + 3 - dn, udma_etc); - } -} - -/** - * via_set_drive - configure transfer mode - * @hwif: port - * @drive: Drive to set up - * - * via_set_drive() computes timing values configures the chipset to - * a desired transfer mode. It also can be called by upper layers. - */ - -static void via_set_drive(ide_hwif_t *hwif, ide_drive_t *drive) -{ - ide_drive_t *peer = ide_get_pair_dev(drive); - struct ide_host *host = dev_get_drvdata(hwif->dev); - struct via82cxxx_dev *vdev = host->host_priv; - struct ide_timing t, p; - unsigned int T, UT; - const u8 speed = drive->dma_mode; - - T = 1000000000 / via_clock; - - switch (vdev->via_config->udma_mask) { - case ATA_UDMA2: UT = T; break; - case ATA_UDMA4: UT = T/2; break; - case ATA_UDMA5: UT = T/3; break; - case ATA_UDMA6: UT = T/4; break; - default: UT = T; - } - - ide_timing_compute(drive, speed, &t, T, UT); - - if (peer) { - ide_timing_compute(peer, peer->pio_mode, &p, T, UT); - ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT); - } - - via_set_speed(hwif, drive->dn, &t); -} - -/** - * via_set_pio_mode - set host controller for PIO mode - * @hwif: port - * @drive: drive - * - * A callback from the upper layers for PIO-only tuning. - */ - -static void via_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) -{ - drive->dma_mode = drive->pio_mode; - via_set_drive(hwif, drive); -} - -static struct via_isa_bridge *via_config_find(struct pci_dev **isa) -{ - struct via_isa_bridge *via_config; - - for (via_config = via_isa_bridges; - via_config->id != PCI_DEVICE_ID_VIA_ANON; via_config++) - if ((*isa = pci_get_device(PCI_VENDOR_ID_VIA + - !!(via_config->flags & VIA_BAD_ID), - via_config->id, NULL))) { - - if ((*isa)->revision >= via_config->rev_min && - (*isa)->revision <= via_config->rev_max) - break; - pci_dev_put(*isa); - } - - return via_config; -} - -/* - * Check and handle 80-wire cable presence - */ -static void via_cable_detect(struct via82cxxx_dev *vdev, u32 u) -{ - int i; - - switch (vdev->via_config->udma_mask) { - case ATA_UDMA4: - for (i = 24; i >= 0; i -= 8) - if (((u >> (i & 16)) & 8) && - ((u >> i) & 0x20) && - (((u >> i) & 7) < 2)) { - /* - * 2x PCI clock and - * UDMA w/ < 3T/cycle - */ - vdev->via_80w |= (1 << (1 - (i >> 4))); - } - break; - - case ATA_UDMA5: - for (i = 24; i >= 0; i -= 8) - if (((u >> i) & 0x10) || - (((u >> i) & 0x20) && - (((u >> i) & 7) < 4))) { - /* BIOS 80-wire bit or - * UDMA w/ < 60ns/cycle - */ - vdev->via_80w |= (1 << (1 - (i >> 4))); - } - break; - - case ATA_UDMA6: - for (i = 24; i >= 0; i -= 8) - if (((u >> i) & 0x10) || - (((u >> i) & 0x20) && - (((u >> i) & 7) < 6))) { - /* BIOS 80-wire bit or - * UDMA w/ < 60ns/cycle - */ - vdev->via_80w |= (1 << (1 - (i >> 4))); - } - break; - } -} - -/** - * init_chipset_via82cxxx - initialization handler - * @dev: PCI device - * - * The initialization callback. Here we determine the IDE chip type - * and initialize its drive independent registers. - */ - -static int init_chipset_via82cxxx(struct pci_dev *dev) -{ - struct ide_host *host = pci_get_drvdata(dev); - struct via82cxxx_dev *vdev = host->host_priv; - struct via_isa_bridge *via_config = vdev->via_config; - u8 t, v; - u32 u; - - /* - * Detect cable and configure Clk66 - */ - pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); - - via_cable_detect(vdev, u); - - if (via_config->udma_mask == ATA_UDMA4) { - /* Enable Clk66 */ - pci_write_config_dword(dev, VIA_UDMA_TIMING, u|0x80008); - } else if (via_config->flags & VIA_BAD_CLK66) { - /* Would cause trouble on 596a and 686 */ - pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008); - } - - /* - * Check whether interfaces are enabled. - */ - - pci_read_config_byte(dev, VIA_IDE_ENABLE, &v); - - /* - * Set up FIFO sizes and thresholds. - */ - - pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t); - - /* Disable PREQ# till DDACK# */ - if (via_config->flags & VIA_BAD_PREQ) { - /* Would crash on 586b rev 41 */ - t &= 0x7f; - } - - /* Fix FIFO split between channels */ - if (via_config->flags & VIA_SET_FIFO) { - t &= (t & 0x9f); - switch (v & 3) { - case 2: t |= 0x00; break; /* 16 on primary */ - case 1: t |= 0x60; break; /* 16 on secondary */ - case 3: t |= 0x20; break; /* 8 pri 8 sec */ - } - } - - pci_write_config_byte(dev, VIA_FIFO_CONFIG, t); - - return 0; -} - -/* - * Cable special cases - */ - -static const struct dmi_system_id cable_dmi_table[] = { - { - .ident = "Acer Ferrari 3400", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Acer,Inc."), - DMI_MATCH(DMI_BOARD_NAME, "Ferrari 3400"), - }, - }, - { } -}; - -static int via_cable_override(struct pci_dev *pdev) -{ - /* Systems by DMI */ - if (dmi_check_system(cable_dmi_table)) - return 1; - - /* Arima W730-K8/Targa Visionary 811/... */ - if (pdev->subsystem_vendor == 0x161F && - pdev->subsystem_device == 0x2032) - return 1; - - return 0; -} - -static u8 via82cxxx_cable_detect(ide_hwif_t *hwif) -{ - struct pci_dev *pdev = to_pci_dev(hwif->dev); - struct ide_host *host = pci_get_drvdata(pdev); - struct via82cxxx_dev *vdev = host->host_priv; - - if (via_cable_override(pdev)) - return ATA_CBL_PATA40_SHORT; - - if ((vdev->via_config->flags & VIA_SATA_PATA) && hwif->channel == 0) - return ATA_CBL_SATA; - - if ((vdev->via_80w >> hwif->channel) & 1) - return ATA_CBL_PATA80; - else - return ATA_CBL_PATA40; -} - -static const struct ide_port_ops via_port_ops = { - .set_pio_mode = via_set_pio_mode, - .set_dma_mode = via_set_drive, - .cable_detect = via82cxxx_cable_detect, -}; - -static const struct ide_port_info via82cxxx_chipset = { - .name = DRV_NAME, - .init_chipset = init_chipset_via82cxxx, - .enablebits = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } }, - .port_ops = &via_port_ops, - .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST | - IDE_HFLAG_POST_SET_MODE | - IDE_HFLAG_IO_32BIT, - .pio_mask = ATA_PIO5, - .swdma_mask = ATA_SWDMA2, - .mwdma_mask = ATA_MWDMA2, -}; - -static int via_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct pci_dev *isa = NULL; - struct via_isa_bridge *via_config; - struct via82cxxx_dev *vdev; - int rc; - u8 idx = id->driver_data; - struct ide_port_info d; - - d = via82cxxx_chipset; - - /* - * Find the ISA bridge and check we know what it is. - */ - via_config = via_config_find(&isa); - - /* - * Print the boot message. - */ - printk(KERN_INFO DRV_NAME " %s: VIA %s (rev %02x) IDE %sDMA%s\n", - pci_name(dev), via_config->name, isa->revision, - via_config->udma_mask ? "U" : "MW", - via_dma[via_config->udma_mask ? - (fls(via_config->udma_mask) - 1) : 0]); - - pci_dev_put(isa); - - /* - * Determine system bus clock. - */ - via_clock = (ide_pci_clk ? ide_pci_clk : 33) * 1000; - - switch (via_clock) { - case 33000: via_clock = 33333; break; - case 37000: via_clock = 37500; break; - case 41000: via_clock = 41666; break; - } - - if (via_clock < 20000 || via_clock > 50000) { - printk(KERN_WARNING DRV_NAME ": User given PCI clock speed " - "impossible (%d), using 33 MHz instead.\n", via_clock); - via_clock = 33333; - } - - if (idx == 1) - d.enablebits[1].reg = d.enablebits[0].reg = 0; - else - d.host_flags |= IDE_HFLAG_NO_AUTODMA; - - if (idx == VIA_IDFLAG_SINGLE) - d.host_flags |= IDE_HFLAG_SINGLE; - - if ((via_config->flags & VIA_NO_UNMASK) == 0) - d.host_flags |= IDE_HFLAG_UNMASK_IRQS; - - d.udma_mask = via_config->udma_mask; - - vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); - if (!vdev) { - printk(KERN_ERR DRV_NAME " %s: out of memory :(\n", - pci_name(dev)); - return -ENOMEM; - } - - vdev->via_config = via_config; - - rc = ide_pci_init_one(dev, &d, vdev); - if (rc) - kfree(vdev); - - return rc; -} - -static void via_remove(struct pci_dev *dev) -{ - struct ide_host *host = pci_get_drvdata(dev); - struct via82cxxx_dev *vdev = host->host_priv; - - ide_pci_remove(dev); - kfree(vdev); -} - -static const struct pci_device_id via_pci_tbl[] = { - { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), 0 }, - { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1), 0 }, - { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_CX700_IDE), 0 }, - { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_VX855_IDE), VIA_IDFLAG_SINGLE }, - { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6410), 1 }, - { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6415), 1 }, - { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), 1 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, via_pci_tbl); - -static struct pci_driver via_pci_driver = { - .name = "VIA_IDE", - .id_table = via_pci_tbl, - .probe = via_init_one, - .remove = via_remove, - .suspend = ide_pci_suspend, - .resume = ide_pci_resume, -}; - -static int __init via_ide_init(void) -{ - return ide_pci_register_driver(&via_pci_driver); -} - -static void __exit via_ide_exit(void) -{ - pci_unregister_driver(&via_pci_driver); -} - -module_init(via_ide_init); -module_exit(via_ide_exit); - -MODULE_AUTHOR("Vojtech Pavlik, Bartlomiej Zolnierkiewicz, Michel Aubry, Jeff Garzik, Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for VIA IDE"); -MODULE_LICENSE("GPL"); diff --git a/include/linux/ide.h b/include/linux/ide.h deleted file mode 100644 index 2c300689a51a..000000000000 --- a/include/linux/ide.h +++ /dev/null @@ -1,1623 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _IDE_H -#define _IDE_H -/* - * linux/include/linux/ide.h - * - * Copyright (C) 1994-2002 Linus Torvalds & authors - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* for request_sense */ -#include -#include -#include -#include - -/* - * Probably not wise to fiddle with these - */ -#define SUPPORT_VLB_SYNC 1 -#define IDE_DEFAULT_MAX_FAILURES 1 -#define ERROR_MAX 8 /* Max read/write errors per sector */ -#define ERROR_RESET 3 /* Reset controller every 4th retry */ -#define ERROR_RECAL 1 /* Recalibrate every 2nd retry */ - -struct device; - -/* values for ide_request.type */ -enum ata_priv_type { - ATA_PRIV_MISC, - ATA_PRIV_TASKFILE, - ATA_PRIV_PC, - ATA_PRIV_SENSE, /* sense request */ - ATA_PRIV_PM_SUSPEND, /* suspend request */ - ATA_PRIV_PM_RESUME, /* resume request */ -}; - -struct ide_request { - struct scsi_request sreq; - u8 sense[SCSI_SENSE_BUFFERSIZE]; - u8 type; - void *special; -}; - -static inline struct ide_request *ide_req(struct request *rq) -{ - return blk_mq_rq_to_pdu(rq); -} - -static inline bool ata_misc_request(struct request *rq) -{ - return blk_rq_is_private(rq) && ide_req(rq)->type == ATA_PRIV_MISC; -} - -static inline bool ata_taskfile_request(struct request *rq) -{ - return blk_rq_is_private(rq) && ide_req(rq)->type == ATA_PRIV_TASKFILE; -} - -static inline bool ata_pc_request(struct request *rq) -{ - return blk_rq_is_private(rq) && ide_req(rq)->type == ATA_PRIV_PC; -} - -static inline bool ata_sense_request(struct request *rq) -{ - return blk_rq_is_private(rq) && ide_req(rq)->type == ATA_PRIV_SENSE; -} - -static inline bool ata_pm_request(struct request *rq) -{ - return blk_rq_is_private(rq) && - (ide_req(rq)->type == ATA_PRIV_PM_SUSPEND || - ide_req(rq)->type == ATA_PRIV_PM_RESUME); -} - -/* Error codes returned in result to the higher part of the driver. */ -enum { - IDE_DRV_ERROR_GENERAL = 101, - IDE_DRV_ERROR_FILEMARK = 102, - IDE_DRV_ERROR_EOD = 103, -}; - -/* - * Definitions for accessing IDE controller registers - */ -#define IDE_NR_PORTS (10) - -struct ide_io_ports { - unsigned long data_addr; - - union { - unsigned long error_addr; /* read: error */ - unsigned long feature_addr; /* write: feature */ - }; - - unsigned long nsect_addr; - unsigned long lbal_addr; - unsigned long lbam_addr; - unsigned long lbah_addr; - - unsigned long device_addr; - - union { - unsigned long status_addr; /*  read: status  */ - unsigned long command_addr; /* write: command */ - }; - - unsigned long ctl_addr; - - unsigned long irq_addr; -}; - -#define OK_STAT(stat,good,bad) (((stat)&((good)|(bad)))==(good)) - -#define BAD_R_STAT (ATA_BUSY | ATA_ERR) -#define BAD_W_STAT (BAD_R_STAT | ATA_DF) -#define BAD_STAT (BAD_R_STAT | ATA_DRQ) -#define DRIVE_READY (ATA_DRDY | ATA_DSC) - -#define BAD_CRC (ATA_ABORTED | ATA_ICRC) - -#define SATA_NR_PORTS (3) /* 16 possible ?? */ - -#define SATA_STATUS_OFFSET (0) -#define SATA_ERROR_OFFSET (1) -#define SATA_CONTROL_OFFSET (2) - -/* - * Our Physical Region Descriptor (PRD) table should be large enough - * to handle the biggest I/O request we are likely to see. Since requests - * can have no more than 256 sectors, and since the typical blocksize is - * two or more sectors, we could get by with a limit of 128 entries here for - * the usual worst case. Most requests seem to include some contiguous blocks, - * further reducing the number of table entries required. - * - * The driver reverts to PIO mode for individual requests that exceed - * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling - * 100% of all crazy scenarios here is not necessary. - * - * As it turns out though, we must allocate a full 4KB page for this, - * so the two PRD tables (ide0 & ide1) will each get half of that, - * allowing each to have about 256 entries (8 bytes each) from this. - */ -#define PRD_BYTES 8 -#define PRD_ENTRIES 256 - -/* - * Some more useful definitions - */ -#define PARTN_BITS 6 /* number of minor dev bits for partitions */ -#define MAX_DRIVES 2 /* per interface; 2 assumed by lots of code */ - -/* - * Timeouts for various operations: - */ -enum { - /* spec allows up to 20ms, but CF cards and SSD drives need more */ - WAIT_DRQ = 1 * HZ, /* 1s */ - /* some laptops are very slow */ - WAIT_READY = 5 * HZ, /* 5s */ - /* should be less than 3ms (?), if all ATAPI CD is closed at boot */ - WAIT_PIDENTIFY = 10 * HZ, /* 10s */ - /* worst case when spinning up */ - WAIT_WORSTCASE = 30 * HZ, /* 30s */ - /* maximum wait for an IRQ to happen */ - WAIT_CMD = 10 * HZ, /* 10s */ - /* Some drives require a longer IRQ timeout. */ - WAIT_FLOPPY_CMD = 50 * HZ, /* 50s */ - /* - * Some drives (for example, Seagate STT3401A Travan) require a very - * long timeout, because they don't return an interrupt or clear their - * BSY bit until after the command completes (even retension commands). - */ - WAIT_TAPE_CMD = 900 * HZ, /* 900s */ - /* minimum sleep time */ - WAIT_MIN_SLEEP = HZ / 50, /* 20ms */ -}; - -/* - * Op codes for special requests to be handled by ide_special_rq(). - * Values should be in the range of 0x20 to 0x3f. - */ -#define REQ_DRIVE_RESET 0x20 -#define REQ_DEVSET_EXEC 0x21 -#define REQ_PARK_HEADS 0x22 -#define REQ_UNPARK_HEADS 0x23 - -/* - * hwif_chipset_t is used to keep track of the specific hardware - * chipset used by each IDE interface, if known. - */ -enum { ide_unknown, ide_generic, ide_pci, - ide_cmd640, ide_dtc2278, ide_ali14xx, - ide_qd65xx, ide_umc8672, ide_ht6560b, - ide_4drives, ide_pmac, ide_acorn, - ide_au1xxx, ide_palm3710 -}; - -typedef u8 hwif_chipset_t; - -/* - * Structure to hold all information about the location of this port - */ -struct ide_hw { - union { - struct ide_io_ports io_ports; - unsigned long io_ports_array[IDE_NR_PORTS]; - }; - - int irq; /* our irq number */ - struct device *dev, *parent; - unsigned long config; -}; - -static inline void ide_std_init_ports(struct ide_hw *hw, - unsigned long io_addr, - unsigned long ctl_addr) -{ - unsigned int i; - - for (i = 0; i <= 7; i++) - hw->io_ports_array[i] = io_addr++; - - hw->io_ports.ctl_addr = ctl_addr; -} - -#define MAX_HWIFS 10 - -/* - * Now for the data we need to maintain per-drive: ide_drive_t - */ - -#define ide_scsi 0x21 -#define ide_disk 0x20 -#define ide_optical 0x7 -#define ide_cdrom 0x5 -#define ide_tape 0x1 -#define ide_floppy 0x0 - -/* - * Special Driver Flags - */ -enum { - IDE_SFLAG_SET_GEOMETRY = BIT(0), - IDE_SFLAG_RECALIBRATE = BIT(1), - IDE_SFLAG_SET_MULTMODE = BIT(2), -}; - -/* - * Status returned from various ide_ functions - */ -typedef enum { - ide_stopped, /* no drive operation was started */ - ide_started, /* a drive operation was started, handler was set */ -} ide_startstop_t; - -enum { - IDE_VALID_ERROR = BIT(1), - IDE_VALID_FEATURE = IDE_VALID_ERROR, - IDE_VALID_NSECT = BIT(2), - IDE_VALID_LBAL = BIT(3), - IDE_VALID_LBAM = BIT(4), - IDE_VALID_LBAH = BIT(5), - IDE_VALID_DEVICE = BIT(6), - IDE_VALID_LBA = IDE_VALID_LBAL | - IDE_VALID_LBAM | - IDE_VALID_LBAH, - IDE_VALID_OUT_TF = IDE_VALID_FEATURE | - IDE_VALID_NSECT | - IDE_VALID_LBA, - IDE_VALID_IN_TF = IDE_VALID_NSECT | - IDE_VALID_LBA, - IDE_VALID_OUT_HOB = IDE_VALID_OUT_TF, - IDE_VALID_IN_HOB = IDE_VALID_ERROR | - IDE_VALID_NSECT | - IDE_VALID_LBA, -}; - -enum { - IDE_TFLAG_LBA48 = BIT(0), - IDE_TFLAG_WRITE = BIT(1), - IDE_TFLAG_CUSTOM_HANDLER = BIT(2), - IDE_TFLAG_DMA_PIO_FALLBACK = BIT(3), - /* force 16-bit I/O operations */ - IDE_TFLAG_IO_16BIT = BIT(4), - /* struct ide_cmd was allocated using kmalloc() */ - IDE_TFLAG_DYN = BIT(5), - IDE_TFLAG_FS = BIT(6), - IDE_TFLAG_MULTI_PIO = BIT(7), - IDE_TFLAG_SET_XFER = BIT(8), -}; - -enum { - IDE_FTFLAG_FLAGGED = BIT(0), - IDE_FTFLAG_SET_IN_FLAGS = BIT(1), - IDE_FTFLAG_OUT_DATA = BIT(2), - IDE_FTFLAG_IN_DATA = BIT(3), -}; - -struct ide_taskfile { - u8 data; /* 0: data byte (for TASKFILE ioctl) */ - union { /* 1: */ - u8 error; /* read: error */ - u8 feature; /* write: feature */ - }; - u8 nsect; /* 2: number of sectors */ - u8 lbal; /* 3: LBA low */ - u8 lbam; /* 4: LBA mid */ - u8 lbah; /* 5: LBA high */ - u8 device; /* 6: device select */ - union { /* 7: */ - u8 status; /* read: status */ - u8 command; /* write: command */ - }; -}; - -struct ide_cmd { - struct ide_taskfile tf; - struct ide_taskfile hob; - struct { - struct { - u8 tf; - u8 hob; - } out, in; - } valid; - - u16 tf_flags; - u8 ftf_flags; /* for TASKFILE ioctl */ - int protocol; - - int sg_nents; /* number of sg entries */ - int orig_sg_nents; - int sg_dma_direction; /* DMA transfer direction */ - - unsigned int nbytes; - unsigned int nleft; - unsigned int last_xfer_len; - - struct scatterlist *cursg; - unsigned int cursg_ofs; - - struct request *rq; /* copy of request */ -}; - -/* ATAPI packet command flags */ -enum { - /* set when an error is considered normal - no retry (ide-tape) */ - PC_FLAG_ABORT = BIT(0), - PC_FLAG_SUPPRESS_ERROR = BIT(1), - PC_FLAG_WAIT_FOR_DSC = BIT(2), - PC_FLAG_DMA_OK = BIT(3), - PC_FLAG_DMA_IN_PROGRESS = BIT(4), - PC_FLAG_DMA_ERROR = BIT(5), - PC_FLAG_WRITING = BIT(6), -}; - -#define ATAPI_WAIT_PC (60 * HZ) - -struct ide_atapi_pc { - /* actual packet bytes */ - u8 c[12]; - /* incremented on each retry */ - int retries; - int error; - - /* bytes to transfer */ - int req_xfer; - - /* the corresponding request */ - struct request *rq; - - unsigned long flags; - - /* - * those are more or less driver-specific and some of them are subject - * to change/removal later. - */ - unsigned long timeout; -}; - -struct ide_devset; -struct ide_driver; - -#ifdef CONFIG_BLK_DEV_IDEACPI -struct ide_acpi_drive_link; -struct ide_acpi_hwif_link; -#endif - -struct ide_drive_s; - -struct ide_disk_ops { - int (*check)(struct ide_drive_s *, const char *); - int (*get_capacity)(struct ide_drive_s *); - void (*unlock_native_capacity)(struct ide_drive_s *); - void (*setup)(struct ide_drive_s *); - void (*flush)(struct ide_drive_s *); - int (*init_media)(struct ide_drive_s *, struct gendisk *); - int (*set_doorlock)(struct ide_drive_s *, struct gendisk *, - int); - ide_startstop_t (*do_request)(struct ide_drive_s *, struct request *, - sector_t); - int (*ioctl)(struct ide_drive_s *, struct block_device *, - fmode_t, unsigned int, unsigned long); - int (*compat_ioctl)(struct ide_drive_s *, struct block_device *, - fmode_t, unsigned int, unsigned long); -}; - -/* ATAPI device flags */ -enum { - IDE_AFLAG_DRQ_INTERRUPT = BIT(0), - - /* ide-cd */ - /* Drive cannot eject the disc. */ - IDE_AFLAG_NO_EJECT = BIT(1), - /* Drive is a pre ATAPI 1.2 drive. */ - IDE_AFLAG_PRE_ATAPI12 = BIT(2), - /* TOC addresses are in BCD. */ - IDE_AFLAG_TOCADDR_AS_BCD = BIT(3), - /* TOC track numbers are in BCD. */ - IDE_AFLAG_TOCTRACKS_AS_BCD = BIT(4), - /* Saved TOC information is current. */ - IDE_AFLAG_TOC_VALID = BIT(6), - /* We think that the drive door is locked. */ - IDE_AFLAG_DOOR_LOCKED = BIT(7), - /* SET_CD_SPEED command is unsupported. */ - IDE_AFLAG_NO_SPEED_SELECT = BIT(8), - IDE_AFLAG_VERTOS_300_SSD = BIT(9), - IDE_AFLAG_VERTOS_600_ESD = BIT(10), - IDE_AFLAG_SANYO_3CD = BIT(11), - IDE_AFLAG_FULL_CAPS_PAGE = BIT(12), - IDE_AFLAG_PLAY_AUDIO_OK = BIT(13), - IDE_AFLAG_LE_SPEED_FIELDS = BIT(14), - - /* ide-floppy */ - /* Avoid commands not supported in Clik drive */ - IDE_AFLAG_CLIK_DRIVE = BIT(15), - /* Requires BH algorithm for packets */ - IDE_AFLAG_ZIP_DRIVE = BIT(16), - /* Supports format progress report */ - IDE_AFLAG_SRFP = BIT(17), - - /* ide-tape */ - IDE_AFLAG_IGNORE_DSC = BIT(18), - /* 0 When the tape position is unknown */ - IDE_AFLAG_ADDRESS_VALID = BIT(19), - /* Device already opened */ - IDE_AFLAG_BUSY = BIT(20), - /* Attempt to auto-detect the current user block size */ - IDE_AFLAG_DETECT_BS = BIT(21), - /* Currently on a filemark */ - IDE_AFLAG_FILEMARK = BIT(22), - /* 0 = no tape is loaded, so we don't rewind after ejecting */ - IDE_AFLAG_MEDIUM_PRESENT = BIT(23), - - IDE_AFLAG_NO_AUTOCLOSE = BIT(24), -}; - -/* device flags */ -enum { - /* restore settings after device reset */ - IDE_DFLAG_KEEP_SETTINGS = BIT(0), - /* device is using DMA for read/write */ - IDE_DFLAG_USING_DMA = BIT(1), - /* okay to unmask other IRQs */ - IDE_DFLAG_UNMASK = BIT(2), - /* don't attempt flushes */ - IDE_DFLAG_NOFLUSH = BIT(3), - /* DSC overlap */ - IDE_DFLAG_DSC_OVERLAP = BIT(4), - /* give potential excess bandwidth */ - IDE_DFLAG_NICE1 = BIT(5), - /* device is physically present */ - IDE_DFLAG_PRESENT = BIT(6), - /* disable Host Protected Area */ - IDE_DFLAG_NOHPA = BIT(7), - /* id read from device (synthetic if not set) */ - IDE_DFLAG_ID_READ = BIT(8), - IDE_DFLAG_NOPROBE = BIT(9), - /* need to do check_media_change() */ - IDE_DFLAG_REMOVABLE = BIT(10), - IDE_DFLAG_FORCED_GEOM = BIT(12), - /* disallow setting unmask bit */ - IDE_DFLAG_NO_UNMASK = BIT(13), - /* disallow enabling 32-bit I/O */ - IDE_DFLAG_NO_IO_32BIT = BIT(14), - /* for removable only: door lock/unlock works */ - IDE_DFLAG_DOORLOCKING = BIT(15), - /* disallow DMA */ - IDE_DFLAG_NODMA = BIT(16), - /* powermanagement told us not to do anything, so sleep nicely */ - IDE_DFLAG_BLOCKED = BIT(17), - /* sleeping & sleep field valid */ - IDE_DFLAG_SLEEPING = BIT(18), - IDE_DFLAG_POST_RESET = BIT(19), - IDE_DFLAG_UDMA33_WARNED = BIT(20), - IDE_DFLAG_LBA48 = BIT(21), - /* status of write cache */ - IDE_DFLAG_WCACHE = BIT(22), - /* used for ignoring ATA_DF */ - IDE_DFLAG_NOWERR = BIT(23), - /* retrying in PIO */ - IDE_DFLAG_DMA_PIO_RETRY = BIT(24), - IDE_DFLAG_LBA = BIT(25), - /* don't unload heads */ - IDE_DFLAG_NO_UNLOAD = BIT(26), - /* heads unloaded, please don't reset port */ - IDE_DFLAG_PARKED = BIT(27), - IDE_DFLAG_MEDIA_CHANGED = BIT(28), - /* write protect */ - IDE_DFLAG_WP = BIT(29), - IDE_DFLAG_FORMAT_IN_PROGRESS = BIT(30), - IDE_DFLAG_NIEN_QUIRK = BIT(31), -}; - -struct ide_drive_s { - char name[4]; /* drive name, such as "hda" */ - char driver_req[10]; /* requests specific driver */ - - struct request_queue *queue; /* request queue */ - - bool (*prep_rq)(struct ide_drive_s *, struct request *); - - struct blk_mq_tag_set tag_set; - - struct request *rq; /* current request */ - void *driver_data; /* extra driver data */ - u16 *id; /* identification info */ -#ifdef CONFIG_IDE_PROC_FS - struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ - const struct ide_proc_devset *settings; /* /proc/ide/ drive settings */ -#endif - struct hwif_s *hwif; /* actually (ide_hwif_t *) */ - - const struct ide_disk_ops *disk_ops; - - unsigned long dev_flags; - - unsigned long sleep; /* sleep until this time */ - unsigned long timeout; /* max time to wait for irq */ - - u8 special_flags; /* special action flags */ - - u8 select; /* basic drive/head select reg value */ - u8 retry_pio; /* retrying dma capable host in pio */ - u8 waiting_for_dma; /* dma currently in progress */ - u8 dma; /* atapi dma flag */ - - u8 init_speed; /* transfer rate set at boot */ - u8 current_speed; /* current transfer rate set */ - u8 desired_speed; /* desired transfer rate set */ - u8 pio_mode; /* for ->set_pio_mode _only_ */ - u8 dma_mode; /* for ->set_dma_mode _only_ */ - u8 dn; /* now wide spread use */ - u8 acoustic; /* acoustic management */ - u8 media; /* disk, cdrom, tape, floppy, ... */ - u8 ready_stat; /* min status value for drive ready */ - u8 mult_count; /* current multiple sector setting */ - u8 mult_req; /* requested multiple sector setting */ - u8 io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */ - u8 bad_wstat; /* used for ignoring ATA_DF */ - u8 head; /* "real" number of heads */ - u8 sect; /* "real" sectors per track */ - u8 bios_head; /* BIOS/fdisk/LILO number of heads */ - u8 bios_sect; /* BIOS/fdisk/LILO sectors per track */ - - /* delay this long before sending packet command */ - u8 pc_delay; - - unsigned int bios_cyl; /* BIOS/fdisk/LILO number of cyls */ - unsigned int cyl; /* "real" number of cyls */ - void *drive_data; /* used by set_pio_mode/dev_select() */ - unsigned int failures; /* current failure count */ - unsigned int max_failures; /* maximum allowed failure count */ - u64 probed_capacity;/* initial/native media capacity */ - u64 capacity64; /* total number of sectors */ - - int lun; /* logical unit */ - int crc_count; /* crc counter to reduce drive speed */ - - unsigned long debug_mask; /* debugging levels switch */ - -#ifdef CONFIG_BLK_DEV_IDEACPI - struct ide_acpi_drive_link *acpidata; -#endif - struct list_head list; - struct device gendev; - struct completion gendev_rel_comp; /* to deal with device release() */ - - /* current packet command */ - struct ide_atapi_pc *pc; - - /* last failed packet command */ - struct ide_atapi_pc *failed_pc; - - /* callback for packet commands */ - int (*pc_callback)(struct ide_drive_s *, int); - - ide_startstop_t (*irq_handler)(struct ide_drive_s *); - - unsigned long atapi_flags; - - struct ide_atapi_pc request_sense_pc; - - /* current sense rq and buffer */ - bool sense_rq_armed; - bool sense_rq_active; - struct request *sense_rq; - struct request_sense sense_data; - - /* async sense insertion */ - struct work_struct rq_work; - struct list_head rq_list; -}; - -typedef struct ide_drive_s ide_drive_t; - -#define to_ide_device(dev) container_of(dev, ide_drive_t, gendev) - -#define to_ide_drv(obj, cont_type) \ - container_of(obj, struct cont_type, dev) - -#define ide_drv_g(disk, cont_type) \ - container_of((disk)->private_data, struct cont_type, driver) - -struct ide_port_info; - -struct ide_tp_ops { - void (*exec_command)(struct hwif_s *, u8); - u8 (*read_status)(struct hwif_s *); - u8 (*read_altstatus)(struct hwif_s *); - void (*write_devctl)(struct hwif_s *, u8); - - void (*dev_select)(ide_drive_t *); - void (*tf_load)(ide_drive_t *, struct ide_taskfile *, u8); - void (*tf_read)(ide_drive_t *, struct ide_taskfile *, u8); - - void (*input_data)(ide_drive_t *, struct ide_cmd *, - void *, unsigned int); - void (*output_data)(ide_drive_t *, struct ide_cmd *, - void *, unsigned int); -}; - -extern const struct ide_tp_ops default_tp_ops; - -/** - * struct ide_port_ops - IDE port operations - * - * @init_dev: host specific initialization of a device - * @set_pio_mode: routine to program host for PIO mode - * @set_dma_mode: routine to program host for DMA mode - * @reset_poll: chipset polling based on hba specifics - * @pre_reset: chipset specific changes to default for device-hba resets - * @resetproc: routine to reset controller after a disk reset - * @maskproc: special host masking for drive selection - * @quirkproc: check host's drive quirk list - * @clear_irq: clear IRQ - * - * @mdma_filter: filter MDMA modes - * @udma_filter: filter UDMA modes - * - * @cable_detect: detect cable type - */ -struct ide_port_ops { - void (*init_dev)(ide_drive_t *); - void (*set_pio_mode)(struct hwif_s *, ide_drive_t *); - void (*set_dma_mode)(struct hwif_s *, ide_drive_t *); - blk_status_t (*reset_poll)(ide_drive_t *); - void (*pre_reset)(ide_drive_t *); - void (*resetproc)(ide_drive_t *); - void (*maskproc)(ide_drive_t *, int); - void (*quirkproc)(ide_drive_t *); - void (*clear_irq)(ide_drive_t *); - int (*test_irq)(struct hwif_s *); - - u8 (*mdma_filter)(ide_drive_t *); - u8 (*udma_filter)(ide_drive_t *); - - u8 (*cable_detect)(struct hwif_s *); -}; - -struct ide_dma_ops { - void (*dma_host_set)(struct ide_drive_s *, int); - int (*dma_setup)(struct ide_drive_s *, struct ide_cmd *); - void (*dma_start)(struct ide_drive_s *); - int (*dma_end)(struct ide_drive_s *); - int (*dma_test_irq)(struct ide_drive_s *); - void (*dma_lost_irq)(struct ide_drive_s *); - /* below ones are optional */ - int (*dma_check)(struct ide_drive_s *, struct ide_cmd *); - int (*dma_timer_expiry)(struct ide_drive_s *); - void (*dma_clear)(struct ide_drive_s *); - /* - * The following method is optional and only required to be - * implemented for the SFF-8038i compatible controllers. - */ - u8 (*dma_sff_read_status)(struct hwif_s *); -}; - -enum { - IDE_PFLAG_PROBING = BIT(0), -}; - -struct ide_host; - -typedef struct hwif_s { - struct hwif_s *mate; /* other hwif from same PCI chip */ - struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ - - struct ide_host *host; - - char name[6]; /* name of interface, eg. "ide0" */ - - struct ide_io_ports io_ports; - - unsigned long sata_scr[SATA_NR_PORTS]; - - ide_drive_t *devices[MAX_DRIVES + 1]; - - unsigned long port_flags; - - u8 major; /* our major number */ - u8 index; /* 0 for ide0; 1 for ide1; ... */ - u8 channel; /* for dual-port chips: 0=primary, 1=secondary */ - - u32 host_flags; - - u8 pio_mask; - - u8 ultra_mask; - u8 mwdma_mask; - u8 swdma_mask; - - u8 cbl; /* cable type */ - - hwif_chipset_t chipset; /* sub-module for tuning.. */ - - struct device *dev; - - void (*rw_disk)(ide_drive_t *, struct request *); - - const struct ide_tp_ops *tp_ops; - const struct ide_port_ops *port_ops; - const struct ide_dma_ops *dma_ops; - - /* dma physical region descriptor table (cpu view) */ - unsigned int *dmatable_cpu; - /* dma physical region descriptor table (dma view) */ - dma_addr_t dmatable_dma; - - /* maximum number of PRD table entries */ - int prd_max_nents; - /* PRD entry size in bytes */ - int prd_ent_size; - - /* Scatter-gather list used to build the above */ - struct scatterlist *sg_table; - int sg_max_nents; /* Maximum number of entries in it */ - - struct ide_cmd cmd; /* current command */ - - int rqsize; /* max sectors per request */ - int irq; /* our irq number */ - - unsigned long dma_base; /* base addr for dma ports */ - - unsigned long config_data; /* for use by chipset-specific code */ - unsigned long select_data; /* for use by chipset-specific code */ - - unsigned long extra_base; /* extra addr for dma ports */ - unsigned extra_ports; /* number of extra dma ports */ - - unsigned present : 1; /* this interface exists */ - unsigned busy : 1; /* serializes devices on a port */ - - struct device gendev; - struct device *portdev; - - struct completion gendev_rel_comp; /* To deal with device release() */ - - void *hwif_data; /* extra hwif data */ - -#ifdef CONFIG_BLK_DEV_IDEACPI - struct ide_acpi_hwif_link *acpidata; -#endif - - /* IRQ handler, if active */ - ide_startstop_t (*handler)(ide_drive_t *); - - /* BOOL: polling active & poll_timeout field valid */ - unsigned int polling : 1; - - /* current drive */ - ide_drive_t *cur_dev; - - /* current request */ - struct request *rq; - - /* failsafe timer */ - struct timer_list timer; - /* timeout value during long polls */ - unsigned long poll_timeout; - /* queried upon timeouts */ - int (*expiry)(ide_drive_t *); - - int req_gen; - int req_gen_timer; - - spinlock_t lock; -} ____cacheline_internodealigned_in_smp ide_hwif_t; - -#define MAX_HOST_PORTS 4 - -struct ide_host { - ide_hwif_t *ports[MAX_HOST_PORTS + 1]; - unsigned int n_ports; - struct device *dev[2]; - - int (*init_chipset)(struct pci_dev *); - - void (*get_lock)(irq_handler_t, void *); - void (*release_lock)(void); - - irq_handler_t irq_handler; - - unsigned long host_flags; - - int irq_flags; - - void *host_priv; - ide_hwif_t *cur_port; /* for hosts requiring serialization */ - - /* used for hosts requiring serialization */ - volatile unsigned long host_busy; -}; - -#define IDE_HOST_BUSY 0 - -/* - * internal ide interrupt handler type - */ -typedef ide_startstop_t (ide_handler_t)(ide_drive_t *); -typedef int (ide_expiry_t)(ide_drive_t *); - -/* used by ide-cd, ide-floppy, etc. */ -typedef void (xfer_func_t)(ide_drive_t *, struct ide_cmd *, void *, unsigned); - -extern struct mutex ide_setting_mtx; - -/* - * configurable drive settings - */ - -#define DS_SYNC BIT(0) - -struct ide_devset { - int (*get)(ide_drive_t *); - int (*set)(ide_drive_t *, int); - unsigned int flags; -}; - -#define __DEVSET(_flags, _get, _set) { \ - .flags = _flags, \ - .get = _get, \ - .set = _set, \ -} - -#define ide_devset_get(name, field) \ -static int get_##name(ide_drive_t *drive) \ -{ \ - return drive->field; \ -} - -#define ide_devset_set(name, field) \ -static int set_##name(ide_drive_t *drive, int arg) \ -{ \ - drive->field = arg; \ - return 0; \ -} - -#define ide_devset_get_flag(name, flag) \ -static int get_##name(ide_drive_t *drive) \ -{ \ - return !!(drive->dev_flags & flag); \ -} - -#define ide_devset_set_flag(name, flag) \ -static int set_##name(ide_drive_t *drive, int arg) \ -{ \ - if (arg) \ - drive->dev_flags |= flag; \ - else \ - drive->dev_flags &= ~flag; \ - return 0; \ -} - -#define __IDE_DEVSET(_name, _flags, _get, _set) \ -const struct ide_devset ide_devset_##_name = \ - __DEVSET(_flags, _get, _set) - -#define IDE_DEVSET(_name, _flags, _get, _set) \ -static __IDE_DEVSET(_name, _flags, _get, _set) - -#define ide_devset_rw(_name, _func) \ -IDE_DEVSET(_name, 0, get_##_func, set_##_func) - -#define ide_devset_w(_name, _func) \ -IDE_DEVSET(_name, 0, NULL, set_##_func) - -#define ide_ext_devset_rw(_name, _func) \ -__IDE_DEVSET(_name, 0, get_##_func, set_##_func) - -#define ide_ext_devset_rw_sync(_name, _func) \ -__IDE_DEVSET(_name, DS_SYNC, get_##_func, set_##_func) - -#define ide_decl_devset(_name) \ -extern const struct ide_devset ide_devset_##_name - -ide_decl_devset(io_32bit); -ide_decl_devset(keepsettings); -ide_decl_devset(pio_mode); -ide_decl_devset(unmaskirq); -ide_decl_devset(using_dma); - -#ifdef CONFIG_IDE_PROC_FS -/* - * /proc/ide interface - */ - -#define ide_devset_rw_field(_name, _field) \ -ide_devset_get(_name, _field); \ -ide_devset_set(_name, _field); \ -IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name) - -#define ide_devset_ro_field(_name, _field) \ -ide_devset_get(_name, _field); \ -IDE_DEVSET(_name, 0, get_##_name, NULL) - -#define ide_devset_rw_flag(_name, _field) \ -ide_devset_get_flag(_name, _field); \ -ide_devset_set_flag(_name, _field); \ -IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name) - -struct ide_proc_devset { - const char *name; - const struct ide_devset *setting; - int min, max; - int (*mulf)(ide_drive_t *); - int (*divf)(ide_drive_t *); -}; - -#define __IDE_PROC_DEVSET(_name, _min, _max, _mulf, _divf) { \ - .name = __stringify(_name), \ - .setting = &ide_devset_##_name, \ - .min = _min, \ - .max = _max, \ - .mulf = _mulf, \ - .divf = _divf, \ -} - -#define IDE_PROC_DEVSET(_name, _min, _max) \ -__IDE_PROC_DEVSET(_name, _min, _max, NULL, NULL) - -typedef struct { - const char *name; - umode_t mode; - int (*show)(struct seq_file *, void *); -} ide_proc_entry_t; - -void proc_ide_create(void); -void proc_ide_destroy(void); -void ide_proc_register_port(ide_hwif_t *); -void ide_proc_port_register_devices(ide_hwif_t *); -void ide_proc_unregister_device(ide_drive_t *); -void ide_proc_unregister_port(ide_hwif_t *); -void ide_proc_register_driver(ide_drive_t *, struct ide_driver *); -void ide_proc_unregister_driver(ide_drive_t *, struct ide_driver *); - -int ide_capacity_proc_show(struct seq_file *m, void *v); -int ide_geometry_proc_show(struct seq_file *m, void *v); -#else -static inline void proc_ide_create(void) { ; } -static inline void proc_ide_destroy(void) { ; } -static inline void ide_proc_register_port(ide_hwif_t *hwif) { ; } -static inline void ide_proc_port_register_devices(ide_hwif_t *hwif) { ; } -static inline void ide_proc_unregister_device(ide_drive_t *drive) { ; } -static inline void ide_proc_unregister_port(ide_hwif_t *hwif) { ; } -static inline void ide_proc_register_driver(ide_drive_t *drive, - struct ide_driver *driver) { ; } -static inline void ide_proc_unregister_driver(ide_drive_t *drive, - struct ide_driver *driver) { ; } -#endif - -enum { - /* enter/exit functions */ - IDE_DBG_FUNC = BIT(0), - /* sense key/asc handling */ - IDE_DBG_SENSE = BIT(1), - /* packet commands handling */ - IDE_DBG_PC = BIT(2), - /* request handling */ - IDE_DBG_RQ = BIT(3), - /* driver probing/setup */ - IDE_DBG_PROBE = BIT(4), -}; - -/* DRV_NAME has to be defined in the driver before using the macro below */ -#define __ide_debug_log(lvl, fmt, args...) \ -{ \ - if (unlikely(drive->debug_mask & lvl)) \ - printk(KERN_INFO DRV_NAME ": %s: " fmt "\n", \ - __func__, ## args); \ -} - -/* - * Power Management state machine (rq->pm->pm_step). - * - * For each step, the core calls ide_start_power_step() first. - * This can return: - * - ide_stopped : In this case, the core calls us back again unless - * step have been set to ide_power_state_completed. - * - ide_started : In this case, the channel is left busy until an - * async event (interrupt) occurs. - * Typically, ide_start_power_step() will issue a taskfile request with - * do_rw_taskfile(). - * - * Upon reception of the interrupt, the core will call ide_complete_power_step() - * with the error code if any. This routine should update the step value - * and return. It should not start a new request. The core will call - * ide_start_power_step() for the new step value, unless step have been - * set to IDE_PM_COMPLETED. - */ -enum { - IDE_PM_START_SUSPEND, - IDE_PM_FLUSH_CACHE = IDE_PM_START_SUSPEND, - IDE_PM_STANDBY, - - IDE_PM_START_RESUME, - IDE_PM_RESTORE_PIO = IDE_PM_START_RESUME, - IDE_PM_IDLE, - IDE_PM_RESTORE_DMA, - - IDE_PM_COMPLETED, -}; - -int generic_ide_suspend(struct device *, pm_message_t); -int generic_ide_resume(struct device *); - -void ide_complete_power_step(ide_drive_t *, struct request *); -ide_startstop_t ide_start_power_step(ide_drive_t *, struct request *); -void ide_complete_pm_rq(ide_drive_t *, struct request *); -void ide_check_pm_state(ide_drive_t *, struct request *); - -/* - * Subdrivers support. - * - * The gendriver.owner field should be set to the module owner of this driver. - * The gendriver.name field should be set to the name of this driver - */ -struct ide_driver { - const char *version; - ide_startstop_t (*do_request)(ide_drive_t *, struct request *, sector_t); - struct device_driver gen_driver; - int (*probe)(ide_drive_t *); - void (*remove)(ide_drive_t *); - void (*resume)(ide_drive_t *); - void (*shutdown)(ide_drive_t *); -#ifdef CONFIG_IDE_PROC_FS - ide_proc_entry_t * (*proc_entries)(ide_drive_t *); - const struct ide_proc_devset * (*proc_devsets)(ide_drive_t *); -#endif -}; - -#define to_ide_driver(drv) container_of(drv, struct ide_driver, gen_driver) - -int ide_device_get(ide_drive_t *); -void ide_device_put(ide_drive_t *); - -struct ide_ioctl_devset { - unsigned int get_ioctl; - unsigned int set_ioctl; - const struct ide_devset *setting; -}; - -int ide_setting_ioctl(ide_drive_t *, struct block_device *, unsigned int, - unsigned long, const struct ide_ioctl_devset *); - -int generic_ide_ioctl(ide_drive_t *, struct block_device *, unsigned, unsigned long); - -extern int ide_vlb_clk; -extern int ide_pci_clk; - -int ide_end_rq(ide_drive_t *, struct request *, blk_status_t, unsigned int); -void ide_kill_rq(ide_drive_t *, struct request *); -void ide_insert_request_head(ide_drive_t *, struct request *); - -void __ide_set_handler(ide_drive_t *, ide_handler_t *, unsigned int); -void ide_set_handler(ide_drive_t *, ide_handler_t *, unsigned int); - -void ide_execute_command(ide_drive_t *, struct ide_cmd *, ide_handler_t *, - unsigned int); - -void ide_pad_transfer(ide_drive_t *, int, int); - -ide_startstop_t ide_error(ide_drive_t *, const char *, u8); - -void ide_fix_driveid(u16 *); - -extern void ide_fixstring(u8 *, const int, const int); - -int ide_busy_sleep(ide_drive_t *, unsigned long, int); - -int __ide_wait_stat(ide_drive_t *, u8, u8, unsigned long, u8 *); -int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long); - -ide_startstop_t ide_do_park_unpark(ide_drive_t *, struct request *); -ide_startstop_t ide_do_devset(ide_drive_t *, struct request *); - -extern ide_startstop_t ide_do_reset (ide_drive_t *); - -extern int ide_devset_execute(ide_drive_t *drive, - const struct ide_devset *setting, int arg); - -void ide_complete_cmd(ide_drive_t *, struct ide_cmd *, u8, u8); -int ide_complete_rq(ide_drive_t *, blk_status_t, unsigned int); - -void ide_tf_readback(ide_drive_t *drive, struct ide_cmd *cmd); -void ide_tf_dump(const char *, struct ide_cmd *); - -void ide_exec_command(ide_hwif_t *, u8); -u8 ide_read_status(ide_hwif_t *); -u8 ide_read_altstatus(ide_hwif_t *); -void ide_write_devctl(ide_hwif_t *, u8); - -void ide_dev_select(ide_drive_t *); -void ide_tf_load(ide_drive_t *, struct ide_taskfile *, u8); -void ide_tf_read(ide_drive_t *, struct ide_taskfile *, u8); - -void ide_input_data(ide_drive_t *, struct ide_cmd *, void *, unsigned int); -void ide_output_data(ide_drive_t *, struct ide_cmd *, void *, unsigned int); - -void SELECT_MASK(ide_drive_t *, int); - -u8 ide_read_error(ide_drive_t *); -void ide_read_bcount_and_ireason(ide_drive_t *, u16 *, u8 *); - -int ide_check_ireason(ide_drive_t *, struct request *, int, int, int); - -int ide_check_atapi_device(ide_drive_t *, const char *); - -void ide_init_pc(struct ide_atapi_pc *); - -/* Disk head parking */ -extern wait_queue_head_t ide_park_wq; -ssize_t ide_park_show(struct device *dev, struct device_attribute *attr, - char *buf); -ssize_t ide_park_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len); - -/* - * Special requests for ide-tape block device strategy routine. - * - * In order to service a character device command, we add special requests to - * the tail of our block device request queue and wait for their completion. - */ -enum { - REQ_IDETAPE_PC1 = BIT(0), /* packet command (first stage) */ - REQ_IDETAPE_PC2 = BIT(1), /* packet command (second stage) */ - REQ_IDETAPE_READ = BIT(2), - REQ_IDETAPE_WRITE = BIT(3), -}; - -int ide_queue_pc_tail(ide_drive_t *, struct gendisk *, struct ide_atapi_pc *, - void *, unsigned int); - -int ide_do_test_unit_ready(ide_drive_t *, struct gendisk *); -int ide_do_start_stop(ide_drive_t *, struct gendisk *, int); -int ide_set_media_lock(ide_drive_t *, struct gendisk *, int); -void ide_create_request_sense_cmd(ide_drive_t *, struct ide_atapi_pc *); -void ide_retry_pc(ide_drive_t *drive); - -void ide_prep_sense(ide_drive_t *drive, struct request *rq); -int ide_queue_sense_rq(ide_drive_t *drive, void *special); - -int ide_cd_expiry(ide_drive_t *); - -int ide_cd_get_xferlen(struct request *); - -ide_startstop_t ide_issue_pc(ide_drive_t *, struct ide_cmd *); - -ide_startstop_t do_rw_taskfile(ide_drive_t *, struct ide_cmd *); - -void ide_pio_bytes(ide_drive_t *, struct ide_cmd *, unsigned int, unsigned int); - -void ide_finish_cmd(ide_drive_t *, struct ide_cmd *, u8); - -int ide_raw_taskfile(ide_drive_t *, struct ide_cmd *, u8 *, u16); -int ide_no_data_taskfile(ide_drive_t *, struct ide_cmd *); - -int ide_taskfile_ioctl(ide_drive_t *, unsigned long); - -int ide_dev_read_id(ide_drive_t *, u8, u16 *, int); - -extern int ide_driveid_update(ide_drive_t *); -extern int ide_config_drive_speed(ide_drive_t *, u8); -extern u8 eighty_ninty_three (ide_drive_t *); -extern int taskfile_lib_get_identify(ide_drive_t *drive, u8 *); - -extern int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout); - -extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout); - -extern void ide_timer_expiry(struct timer_list *t); -extern irqreturn_t ide_intr(int irq, void *dev_id); -extern blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *, const struct blk_mq_queue_data *); -extern blk_status_t ide_issue_rq(ide_drive_t *, struct request *, bool); -extern void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq); - -void ide_init_disk(struct gendisk *, ide_drive_t *); - -#ifdef CONFIG_IDEPCI_PCIBUS_ORDER -extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner, const char *mod_name); -#define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE, KBUILD_MODNAME) -#else -#define ide_pci_register_driver(d) pci_register_driver(d) -#endif - -static inline int ide_pci_is_in_compatibility_mode(struct pci_dev *dev) -{ - if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 5) != 5) - return 1; - return 0; -} - -void ide_pci_setup_ports(struct pci_dev *, const struct ide_port_info *, - struct ide_hw *, struct ide_hw **); -void ide_setup_pci_noise(struct pci_dev *, const struct ide_port_info *); - -#ifdef CONFIG_BLK_DEV_IDEDMA_PCI -int ide_pci_set_master(struct pci_dev *, const char *); -unsigned long ide_pci_dma_base(ide_hwif_t *, const struct ide_port_info *); -int ide_pci_check_simplex(ide_hwif_t *, const struct ide_port_info *); -int ide_hwif_setup_dma(ide_hwif_t *, const struct ide_port_info *); -#else -static inline int ide_hwif_setup_dma(ide_hwif_t *hwif, - const struct ide_port_info *d) -{ - return -EINVAL; -} -#endif - -struct ide_pci_enablebit { - u8 reg; /* byte pci reg holding the enable-bit */ - u8 mask; /* mask to isolate the enable-bit */ - u8 val; /* value of masked reg when "enabled" */ -}; - -enum { - /* Uses ISA control ports not PCI ones. */ - IDE_HFLAG_ISA_PORTS = BIT(0), - /* single port device */ - IDE_HFLAG_SINGLE = BIT(1), - /* don't use legacy PIO blacklist */ - IDE_HFLAG_PIO_NO_BLACKLIST = BIT(2), - /* set for the second port of QD65xx */ - IDE_HFLAG_QD_2ND_PORT = BIT(3), - /* use PIO8/9 for prefetch off/on */ - IDE_HFLAG_ABUSE_PREFETCH = BIT(4), - /* use PIO6/7 for fast-devsel off/on */ - IDE_HFLAG_ABUSE_FAST_DEVSEL = BIT(5), - /* use 100-102 and 200-202 PIO values to set DMA modes */ - IDE_HFLAG_ABUSE_DMA_MODES = BIT(6), - /* - * keep DMA setting when programming PIO mode, may be used only - * for hosts which have separate PIO and DMA timings (ie. PMAC) - */ - IDE_HFLAG_SET_PIO_MODE_KEEP_DMA = BIT(7), - /* program host for the transfer mode after programming device */ - IDE_HFLAG_POST_SET_MODE = BIT(8), - /* don't program host/device for the transfer mode ("smart" hosts) */ - IDE_HFLAG_NO_SET_MODE = BIT(9), - /* trust BIOS for programming chipset/device for DMA */ - IDE_HFLAG_TRUST_BIOS_FOR_DMA = BIT(10), - /* host is CS5510/CS5520 */ - IDE_HFLAG_CS5520 = BIT(11), - /* ATAPI DMA is unsupported */ - IDE_HFLAG_NO_ATAPI_DMA = BIT(12), - /* set if host is a "non-bootable" controller */ - IDE_HFLAG_NON_BOOTABLE = BIT(13), - /* host doesn't support DMA */ - IDE_HFLAG_NO_DMA = BIT(14), - /* check if host is PCI IDE device before allowing DMA */ - IDE_HFLAG_NO_AUTODMA = BIT(15), - /* host uses MMIO */ - IDE_HFLAG_MMIO = BIT(16), - /* no LBA48 */ - IDE_HFLAG_NO_LBA48 = BIT(17), - /* no LBA48 DMA */ - IDE_HFLAG_NO_LBA48_DMA = BIT(18), - /* data FIFO is cleared by an error */ - IDE_HFLAG_ERROR_STOPS_FIFO = BIT(19), - /* serialize ports */ - IDE_HFLAG_SERIALIZE = BIT(20), - /* host is DTC2278 */ - IDE_HFLAG_DTC2278 = BIT(21), - /* 4 devices on a single set of I/O ports */ - IDE_HFLAG_4DRIVES = BIT(22), - /* host is TRM290 */ - IDE_HFLAG_TRM290 = BIT(23), - /* use 32-bit I/O ops */ - IDE_HFLAG_IO_32BIT = BIT(24), - /* unmask IRQs */ - IDE_HFLAG_UNMASK_IRQS = BIT(25), - IDE_HFLAG_BROKEN_ALTSTATUS = BIT(26), - /* serialize ports if DMA is possible (for sl82c105) */ - IDE_HFLAG_SERIALIZE_DMA = BIT(27), - /* force host out of "simplex" mode */ - IDE_HFLAG_CLEAR_SIMPLEX = BIT(28), - /* DSC overlap is unsupported */ - IDE_HFLAG_NO_DSC = BIT(29), - /* never use 32-bit I/O ops */ - IDE_HFLAG_NO_IO_32BIT = BIT(30), - /* never unmask IRQs */ - IDE_HFLAG_NO_UNMASK_IRQS = BIT(31), -}; - -#ifdef CONFIG_BLK_DEV_OFFBOARD -# define IDE_HFLAG_OFF_BOARD 0 -#else -# define IDE_HFLAG_OFF_BOARD IDE_HFLAG_NON_BOOTABLE -#endif - -struct ide_port_info { - char *name; - - int (*init_chipset)(struct pci_dev *); - - void (*get_lock)(irq_handler_t, void *); - void (*release_lock)(void); - - void (*init_iops)(ide_hwif_t *); - void (*init_hwif)(ide_hwif_t *); - int (*init_dma)(ide_hwif_t *, - const struct ide_port_info *); - - const struct ide_tp_ops *tp_ops; - const struct ide_port_ops *port_ops; - const struct ide_dma_ops *dma_ops; - - struct ide_pci_enablebit enablebits[2]; - - hwif_chipset_t chipset; - - u16 max_sectors; /* if < than the default one */ - - u32 host_flags; - - int irq_flags; - - u8 pio_mask; - u8 swdma_mask; - u8 mwdma_mask; - u8 udma_mask; -}; - -/* - * State information carried for REQ_TYPE_ATA_PM_SUSPEND and REQ_TYPE_ATA_PM_RESUME - * requests. - */ -struct ide_pm_state { - /* PM state machine step value, currently driver specific */ - int pm_step; - /* requested PM state value (S1, S2, S3, S4, ...) */ - u32 pm_state; - void* data; /* for driver use */ -}; - - -int ide_pci_init_one(struct pci_dev *, const struct ide_port_info *, void *); -int ide_pci_init_two(struct pci_dev *, struct pci_dev *, - const struct ide_port_info *, void *); -void ide_pci_remove(struct pci_dev *); - -#ifdef CONFIG_PM -int ide_pci_suspend(struct pci_dev *, pm_message_t); -int ide_pci_resume(struct pci_dev *); -#else -#define ide_pci_suspend NULL -#define ide_pci_resume NULL -#endif - -void ide_map_sg(ide_drive_t *, struct ide_cmd *); -void ide_init_sg_cmd(struct ide_cmd *, unsigned int); - -#define BAD_DMA_DRIVE 0 -#define GOOD_DMA_DRIVE 1 - -struct drive_list_entry { - const char *id_model; - const char *id_firmware; -}; - -int ide_in_drive_list(u16 *, const struct drive_list_entry *); - -#ifdef CONFIG_BLK_DEV_IDEDMA -int ide_dma_good_drive(ide_drive_t *); -int __ide_dma_bad_drive(ide_drive_t *); - -u8 ide_find_dma_mode(ide_drive_t *, u8); - -static inline u8 ide_max_dma_mode(ide_drive_t *drive) -{ - return ide_find_dma_mode(drive, XFER_UDMA_6); -} - -void ide_dma_off_quietly(ide_drive_t *); -void ide_dma_off(ide_drive_t *); -void ide_dma_on(ide_drive_t *); -int ide_set_dma(ide_drive_t *); -void ide_check_dma_crc(ide_drive_t *); -ide_startstop_t ide_dma_intr(ide_drive_t *); - -int ide_allocate_dma_engine(ide_hwif_t *); -void ide_release_dma_engine(ide_hwif_t *); - -int ide_dma_prepare(ide_drive_t *, struct ide_cmd *); -void ide_dma_unmap_sg(ide_drive_t *, struct ide_cmd *); - -#ifdef CONFIG_BLK_DEV_IDEDMA_SFF -int config_drive_for_dma(ide_drive_t *); -int ide_build_dmatable(ide_drive_t *, struct ide_cmd *); -void ide_dma_host_set(ide_drive_t *, int); -int ide_dma_setup(ide_drive_t *, struct ide_cmd *); -extern void ide_dma_start(ide_drive_t *); -int ide_dma_end(ide_drive_t *); -int ide_dma_test_irq(ide_drive_t *); -int ide_dma_sff_timer_expiry(ide_drive_t *); -u8 ide_dma_sff_read_status(ide_hwif_t *); -extern const struct ide_dma_ops sff_dma_ops; -#else -static inline int config_drive_for_dma(ide_drive_t *drive) { return 0; } -#endif /* CONFIG_BLK_DEV_IDEDMA_SFF */ - -void ide_dma_lost_irq(ide_drive_t *); -ide_startstop_t ide_dma_timeout_retry(ide_drive_t *, int); - -#else -static inline u8 ide_find_dma_mode(ide_drive_t *drive, u8 speed) { return 0; } -static inline u8 ide_max_dma_mode(ide_drive_t *drive) { return 0; } -static inline void ide_dma_off_quietly(ide_drive_t *drive) { ; } -static inline void ide_dma_off(ide_drive_t *drive) { ; } -static inline void ide_dma_on(ide_drive_t *drive) { ; } -static inline void ide_dma_verbose(ide_drive_t *drive) { ; } -static inline int ide_set_dma(ide_drive_t *drive) { return 1; } -static inline void ide_check_dma_crc(ide_drive_t *drive) { ; } -static inline ide_startstop_t ide_dma_intr(ide_drive_t *drive) { return ide_stopped; } -static inline ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) { return ide_stopped; } -static inline void ide_release_dma_engine(ide_hwif_t *hwif) { ; } -static inline int ide_dma_prepare(ide_drive_t *drive, - struct ide_cmd *cmd) { return 1; } -static inline void ide_dma_unmap_sg(ide_drive_t *drive, - struct ide_cmd *cmd) { ; } -#endif /* CONFIG_BLK_DEV_IDEDMA */ - -#ifdef CONFIG_BLK_DEV_IDEACPI -int ide_acpi_init(void); -bool ide_port_acpi(ide_hwif_t *hwif); -extern int ide_acpi_exec_tfs(ide_drive_t *drive); -extern void ide_acpi_get_timing(ide_hwif_t *hwif); -extern void ide_acpi_push_timing(ide_hwif_t *hwif); -void ide_acpi_init_port(ide_hwif_t *); -void ide_acpi_port_init_devices(ide_hwif_t *); -extern void ide_acpi_set_state(ide_hwif_t *hwif, int on); -#else -static inline int ide_acpi_init(void) { return 0; } -static inline bool ide_port_acpi(ide_hwif_t *hwif) { return 0; } -static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; } -static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; } -static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; } -static inline void ide_acpi_init_port(ide_hwif_t *hwif) { ; } -static inline void ide_acpi_port_init_devices(ide_hwif_t *hwif) { ; } -static inline void ide_acpi_set_state(ide_hwif_t *hwif, int on) {} -#endif - -void ide_check_nien_quirk_list(ide_drive_t *); -void ide_undecoded_slave(ide_drive_t *); - -void ide_port_apply_params(ide_hwif_t *); -int ide_sysfs_register_port(ide_hwif_t *); - -struct ide_host *ide_host_alloc(const struct ide_port_info *, struct ide_hw **, - unsigned int); -void ide_host_free(struct ide_host *); -int ide_host_register(struct ide_host *, const struct ide_port_info *, - struct ide_hw **); -int ide_host_add(const struct ide_port_info *, struct ide_hw **, unsigned int, - struct ide_host **); -void ide_host_remove(struct ide_host *); -int ide_legacy_device_add(const struct ide_port_info *, unsigned long); -void ide_port_unregister_devices(ide_hwif_t *); -void ide_port_scan(ide_hwif_t *); - -static inline void *ide_get_hwifdata (ide_hwif_t * hwif) -{ - return hwif->hwif_data; -} - -static inline void ide_set_hwifdata (ide_hwif_t * hwif, void *data) -{ - hwif->hwif_data = data; -} - -u64 ide_get_lba_addr(struct ide_cmd *, int); -u8 ide_dump_status(ide_drive_t *, const char *, u8); - -struct ide_timing { - u8 mode; - u8 setup; /* t1 */ - u16 act8b; /* t2 for 8-bit io */ - u16 rec8b; /* t2i for 8-bit io */ - u16 cyc8b; /* t0 for 8-bit io */ - u16 active; /* t2 or tD */ - u16 recover; /* t2i or tK */ - u16 cycle; /* t0 */ - u16 udma; /* t2CYCTYP/2 */ -}; - -enum { - IDE_TIMING_SETUP = BIT(0), - IDE_TIMING_ACT8B = BIT(1), - IDE_TIMING_REC8B = BIT(2), - IDE_TIMING_CYC8B = BIT(3), - IDE_TIMING_8BIT = IDE_TIMING_ACT8B | IDE_TIMING_REC8B | - IDE_TIMING_CYC8B, - IDE_TIMING_ACTIVE = BIT(4), - IDE_TIMING_RECOVER = BIT(5), - IDE_TIMING_CYCLE = BIT(6), - IDE_TIMING_UDMA = BIT(7), - IDE_TIMING_ALL = IDE_TIMING_SETUP | IDE_TIMING_8BIT | - IDE_TIMING_ACTIVE | IDE_TIMING_RECOVER | - IDE_TIMING_CYCLE | IDE_TIMING_UDMA, -}; - -struct ide_timing *ide_timing_find_mode(u8); -u16 ide_pio_cycle_time(ide_drive_t *, u8); -void ide_timing_merge(struct ide_timing *, struct ide_timing *, - struct ide_timing *, unsigned int); -int ide_timing_compute(ide_drive_t *, u8, struct ide_timing *, int, int); - -#ifdef CONFIG_IDE_XFER_MODE -int ide_scan_pio_blacklist(char *); -const char *ide_xfer_verbose(u8); -int ide_pio_need_iordy(ide_drive_t *, const u8); -int ide_set_pio_mode(ide_drive_t *, u8); -int ide_set_dma_mode(ide_drive_t *, u8); -void ide_set_pio(ide_drive_t *, u8); -int ide_set_xfer_rate(ide_drive_t *, u8); -#else -static inline void ide_set_pio(ide_drive_t *drive, u8 pio) { ; } -static inline int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) { return -1; } -#endif - -static inline void ide_set_max_pio(ide_drive_t *drive) -{ - ide_set_pio(drive, 255); -} - -char *ide_media_string(ide_drive_t *); - -extern const struct attribute_group *ide_dev_groups[]; -extern struct bus_type ide_bus_type; -extern struct class *ide_port_class; - -static inline void ide_dump_identify(u8 *id) -{ - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 2, id, 512, 0); -} - -static inline int hwif_to_node(ide_hwif_t *hwif) -{ - return hwif->dev ? dev_to_node(hwif->dev) : -1; -} - -static inline ide_drive_t *ide_get_pair_dev(ide_drive_t *drive) -{ - ide_drive_t *peer = drive->hwif->devices[(drive->dn ^ 1) & 1]; - - return (peer->dev_flags & IDE_DFLAG_PRESENT) ? peer : NULL; -} - -static inline void *ide_get_drivedata(ide_drive_t *drive) -{ - return drive->drive_data; -} - -static inline void ide_set_drivedata(ide_drive_t *drive, void *data) -{ - drive->drive_data = data; -} - -#define ide_port_for_each_dev(i, dev, port) \ - for ((i) = 0; ((dev) = (port)->devices[i]) || (i) < MAX_DRIVES; (i)++) - -#define ide_port_for_each_present_dev(i, dev, port) \ - for ((i) = 0; ((dev) = (port)->devices[i]) || (i) < MAX_DRIVES; (i)++) \ - if ((dev)->dev_flags & IDE_DFLAG_PRESENT) - -#define ide_host_for_each_port(i, port, host) \ - for ((i) = 0; ((port) = (host)->ports[i]) || (i) < MAX_HOST_PORTS; (i)++) - - -#endif /* _IDE_H */ -- cgit v1.3.1 From 8669dbab2ae56085c128894b181c2aa50f97e368 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 15 Jun 2021 18:23:19 -0700 Subject: mm/slub: clarify verification reporting Patch series "Actually fix freelist pointer vs redzoning", v4. This fixes redzoning vs the freelist pointer (both for middle-position and very small caches). Both are "theoretical" fixes, in that I see no evidence of such small-sized caches actually be used in the kernel, but that's no reason to let the bugs continue to exist, especially since people doing local development keep tripping over it. :) This patch (of 3): Instead of repeating "Redzone" and "Poison", clarify which sides of those zones got tripped. Additionally fix column alignment in the trailer. Before: BUG test (Tainted: G B ): Redzone overwritten ... Redzone (____ptrval____): bb bb bb bb bb bb bb bb ........ Object (____ptrval____): f6 f4 a5 40 1d e8 ...@.. Redzone (____ptrval____): 1a aa .. Padding (____ptrval____): 00 00 00 00 00 00 00 00 ........ After: BUG test (Tainted: G B ): Right Redzone overwritten ... Redzone (____ptrval____): bb bb bb bb bb bb bb bb ........ Object (____ptrval____): f6 f4 a5 40 1d e8 ...@.. Redzone (____ptrval____): 1a aa .. Padding (____ptrval____): 00 00 00 00 00 00 00 00 ........ The earlier commits that slowly resulted in the "Before" reporting were: d86bd1bece6f ("mm/slub: support left redzone") ffc79d288000 ("slub: use print_hex_dump") 2492268472e7 ("SLUB: change error reporting format to follow lockdep loosely") Link: https://lkml.kernel.org/r/20210608183955.280836-1-keescook@chromium.org Link: https://lkml.kernel.org/r/20210608183955.280836-2-keescook@chromium.org Link: https://lore.kernel.org/lkml/cfdb11d7-fb8e-e578-c939-f7f5fb69a6bd@suse.cz/ Signed-off-by: Kees Cook Acked-by: Vlastimil Babka Cc: Marco Elver Cc: "Lin, Zhenpeng" Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Cc: Roman Gushchin Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/slub.rst | 10 +++++----- mm/slub.c | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/vm/slub.rst b/Documentation/vm/slub.rst index 03f294a638bd..d3028554b1e9 100644 --- a/Documentation/vm/slub.rst +++ b/Documentation/vm/slub.rst @@ -181,7 +181,7 @@ SLUB Debug output Here is a sample of slub debug output:: ==================================================================== - BUG kmalloc-8: Redzone overwritten + BUG kmalloc-8: Right Redzone overwritten -------------------------------------------------------------------- INFO: 0xc90f6d28-0xc90f6d2b. First byte 0x00 instead of 0xcc @@ -189,10 +189,10 @@ Here is a sample of slub debug output:: INFO: Object 0xc90f6d20 @offset=3360 fp=0xc90f6d58 INFO: Allocated in get_modalias+0x61/0xf5 age=53 cpu=1 pid=554 - Bytes b4 0xc90f6d10: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ - Object 0xc90f6d20: 31 30 31 39 2e 30 30 35 1019.005 - Redzone 0xc90f6d28: 00 cc cc cc . - Padding 0xc90f6d50: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ + Bytes b4 (0xc90f6d10): 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ + Object (0xc90f6d20): 31 30 31 39 2e 30 30 35 1019.005 + Redzone (0xc90f6d28): 00 cc cc cc . + Padding (0xc90f6d50): 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ [] dump_trace+0x63/0x1eb [] show_trace_log_lvl+0x1a/0x2f diff --git a/mm/slub.c b/mm/slub.c index 3f96e099817a..f91d9fe7d0d8 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -712,15 +712,15 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p) p, p - addr, get_freepointer(s, p)); if (s->flags & SLAB_RED_ZONE) - print_section(KERN_ERR, "Redzone ", p - s->red_left_pad, + print_section(KERN_ERR, "Redzone ", p - s->red_left_pad, s->red_left_pad); else if (p > addr + 16) print_section(KERN_ERR, "Bytes b4 ", p - 16, 16); - print_section(KERN_ERR, "Object ", p, + print_section(KERN_ERR, "Object ", p, min_t(unsigned int, s->object_size, PAGE_SIZE)); if (s->flags & SLAB_RED_ZONE) - print_section(KERN_ERR, "Redzone ", p + s->object_size, + print_section(KERN_ERR, "Redzone ", p + s->object_size, s->inuse - s->object_size); off = get_info_end(s); @@ -732,7 +732,7 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p) if (off != size_from_object(s)) /* Beginning of the filler is the free pointer */ - print_section(KERN_ERR, "Padding ", p + off, + print_section(KERN_ERR, "Padding ", p + off, size_from_object(s) - off); dump_stack(); @@ -909,11 +909,11 @@ static int check_object(struct kmem_cache *s, struct page *page, u8 *endobject = object + s->object_size; if (s->flags & SLAB_RED_ZONE) { - if (!check_bytes_and_report(s, page, object, "Redzone", + if (!check_bytes_and_report(s, page, object, "Left Redzone", object - s->red_left_pad, val, s->red_left_pad)) return 0; - if (!check_bytes_and_report(s, page, object, "Redzone", + if (!check_bytes_and_report(s, page, object, "Right Redzone", endobject, val, s->inuse - s->object_size)) return 0; } else { @@ -928,7 +928,7 @@ static int check_object(struct kmem_cache *s, struct page *page, if (val != SLUB_RED_ACTIVE && (s->flags & __OBJECT_POISON) && (!check_bytes_and_report(s, page, p, "Poison", p, POISON_FREE, s->object_size - 1) || - !check_bytes_and_report(s, page, p, "Poison", + !check_bytes_and_report(s, page, p, "End Poison", p + s->object_size - 1, POISON_END, 1))) return 0; /* -- cgit v1.3.1 From 7bb9557b48fcabaa12750a8775352740def381a8 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 14 Jun 2021 12:39:51 -0700 Subject: pstore/blk: Use the normal block device I/O path Stop poking into block layer internals and just open the block device file an use kernel_read and kernel_write on it. Note that this means the transformation from name_to_dev_t can't be used anymore when pstore_blk is loaded as a module: a full filesystem device path name must be used instead. Additionally removes ":internal:" kerndoc link, since no such documentation remains. Co-developed-by: Christoph Hellwig Signed-off-by: Christoph Hellwig Reviewed-by: Christoph Hellwig Signed-off-by: Kees Cook --- Documentation/admin-guide/pstore-blk.rst | 3 - fs/pstore/blk.c | 264 ++++++++++--------------------- 2 files changed, 83 insertions(+), 184 deletions(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/pstore-blk.rst b/Documentation/admin-guide/pstore-blk.rst index 49d8149f8d32..79f6d23e8cda 100644 --- a/Documentation/admin-guide/pstore-blk.rst +++ b/Documentation/admin-guide/pstore-blk.rst @@ -227,8 +227,5 @@ For developer reference, here are all the important structures and APIs: .. kernel-doc:: include/linux/pstore_zone.h :internal: -.. kernel-doc:: fs/pstore/blk.c - :internal: - .. kernel-doc:: include/linux/pstore_blk.h :internal: diff --git a/fs/pstore/blk.c b/fs/pstore/blk.c index 7d8e5a1ddd5b..dc5ff763d414 100644 --- a/fs/pstore/blk.c +++ b/fs/pstore/blk.c @@ -8,15 +8,16 @@ #include #include -#include "../../block/blk.h" #include #include #include #include #include #include +#include +#include +#include #include -#include static long kmsg_size = CONFIG_PSTORE_BLK_KMSG_SIZE; module_param(kmsg_size, long, 0400); @@ -60,23 +61,25 @@ MODULE_PARM_DESC(best_effort, "use best effort to write (i.e. do not require sto * * Usually, this will be a partition of a block device. * - * blkdev accepts the following variants: - * 1) device number in hexadecimal representation, - * with no leading 0x, for example b302. - * 2) /dev/ represents the device number of disk - * 3) /dev/ represents the device number + * blkdev accepts the following variants, when built as a module: + * 1) /dev/ represents the device number of disk + * 2) /dev/ represents the device number * of partition - device number of disk plus the partition number - * 4) /dev/p - same as the above, that form is + * 3) /dev/p - same as the above, that form is * used when disk name of partitioned disk ends on a digit. - * 5) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the + * + * blkdev accepts the following variants when built into the kernel: + * 1) device number in hexadecimal representation, + * with no leading 0x, for example b302. + * 2) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the * unique id of a partition if the partition table provides it. * The UUID may be either an EFI/GPT UUID, or refer to an MSDOS * partition using the format SSSSSSSS-PP, where SSSSSSSS is a zero- * filled hex representation of the 32-bit "NT disk signature", and PP * is a zero-filled hex representation of the 1-based partition number. - * 6) PARTUUID=/PARTNROFF= to select a partition in relation to + * 3) PARTUUID=/PARTNROFF= to select a partition in relation to * a partition with a known unique id. - * 7) : major and minor number of the device separated by + * 4) : major and minor number of the device separated by * a colon. */ static char blkdev[80] = CONFIG_PSTORE_BLK_BLKDEV; @@ -88,15 +91,9 @@ MODULE_PARM_DESC(blkdev, "block device for pstore storage"); * during the register/unregister functions. */ static DEFINE_MUTEX(pstore_blk_lock); -static struct block_device *psblk_bdev; +static struct file *psblk_file; static struct pstore_zone_info *pstore_zone_info; -struct bdev_info { - dev_t devt; - sector_t nr_sects; - sector_t start_sect; -}; - #define check_size(name, alignsize) ({ \ long _##name_ = (name); \ _##name_ = _##name_ <= 0 ? 0 : (_##name_ * 1024); \ @@ -219,203 +216,73 @@ void unregister_pstore_device(struct pstore_device_info *dev) } EXPORT_SYMBOL_GPL(unregister_pstore_device); -/** - * psblk_get_bdev() - open block device - * - * @holder: Exclusive holder identifier - * @info: Information about bdev to fill in - * - * Return: pointer to block device on success and others on error. - * - * On success, the returned block_device has reference count of one. - */ -static struct block_device *psblk_get_bdev(void *holder, - struct bdev_info *info) -{ - struct block_device *bdev = ERR_PTR(-ENODEV); - fmode_t mode = FMODE_READ | FMODE_WRITE; - sector_t nr_sects; - - lockdep_assert_held(&pstore_blk_lock); - - if (pstore_zone_info) - return ERR_PTR(-EBUSY); - - if (!blkdev[0]) - return ERR_PTR(-ENODEV); - - if (holder) - mode |= FMODE_EXCL; - bdev = blkdev_get_by_path(blkdev, mode, holder); - if (IS_ERR(bdev)) { - dev_t devt; - - devt = name_to_dev_t(blkdev); - if (devt == 0) - return ERR_PTR(-ENODEV); - bdev = blkdev_get_by_dev(devt, mode, holder); - if (IS_ERR(bdev)) - return bdev; - } - - nr_sects = bdev_nr_sectors(bdev); - if (!nr_sects) { - pr_err("not enough space for '%s'\n", blkdev); - blkdev_put(bdev, mode); - return ERR_PTR(-ENOSPC); - } - - if (info) { - info->devt = bdev->bd_dev; - info->nr_sects = nr_sects; - info->start_sect = get_start_sect(bdev); - } - - return bdev; -} - -static void psblk_put_bdev(struct block_device *bdev, void *holder) -{ - fmode_t mode = FMODE_READ | FMODE_WRITE; - - lockdep_assert_held(&pstore_blk_lock); - - if (!bdev) - return; - - if (holder) - mode |= FMODE_EXCL; - blkdev_put(bdev, mode); -} - static ssize_t psblk_generic_blk_read(char *buf, size_t bytes, loff_t pos) { - struct block_device *bdev = psblk_bdev; - struct file file; - struct kiocb kiocb; - struct iov_iter iter; - struct kvec iov = {.iov_base = buf, .iov_len = bytes}; - - if (!bdev) - return -ENODEV; - - memset(&file, 0, sizeof(struct file)); - file.f_mapping = bdev->bd_inode->i_mapping; - file.f_flags = O_DSYNC | __O_SYNC | O_NOATIME; - file.f_inode = bdev->bd_inode; - file_ra_state_init(&file.f_ra, file.f_mapping); - - init_sync_kiocb(&kiocb, &file); - kiocb.ki_pos = pos; - iov_iter_kvec(&iter, READ, &iov, 1, bytes); - - return generic_file_read_iter(&kiocb, &iter); + return kernel_read(psblk_file, buf, bytes, &pos); } static ssize_t psblk_generic_blk_write(const char *buf, size_t bytes, loff_t pos) { - struct block_device *bdev = psblk_bdev; - struct iov_iter iter; - struct kiocb kiocb; - struct file file; - ssize_t ret; - struct kvec iov = {.iov_base = (void *)buf, .iov_len = bytes}; - - if (!bdev) - return -ENODEV; - /* Console/Ftrace backend may handle buffer until flush dirty zones */ if (in_interrupt() || irqs_disabled()) return -EBUSY; - - memset(&file, 0, sizeof(struct file)); - file.f_mapping = bdev->bd_inode->i_mapping; - file.f_flags = O_DSYNC | __O_SYNC | O_NOATIME; - file.f_inode = bdev->bd_inode; - - init_sync_kiocb(&kiocb, &file); - kiocb.ki_pos = pos; - iov_iter_kvec(&iter, WRITE, &iov, 1, bytes); - - inode_lock(bdev->bd_inode); - ret = generic_write_checks(&kiocb, &iter); - if (ret > 0) - ret = generic_perform_write(&file, &iter, pos); - inode_unlock(bdev->bd_inode); - - if (likely(ret > 0)) { - const struct file_operations f_op = {.fsync = blkdev_fsync}; - - file.f_op = &f_op; - kiocb.ki_pos += ret; - ret = generic_write_sync(&kiocb, ret); - } - return ret; + return kernel_write(psblk_file, buf, bytes, &pos); } /* * This takes its configuration only from the module parameters now. - * See psblk_get_bdev() and blkdev. */ -static int __register_pstore_blk(void) +static int __register_pstore_blk(const char *devpath) { - char bdev_name[BDEVNAME_SIZE]; - struct block_device *bdev; - struct pstore_device_info dev; - struct bdev_info binfo; - void *holder = blkdev; + struct pstore_device_info dev = { + .read = psblk_generic_blk_read, + .write = psblk_generic_blk_write, + }; + struct inode *inode; int ret = -ENODEV; lockdep_assert_held(&pstore_blk_lock); - /* hold bdev exclusively */ - memset(&binfo, 0, sizeof(binfo)); - bdev = psblk_get_bdev(holder, &binfo); - if (IS_ERR(bdev)) { - pr_err("failed to open '%s'!\n", blkdev); - return PTR_ERR(bdev); + psblk_file = filp_open(devpath, O_RDWR | O_DSYNC | O_NOATIME | O_EXCL, 0); + if (IS_ERR(psblk_file)) { + ret = PTR_ERR(psblk_file); + pr_err("failed to open '%s': %d!\n", devpath, ret); + goto err; } - /* only allow driver matching the @blkdev */ - if (!binfo.devt) { - pr_debug("no major\n"); - ret = -ENODEV; - goto err_put_bdev; + inode = file_inode(psblk_file); + if (!S_ISBLK(inode->i_mode)) { + pr_err("'%s' is not block device!\n", devpath); + goto err_fput; } - /* psblk_bdev must be assigned before register to pstore/blk */ - psblk_bdev = bdev; - - memset(&dev, 0, sizeof(dev)); - dev.total_size = binfo.nr_sects << SECTOR_SHIFT; - dev.read = psblk_generic_blk_read; - dev.write = psblk_generic_blk_write; + inode = I_BDEV(psblk_file->f_mapping->host)->bd_inode; + dev.total_size = i_size_read(inode); ret = __register_pstore_device(&dev); if (ret) - goto err_put_bdev; + goto err_fput; - bdevname(bdev, bdev_name); - pr_info("attached %s (no dedicated panic_write!)\n", bdev_name); return 0; -err_put_bdev: - psblk_bdev = NULL; - psblk_put_bdev(bdev, holder); +err_fput: + fput(psblk_file); +err: + psblk_file = NULL; + return ret; } -static void __unregister_pstore_blk(unsigned int major) +static void __unregister_pstore_blk(struct file *device) { struct pstore_device_info dev = { .read = psblk_generic_blk_read }; - void *holder = blkdev; lockdep_assert_held(&pstore_blk_lock); - if (psblk_bdev && MAJOR(psblk_bdev->bd_dev) == major) { + if (psblk_file && psblk_file == device) { __unregister_pstore_device(&dev); - psblk_put_bdev(psblk_bdev, holder); - psblk_bdev = NULL; + fput(psblk_file); + psblk_file = NULL; } } @@ -433,13 +300,48 @@ int pstore_blk_get_config(struct pstore_blk_config *info) } EXPORT_SYMBOL_GPL(pstore_blk_get_config); + +#ifndef MODULE +static const char devname[] = "/dev/pstore-blk"; +static __init const char *early_boot_devpath(const char *initial_devname) +{ + /* + * During early boot the real root file system hasn't been + * mounted yet, and no device nodes are present yet. Use the + * same scheme to find the device that we use for mounting + * the root file system. + */ + dev_t dev = name_to_dev_t(initial_devname); + + if (!dev) { + pr_err("failed to resolve '%s'!\n", initial_devname); + return initial_devname; + } + + init_unlink(devname); + init_mknod(devname, S_IFBLK | 0600, new_encode_dev(dev)); + + return devname; +} +#else +static inline const char *early_boot_devpath(const char *initial_devname) +{ + return initial_devname; +} +#endif + static int __init pstore_blk_init(void) { int ret = 0; mutex_lock(&pstore_blk_lock); - if (!pstore_zone_info && best_effort && blkdev[0]) - ret = __register_pstore_blk(); + if (!pstore_zone_info && best_effort && blkdev[0]) { + ret = __register_pstore_blk(early_boot_devpath(blkdev)); + if (ret == 0 && pstore_zone_info) + pr_info("attached %s:%s (%zu) (no dedicated panic_write!)\n", + pstore_zone_info->name, blkdev, + pstore_zone_info->total_size); + } mutex_unlock(&pstore_blk_lock); return ret; @@ -449,8 +351,8 @@ late_initcall(pstore_blk_init); static void __exit pstore_blk_exit(void) { mutex_lock(&pstore_blk_lock); - if (psblk_bdev) - __unregister_pstore_blk(MAJOR(psblk_bdev->bd_dev)); + if (psblk_file) + __unregister_pstore_blk(psblk_file); else { struct pstore_device_info dev = { }; -- cgit v1.3.1 From c811659bb9a09b319842bf61602ce858b1d1920a Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 15 Jun 2021 10:33:00 -0700 Subject: pstore/blk: Fix kerndoc and redundancy on blkdev param Remove redundant details of blkdev and fix up resulting kerndoc. Reviewed-by: Christoph Hellwig Signed-off-by: Kees Cook --- Documentation/admin-guide/pstore-blk.rst | 11 +++++++---- fs/pstore/blk.c | 24 +----------------------- 2 files changed, 8 insertions(+), 27 deletions(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/pstore-blk.rst b/Documentation/admin-guide/pstore-blk.rst index 79f6d23e8cda..2d22ead9520e 100644 --- a/Documentation/admin-guide/pstore-blk.rst +++ b/Documentation/admin-guide/pstore-blk.rst @@ -45,15 +45,18 @@ blkdev The block device to use. Most of the time, it is a partition of block device. It's required for pstore/blk. It is also used for MTD device. -It accepts the following variants for block device: +When pstore/blk is built as a module, "blkdev" accepts the following variants: -1. device number in hexadecimal represents itself; no - leading 0x, for example b302. -#. /dev/ represents the device number of disk +1. /dev/ represents the device number of disk #. /dev/ represents the device number of partition - device number of disk plus the partition number #. /dev/p - same as the above; this form is used when disk name of partitioned disk ends with a digit. + +When pstore/blk is built into the kernel, "blkdev" accepts the following variants: + +#. device number in hexadecimal representation, + with no leading 0x, for example b302. #. PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF represents the unique id of a partition if the partition table provides it. The UUID may be either an EFI/GPT UUID, or refer to an MSDOS partition using the format SSSSSSSS-PP, diff --git a/fs/pstore/blk.c b/fs/pstore/blk.c index dc5ff763d414..c373e0d73e6c 100644 --- a/fs/pstore/blk.c +++ b/fs/pstore/blk.c @@ -58,29 +58,7 @@ MODULE_PARM_DESC(best_effort, "use best effort to write (i.e. do not require sto /* * blkdev - the block device to use for pstore storage - * - * Usually, this will be a partition of a block device. - * - * blkdev accepts the following variants, when built as a module: - * 1) /dev/ represents the device number of disk - * 2) /dev/ represents the device number - * of partition - device number of disk plus the partition number - * 3) /dev/p - same as the above, that form is - * used when disk name of partitioned disk ends on a digit. - * - * blkdev accepts the following variants when built into the kernel: - * 1) device number in hexadecimal representation, - * with no leading 0x, for example b302. - * 2) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the - * unique id of a partition if the partition table provides it. - * The UUID may be either an EFI/GPT UUID, or refer to an MSDOS - * partition using the format SSSSSSSS-PP, where SSSSSSSS is a zero- - * filled hex representation of the 32-bit "NT disk signature", and PP - * is a zero-filled hex representation of the 1-based partition number. - * 3) PARTUUID=/PARTNROFF= to select a partition in relation to - * a partition with a known unique id. - * 4) : major and minor number of the device separated by - * a colon. + * See Documentation/admin-guide/pstore-blk.rst for details. */ static char blkdev[80] = CONFIG_PSTORE_BLK_BLKDEV; module_param_string(blkdev, blkdev, 80, 0400); -- cgit v1.3.1 From 271ca53cb0c8b3a45c73e1140fc3336c2da42315 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Tue, 1 Jun 2021 05:23:18 +0300 Subject: dt-bindings: devfreq: tegra30-actmon: Convert to schema Convert NVIDIA Tegra ACTMON binding to schema. Reviewed-by: Rob Herring Acked-by: Chanwoo Choi Acked-by: Thierry Reding Signed-off-by: Dmitry Osipenko Signed-off-by: Chanwoo Choi --- .../bindings/arm/tegra/nvidia,tegra30-actmon.txt | 57 ---------- .../bindings/devfreq/nvidia,tegra30-actmon.yaml | 121 +++++++++++++++++++++ 2 files changed, 121 insertions(+), 57 deletions(-) delete mode 100644 Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-actmon.txt create mode 100644 Documentation/devicetree/bindings/devfreq/nvidia,tegra30-actmon.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-actmon.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-actmon.txt deleted file mode 100644 index 897eedfa2bc8..000000000000 --- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-actmon.txt +++ /dev/null @@ -1,57 +0,0 @@ -NVIDIA Tegra Activity Monitor - -The activity monitor block collects statistics about the behaviour of other -components in the system. This information can be used to derive the rate at -which the external memory needs to be clocked in order to serve all requests -from the monitored clients. - -Required properties: -- compatible: should be "nvidia,tegra-actmon" -- reg: offset and length of the register set for the device -- interrupts: standard interrupt property -- clocks: Must contain a phandle and clock specifier pair for each entry in -clock-names. See ../../clock/clock-bindings.txt for details. -- clock-names: Must include the following entries: - - actmon - - emc -- resets: Must contain an entry for each entry in reset-names. See -../../reset/reset.txt for details. -- reset-names: Must include the following entries: - - actmon -- operating-points-v2: See ../bindings/opp/opp.txt for details. -- interconnects: Should contain entries for memory clients sitting on - MC->EMC memory interconnect path. -- interconnect-names: Should include name of the interconnect path for each - interconnect entry. Consult TRM documentation for - information about available memory clients, see MEMORY - CONTROLLER section. - -For each opp entry in 'operating-points-v2' table: -- opp-supported-hw: bitfield indicating SoC speedo ID mask -- opp-peak-kBps: peak bandwidth of the memory channel - -Example: - dfs_opp_table: opp-table { - compatible = "operating-points-v2"; - - opp@12750000 { - opp-hz = /bits/ 64 <12750000>; - opp-supported-hw = <0x000F>; - opp-peak-kBps = <51000>; - }; - ... - }; - - actmon@6000c800 { - compatible = "nvidia,tegra124-actmon"; - reg = <0x0 0x6000c800 0x0 0x400>; - interrupts = ; - clocks = <&tegra_car TEGRA124_CLK_ACTMON>, - <&tegra_car TEGRA124_CLK_EMC>; - clock-names = "actmon", "emc"; - resets = <&tegra_car 119>; - reset-names = "actmon"; - operating-points-v2 = <&dfs_opp_table>; - interconnects = <&mc TEGRA124_MC_MPCORER &emc>; - interconnect-names = "cpu"; - }; diff --git a/Documentation/devicetree/bindings/devfreq/nvidia,tegra30-actmon.yaml b/Documentation/devicetree/bindings/devfreq/nvidia,tegra30-actmon.yaml new file mode 100644 index 000000000000..ba938eed28ee --- /dev/null +++ b/Documentation/devicetree/bindings/devfreq/nvidia,tegra30-actmon.yaml @@ -0,0 +1,121 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/devfreq/nvidia,tegra30-actmon.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra30 Activity Monitor + +maintainers: + - Dmitry Osipenko + - Jon Hunter + - Thierry Reding + +description: | + The activity monitor block collects statistics about the behaviour of other + components in the system. This information can be used to derive the rate at + which the external memory needs to be clocked in order to serve all requests + from the monitored clients. + +properties: + compatible: + enum: + - nvidia,tegra30-actmon + - nvidia,tegra114-actmon + - nvidia,tegra124-actmon + - nvidia,tegra210-actmon + + reg: + maxItems: 1 + + clocks: + maxItems: 2 + + clock-names: + items: + - const: actmon + - const: emc + + resets: + maxItems: 1 + + reset-names: + items: + - const: actmon + + interrupts: + maxItems: 1 + + interconnects: + minItems: 1 + maxItems: 12 + + interconnect-names: + minItems: 1 + maxItems: 12 + description: + Should include name of the interconnect path for each interconnect + entry. Consult TRM documentation for information about available + memory clients, see MEMORY CONTROLLER and ACTIVITY MONITOR sections. + + operating-points-v2: + description: + Should contain freqs and voltages and opp-supported-hw property, which + is a bitfield indicating SoC speedo ID mask. + +required: + - compatible + - reg + - clocks + - clock-names + - resets + - reset-names + - interrupts + - interconnects + - interconnect-names + - operating-points-v2 + +additionalProperties: false + +examples: + - | + #include + + mc: memory-controller@7000f000 { + compatible = "nvidia,tegra30-mc"; + reg = <0x7000f000 0x400>; + clocks = <&clk 32>; + clock-names = "mc"; + + interrupts = <0 77 4>; + + #iommu-cells = <1>; + #reset-cells = <1>; + #interconnect-cells = <1>; + }; + + emc: external-memory-controller@7000f400 { + compatible = "nvidia,tegra30-emc"; + reg = <0x7000f400 0x400>; + interrupts = <0 78 4>; + clocks = <&clk 57>; + + nvidia,memory-controller = <&mc>; + operating-points-v2 = <&dvfs_opp_table>; + power-domains = <&domain>; + + #interconnect-cells = <0>; + }; + + actmon@6000c800 { + compatible = "nvidia,tegra30-actmon"; + reg = <0x6000c800 0x400>; + interrupts = <0 45 4>; + clocks = <&clk 119>, <&clk 57>; + clock-names = "actmon", "emc"; + resets = <&rst 119>; + reset-names = "actmon"; + operating-points-v2 = <&dvfs_opp_table>; + interconnects = <&mc TEGRA30_MC_MPCORER &emc>; + interconnect-names = "cpu-read"; + }; -- cgit v1.3.1 From 6b61f55ecbe693d9d0d7ae14ebce01dabe10ecf1 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Tue, 1 Jun 2021 05:23:19 +0300 Subject: dt-bindings: devfreq: tegra30-actmon: Add cooling-cells The ACTMON watches activity of memory clients. Decisions about a minimum required frequency are made based on the info from ACTMON. We can use ACTMON as a thermal cooling device by limiting the required frequency. Document new cooling-cells property of NVIDIA Tegra ACTMON hardware unit. Reviewed-by: Rob Herring Acked-by: Chanwoo Choi Acked-by: Thierry Reding Signed-off-by: Dmitry Osipenko Signed-off-by: Chanwoo Choi --- Documentation/devicetree/bindings/devfreq/nvidia,tegra30-actmon.yaml | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/devfreq/nvidia,tegra30-actmon.yaml b/Documentation/devicetree/bindings/devfreq/nvidia,tegra30-actmon.yaml index ba938eed28ee..e3379d106728 100644 --- a/Documentation/devicetree/bindings/devfreq/nvidia,tegra30-actmon.yaml +++ b/Documentation/devicetree/bindings/devfreq/nvidia,tegra30-actmon.yaml @@ -63,6 +63,9 @@ properties: Should contain freqs and voltages and opp-supported-hw property, which is a bitfield indicating SoC speedo ID mask. + "#cooling-cells": + const: 2 + required: - compatible - reg @@ -74,6 +77,7 @@ required: - interconnects - interconnect-names - operating-points-v2 + - "#cooling-cells" additionalProperties: false @@ -118,4 +122,5 @@ examples: operating-points-v2 = <&dvfs_opp_table>; interconnects = <&mc TEGRA30_MC_MPCORER &emc>; interconnect-names = "cpu-read"; + #cooling-cells = <2>; }; -- cgit v1.3.1 From 5cd57605771216755bd6f98748d4f11d1e65b780 Mon Sep 17 00:00:00 2001 From: Irui Wang Date: Sat, 5 Jun 2021 04:29:14 +0200 Subject: media: dt-bindings: media: mtk-vcodec: Add dma-ranges property The mt8192 iommu support 0~16GB iova. We separate it to four banks: 0~4G; 4G~8G; 8G~12G; 12G~16G. The "dma-ranges" could be used to adjust the bank we locate. If we don't set this property. The default range always is 0~4G. This is optional and only needed in mt8192, the dma ranges should not cross 4G/8G/12G. Here we don't have actual bus/parent concept here. And the iova requirement is for our HW. Thus put the property in our node. Acked-by: Rob Herring Signed-off-by: Irui Wang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/mediatek-vcodec.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/mediatek-vcodec.txt b/Documentation/devicetree/bindings/media/mediatek-vcodec.txt index 06db6837cefd..5bb9e6e191b7 100644 --- a/Documentation/devicetree/bindings/media/mediatek-vcodec.txt +++ b/Documentation/devicetree/bindings/media/mediatek-vcodec.txt @@ -22,6 +22,7 @@ Required properties: - iommus : should point to the respective IOMMU block with master port as argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml for details. +- dma-ranges : describes the dma address range space that the codec hw access. One of the two following nodes: - mediatek,vpu : the node of the video processor unit, if using VPU. - mediatek,scp : the node of the SCP unit, if using SCP. -- cgit v1.3.1 From aa950d8619694fb1a7d0e68aa556976e2f34476d Mon Sep 17 00:00:00 2001 From: Irui Wang Date: Sat, 5 Jun 2021 04:29:16 +0200 Subject: media: dt-bindings: media: mtk-vcodec: Add binding for MT8192 VENC Updates binding document for mt8192 encoder driver. Acked-by: Rob Herring Signed-off-by: Irui Wang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/mediatek-vcodec.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/mediatek-vcodec.txt b/Documentation/devicetree/bindings/media/mediatek-vcodec.txt index 5bb9e6e191b7..ad1321e5a22d 100644 --- a/Documentation/devicetree/bindings/media/mediatek-vcodec.txt +++ b/Documentation/devicetree/bindings/media/mediatek-vcodec.txt @@ -9,6 +9,7 @@ Required properties: "mediatek,mt8173-vcodec-enc" for mt8173 avc encoder. "mediatek,mt8183-vcodec-enc" for MT8183 encoder. "mediatek,mt8173-vcodec-dec" for MT8173 decoder. + "mediatek,mt8192-vcodec-enc" for MT8192 encoder. - reg : Physical base address of the video codec registers and length of memory mapped region. - interrupts : interrupt number to the cpu. -- cgit v1.3.1 From b32178e77d257c148b8ad8c31db36bb0c2d49bab Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Mon, 14 Jun 2021 23:32:10 +0200 Subject: media: dt-bindings: media: rockchip-vpu: add new compatibles Add compatibles for RK3036, RK3066, RK3188 and RK3228. Also reflect the changes to the additional clocks for RK3066/RK3188. Signed-off-by: Alex Bee Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/rockchip-vpu.yaml | 33 ++++++++++++++++------ 1 file changed, 25 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml index c81dbc3e8960..b88172a59de7 100644 --- a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml +++ b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml @@ -15,10 +15,19 @@ description: properties: compatible: - enum: - - rockchip,rk3288-vpu - - rockchip,rk3328-vpu - - rockchip,rk3399-vpu + oneOf: + - enum: + - rockchip,rk3036-vpu + - rockchip,rk3066-vpu + - rockchip,rk3288-vpu + - rockchip,rk3328-vpu + - rockchip,rk3399-vpu + - items: + - const: rockchip,rk3188-vpu + - const: rockchip,rk3066-vpu + - items: + - const: rockchip,rk3228-vpu + - const: rockchip,rk3399-vpu reg: maxItems: 1 @@ -35,12 +44,20 @@ properties: - const: vdpu clocks: - maxItems: 2 + oneOf: + - maxItems: 2 + - maxItems: 4 clock-names: - items: - - const: aclk - - const: hclk + oneOf: + - items: + - const: aclk + - const: hclk + - items: + - const: aclk_vdpu + - const: hclk_vdpu + - const: aclk_vepu + - const: hclk_vepu power-domains: maxItems: 1 -- cgit v1.3.1 From 502cf736419aba4cfa0a6737cf66d286c699f144 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Mon, 14 Jun 2021 23:32:11 +0200 Subject: media: dt-bindings: media: rockchip-vdec: add RK3228 compatible Document the RK3228 compatible for rockchip-vdec. Also add the optional assigned-clocks and assigned-clock-rates properties. Signed-off-by: Alex Bee Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/rockchip,vdec.yaml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml index 8d35c327018b..089f11d21b25 100644 --- a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml +++ b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml @@ -15,7 +15,11 @@ description: |- properties: compatible: - const: rockchip,rk3399-vdec + oneOf: + - const: rockchip,rk3399-vdec + - items: + - const: rockchip,rk3228-vdec + - const: rockchip,rk3399-vdec reg: maxItems: 1 @@ -37,6 +41,10 @@ properties: - const: cabac - const: core + assigned-clocks: true + + assigned-clock-rates: true + power-domains: maxItems: 1 -- cgit v1.3.1 From 6e954d2e649a373cdebb4d2b0de5197ca3f6b87e Mon Sep 17 00:00:00 2001 From: Erik Rosen Date: Fri, 23 Apr 2021 17:33:29 +0200 Subject: hwmon: (pmbus/zl6100) Update documentation for zl6100 driver Update documentation for zl6100 driver and fix dead links to technical specifications Signed-off-by: Erik Rosen Link: https://lore.kernel.org/r/20210423153329.33457-3-erik.rosen@metormote.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/zl6100.rst | 132 +++++++++++++++++++++++++++-------------- 1 file changed, 89 insertions(+), 43 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/zl6100.rst b/Documentation/hwmon/zl6100.rst index 968aff10ce0a..d42ed9d3ac69 100644 --- a/Documentation/hwmon/zl6100.rst +++ b/Documentation/hwmon/zl6100.rst @@ -3,87 +3,103 @@ Kernel driver zl6100 Supported chips: - * Intersil / Zilker Labs ZL2004 + * Renesas / Intersil / Zilker Labs ZL2004 Prefix: 'zl2004' Addresses scanned: - - Datasheet: http://www.intersil.com/data/fn/fn6847.pdf + Datasheet: https://www.renesas.com/us/en/document/dst/zl2004-datasheet.pdf - * Intersil / Zilker Labs ZL2005 + * Renesas / Intersil / Zilker Labs ZL2005 Prefix: 'zl2005' Addresses scanned: - - Datasheet: http://www.intersil.com/data/fn/fn6848.pdf + Datasheet: https://www.renesas.com/us/en/document/dst/zl2005-datasheet.pdf - * Intersil / Zilker Labs ZL2006 + * Renesas / Intersil / Zilker Labs ZL2006 Prefix: 'zl2006' Addresses scanned: - - Datasheet: http://www.intersil.com/data/fn/fn6850.pdf + Datasheet: https://www.renesas.com/us/en/document/dst/zl2006-datasheet.pdf - * Intersil / Zilker Labs ZL2008 + * Renesas / Intersil / Zilker Labs ZL2008 Prefix: 'zl2008' Addresses scanned: - - Datasheet: http://www.intersil.com/data/fn/fn6859.pdf + Datasheet: https://www.renesas.com/us/en/document/dst/zl2008-datasheet.pdf - * Intersil / Zilker Labs ZL2105 + * Renesas / Intersil / Zilker Labs ZL2105 Prefix: 'zl2105' Addresses scanned: - - Datasheet: http://www.intersil.com/data/fn/fn6851.pdf + Datasheet: https://www.renesas.com/us/en/document/dst/zl2105-datasheet.pdf - * Intersil / Zilker Labs ZL2106 + * Renesas / Intersil / Zilker Labs ZL2106 Prefix: 'zl2106' Addresses scanned: - - Datasheet: http://www.intersil.com/data/fn/fn6852.pdf + Datasheet: https://www.renesas.com/us/en/document/dst/zl2106-datasheet.pdf - * Intersil / Zilker Labs ZL6100 + * Renesas / Intersil / Zilker Labs ZL6100 Prefix: 'zl6100' Addresses scanned: - - Datasheet: http://www.intersil.com/data/fn/fn6876.pdf + Datasheet: https://www.renesas.com/us/en/document/dst/zl6100-datasheet.pdf - * Intersil / Zilker Labs ZL6105 + * Renesas / Intersil / Zilker Labs ZL6105 Prefix: 'zl6105' Addresses scanned: - - Datasheet: http://www.intersil.com/data/fn/fn6906.pdf + Datasheet: https://www.renesas.com/us/en/document/dst/zl6105-datasheet.pdf - * Intersil / Zilker Labs ZL9101M + * Renesas / Intersil / Zilker Labs ZL8802 + + Prefix: 'zl8802' + + Addresses scanned: - + + Datasheet: https://www.renesas.com/us/en/document/dst/zl8802-datasheet + + * Renesas / Intersil / Zilker Labs ZL9101M Prefix: 'zl9101' Addresses scanned: - - Datasheet: http://www.intersil.com/data/fn/fn7669.pdf + Datasheet: https://www.renesas.com/us/en/document/dst/zl9101m-datasheet - * Intersil / Zilker Labs ZL9117M + * Renesas / Intersil / Zilker Labs ZL9117M Prefix: 'zl9117' Addresses scanned: - - Datasheet: http://www.intersil.com/data/fn/fn7914.pdf + Datasheet: https://www.renesas.com/us/en/document/dst/zl9117m-datasheet + + * Renesas / Intersil / Zilker Labs ZLS1003, ZLS4009 + + Prefix: 'zls1003', zls4009 + + Addresses scanned: - + + Datasheet: Not published - * Ericsson BMR450, BMR451 + * Flex BMR450, BMR451 Prefix: 'bmr450', 'bmr451' @@ -91,17 +107,39 @@ Supported chips: Datasheet: -http://archive.ericsson.net/service/internet/picov/get?DocNo=28701-EN/LZT146401 +https://flexpowermodules.com/resources/fpm-techspec-bmr450-digital-pol-regulators-20a - * Ericsson BMR462, BMR463, BMR464 + * Flex BMR462, BMR463, BMR464 Prefixes: 'bmr462', 'bmr463', 'bmr464' Addresses scanned: - - Datasheet: + Datasheet: https://flexpowermodules.com/resources/fpm-techspec-bmr462 + + * Flex BMR465, BMR467 + + Prefixes: 'bmr465', 'bmr467' + + Addresses scanned: - + + Datasheet: https://flexpowermodules.com/resources/fpm-techspec-bmr465-digital-pol + + * Flex BMR466 + + Prefixes: 'bmr466' + + Addresses scanned: - + + Datasheet: https://flexpowermodules.com/resources/fpm-techspec-bmr466-8x12 - http://archive.ericsson.net/service/internet/picov/get?DocNo=28701-EN/LZT146256 + * Flex BMR469 + + Prefixes: 'bmr469' + + Addresses scanned: - + + Datasheet: https://flexpowermodules.com/resources/fpm-techspec-bmr4696001 Author: Guenter Roeck @@ -109,8 +147,8 @@ Author: Guenter Roeck Description ----------- -This driver supports hardware monitoring for Intersil / Zilker Labs ZL6100 and -compatible digital DC-DC controllers. +This driver supports hardware monitoring for Renesas / Intersil / Zilker Labs +ZL6100 and compatible digital DC-DC controllers. The driver is a client driver to the core PMBus driver. Please see Documentation/hwmon/pmbus.rst and Documentation.hwmon/pmbus-core for details @@ -147,12 +185,12 @@ Module parameters delay ----- -Intersil/Zilker Labs DC-DC controllers require a minimum interval between I2C -bus accesses. According to Intersil, the minimum interval is 2 ms, though 1 ms -appears to be sufficient and has not caused any problems in testing. The problem -is known to affect all currently supported chips. For manual override, the -driver provides a writeable module parameter, 'delay', which can be used to set -the interval to a value between 0 and 65,535 microseconds. +Renesas/Intersil/Zilker Labs DC-DC controllers require a minimum interval +between I2C bus accesses. According to Intersil, the minimum interval is 2 ms, +though 1 ms appears to be sufficient and has not caused any problems in testing. +The problem is known to affect all currently supported chips. For manual override, +the driver provides a writeable module parameter, 'delay', which can be used +to set the interval to a value between 0 and 65,535 microseconds. Sysfs entries @@ -182,24 +220,32 @@ in2_crit Critical maximum VMON/VDRV voltage. in2_lcrit_alarm VMON/VDRV voltage critical low alarm. in2_crit_alarm VMON/VDRV voltage critical high alarm. - vmon attributes are supported on ZL2004, ZL9101M, - and ZL9117M only. + vmon attributes are supported on ZL2004, ZL8802, + ZL9101M, ZL9117M and ZLS4009 only. -inX_label "vout1" +inX_label "vout[12]" inX_input Measured output voltage. inX_lcrit Critical minimum output Voltage. inX_crit Critical maximum output voltage. inX_lcrit_alarm Critical output voltage critical low alarm. inX_crit_alarm Critical output voltage critical high alarm. - X is 3 for ZL2004, ZL9101M, and ZL9117M, 2 otherwise. + X is 3 for ZL2004, ZL9101M, and ZL9117M, + 3, 4 for ZL8802 and 2 otherwise. + +curr1_label "iin" +curr1_input Measured input current. + + iin attributes are supported on ZL8802 only + +currY_label "iout[12]" +currY_input Measured output current. +currY_lcrit Critical minimum output current. +currY_crit Critical maximum output current. +currY_lcrit_alarm Output current critical low alarm. +currY_crit_alarm Output current critical high alarm. -curr1_label "iout1" -curr1_input Measured output current. -curr1_lcrit Critical minimum output current. -curr1_crit Critical maximum output current. -curr1_lcrit_alarm Output current critical low alarm. -curr1_crit_alarm Output current critical high alarm. + Y is 2, 3 for ZL8802, 1 otherwise temp[12]_input Measured temperature. temp[12]_min Minimum temperature. -- cgit v1.3.1 From ec081f9154766be98b7be6e4c4483b580c5b12e7 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Thu, 29 Apr 2021 14:11:49 +0200 Subject: hwmon: (lm75) Add TI TMP1075 support TI TMP1075 is a LM75 compatible sensor, so lets add support for it. Signed-off-by: Robert Marko Link: https://lore.kernel.org/r/20210429121150.106804-1-robert.marko@sartura.hr Signed-off-by: Guenter Roeck --- Documentation/hwmon/lm75.rst | 6 ++++-- drivers/hwmon/lm75.c | 13 +++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/lm75.rst b/Documentation/hwmon/lm75.rst index 81257d5fc48f..8d0ab4ad5fb5 100644 --- a/Documentation/hwmon/lm75.rst +++ b/Documentation/hwmon/lm75.rst @@ -93,9 +93,9 @@ Supported chips: https://www.st.com/resource/en/datasheet/stlm75.pdf - * Texas Instruments TMP100, TMP101, TMP105, TMP112, TMP75, TMP75B, TMP75C, TMP175, TMP275 + * Texas Instruments TMP100, TMP101, TMP105, TMP112, TMP75, TMP75B, TMP75C, TMP175, TMP275, TMP1075 - Prefixes: 'tmp100', 'tmp101', 'tmp105', 'tmp112', 'tmp175', 'tmp75', 'tmp75b', 'tmp75c', 'tmp275' + Prefixes: 'tmp100', 'tmp101', 'tmp105', 'tmp112', 'tmp175', 'tmp75', 'tmp75b', 'tmp75c', 'tmp275', 'tmp1075' Addresses scanned: none @@ -119,6 +119,8 @@ Supported chips: https://www.ti.com/product/tmp275 + https://www.ti.com/product/TMP1075 + * NXP LM75B, PCT2075 Prefix: 'lm75b', 'pct2075' diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index e447febd121a..afdbb63237b9 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -50,6 +50,7 @@ enum lm75_type { /* keep sorted in alphabetical order */ tmp75, tmp75b, tmp75c, + tmp1075, }; /** @@ -293,6 +294,13 @@ static const struct lm75_params device_params[] = { .clr_mask = 1 << 5, /*not one-shot mode*/ .default_resolution = 12, .default_sample_time = MSEC_PER_SEC / 12, + }, + [tmp1075] = { /* not one-shot mode, 27.5 ms sample rate */ + .clr_mask = 1 << 5 | 1 << 6 | 1 << 7, + .default_resolution = 12, + .default_sample_time = 28, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 28, 55, 110, 220 }, } }; @@ -662,6 +670,7 @@ static const struct i2c_device_id lm75_ids[] = { { "tmp75", tmp75, }, { "tmp75b", tmp75b, }, { "tmp75c", tmp75c, }, + { "tmp1075", tmp1075, }, { /* LIST END */ } }; MODULE_DEVICE_TABLE(i2c, lm75_ids); @@ -771,6 +780,10 @@ static const struct of_device_id __maybe_unused lm75_of_match[] = { .compatible = "ti,tmp75c", .data = (void *)tmp75c }, + { + .compatible = "ti,tmp1075", + .data = (void *)tmp1075 + }, { }, }; MODULE_DEVICE_TABLE(of, lm75_of_match); -- cgit v1.3.1 From 42c7fd53aeff8241d64cdcfaffe06bb955852112 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Thu, 29 Apr 2021 14:11:50 +0200 Subject: dt-bindings: hwmon: Add Texas Instruments TMP1075 Document the DT compatible for TI TMP1075 which is a LM75 compatible sensor. Signed-off-by: Robert Marko Link: https://lore.kernel.org/r/20210429121150.106804-2-robert.marko@sartura.hr Acked-by: Rob Herring Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/lm75.yaml | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/hwmon/lm75.yaml b/Documentation/devicetree/bindings/hwmon/lm75.yaml index 96eed5cc7841..72980d083c21 100644 --- a/Documentation/devicetree/bindings/hwmon/lm75.yaml +++ b/Documentation/devicetree/bindings/hwmon/lm75.yaml @@ -30,6 +30,7 @@ properties: - st,stds75 - st,stlm75 - microchip,tcn75 + - ti,tmp1075 - ti,tmp100 - ti,tmp101 - ti,tmp105 -- cgit v1.3.1 From f0635523c8b57aea6b1b75e99ea9c86ccc2a8b45 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 16 May 2021 12:18:18 +0200 Subject: docs: hwmon: ir36021.rst: replace some characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion tools used during DocBook/LaTeX/html/Markdown->ReST conversion and some cut-and-pasted text contain some characters that aren't easily reachable on standard keyboards and/or could cause troubles when parsed by the documentation build system. Replace the occurences of the following characters: - U+2010 ('‐'): HYPHEN as ASCII HYPHEN is preferred over U+2010 Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/ba8b5122ac9d4918fd966d0eb0a5ca9d89044b04.1621159997.git.mchehab+huawei@kernel.org Signed-off-by: Guenter Roeck --- Documentation/hwmon/ir36021.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/ir36021.rst b/Documentation/hwmon/ir36021.rst index ca3436b04e20..1faa85c39f1b 100644 --- a/Documentation/hwmon/ir36021.rst +++ b/Documentation/hwmon/ir36021.rst @@ -19,7 +19,7 @@ Authors: Description ----------- -The IR36021 is a dual‐loop digital multi‐phase buck controller designed for +The IR36021 is a dual-loop digital multi-phase buck controller designed for point of load applications. Usage Notes -- cgit v1.3.1 From b3ea2fe7e2814d17426674eff3d440c4e9c3a107 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 10 May 2021 12:26:17 +0200 Subject: docs: hwmon: avoid using UTF-8 chars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While UTF-8 characters can be used at the Linux documentation, the best is to use them only when ASCII doesn't offer a good replacement. So, replace the occurences of the following UTF-8 characters: - U+2010 ('‐'): HYPHEN - U+2013 ('–'): EN DASH - U+2019 ('’'): RIGHT SINGLE QUOTATION MARK Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/ccdd1bf45963a7748188a97c75f667b37bd43d2f.1620641727.git.mchehab+huawei@kernel.org Signed-off-by: Guenter Roeck --- Documentation/hwmon/ltc2992.rst | 2 +- Documentation/hwmon/pm6764tr.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/ltc2992.rst b/Documentation/hwmon/ltc2992.rst index 46aa1aa84a1a..a0bcd867a0f5 100644 --- a/Documentation/hwmon/ltc2992.rst +++ b/Documentation/hwmon/ltc2992.rst @@ -19,7 +19,7 @@ This driver supports hardware monitoring for Linear Technology LTC2992 power mon LTC2992 is a rail-to-rail system monitor that measures current, voltage, and power of two supplies. -Two ADCs simultaneously measure each supply’s current. A third ADC monitors +Two ADCs simultaneously measure each supply's current. A third ADC monitors the input voltages and four auxiliary external voltages. diff --git a/Documentation/hwmon/pm6764tr.rst b/Documentation/hwmon/pm6764tr.rst index a1fb8fea2326..294a8ffc8bd8 100644 --- a/Documentation/hwmon/pm6764tr.rst +++ b/Documentation/hwmon/pm6764tr.rst @@ -20,7 +20,7 @@ Description: ------------ This driver supports the STMicroelectronics PM6764TR chip. The PM6764TR is a high -performance digital controller designed to power Intel’s VR12.5 processors and memories. +performance digital controller designed to power Intel's VR12.5 processors and memories. The device utilizes digital technology to implement all control and power management functions to provide maximum flexibility and performance. The NVM is embedded to store -- cgit v1.3.1 From b976760dc4efd1de7965bf020195a22fce4f456c Mon Sep 17 00:00:00 2001 From: Erik Rosen Date: Fri, 7 May 2021 21:40:22 +0200 Subject: hwmon: (pmbus) Add documentation for new flags Add documentation for the new pmbus flags PMBUS_WRITE_PROTECTED, PMBUS_NO_CAPABILITY and PMBUS_READ_STATUS_AFTER_FAILED_CHECK Signed-off-by: Erik Rosen Link: https://lore.kernel.org/r/20210507194023.61138-3-erik.rosen@metormote.com [groeck: Added newline at end of file] Signed-off-by: Guenter Roeck --- Documentation/hwmon/pmbus-core.rst | 42 ++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/pmbus-core.rst b/Documentation/hwmon/pmbus-core.rst index 73e23ab42cc3..e7e0c9ef10be 100644 --- a/Documentation/hwmon/pmbus-core.rst +++ b/Documentation/hwmon/pmbus-core.rst @@ -289,12 +289,22 @@ PMBus driver platform data ========================== PMBus platform data is defined in include/linux/pmbus.h. Platform data -currently only provides a flag field with a single bit used:: +currently provides a flags field with four bits used:: - #define PMBUS_SKIP_STATUS_CHECK (1 << 0) + #define PMBUS_SKIP_STATUS_CHECK BIT(0) + + #define PMBUS_WRITE_PROTECTED BIT(1) + + #define PMBUS_NO_CAPABILITY BIT(2) + + #define PMBUS_READ_STATUS_AFTER_FAILED_CHECK BIT(3) struct pmbus_platform_data { u32 flags; /* Device specific flags */ + + /* regulator support */ + int num_regulators; + struct regulator_init_data *reg_init_data; }; @@ -302,8 +312,9 @@ Flags ----- PMBUS_SKIP_STATUS_CHECK - During register detection, skip checking the status register for - communication or command errors. + +During register detection, skip checking the status register for +communication or command errors. Some PMBus chips respond with valid data when trying to read an unsupported register. For such chips, checking the status register is mandatory when @@ -315,3 +326,26 @@ status register must be disabled. Some i2c controllers do not support single-byte commands (write commands with no data, i2c_smbus_write_byte()). With such controllers, clearing the status register is impossible, and the PMBUS_SKIP_STATUS_CHECK flag must be set. + +PMBUS_WRITE_PROTECTED + +Set if the chip is write protected and write protection is not determined +by the standard WRITE_PROTECT command. + +PMBUS_NO_CAPABILITY + +Some PMBus chips don't respond with valid data when reading the CAPABILITY +register. For such chips, this flag should be set so that the PMBus core +driver doesn't use CAPABILITY to determine it's behavior. + +PMBUS_READ_STATUS_AFTER_FAILED_CHECK + +Read the STATUS register after each failed register check. + +Some PMBus chips end up in an undefined state when trying to read an +unsupported register. For such chips, it is necessary to reset the +chip pmbus controller to a known state after a failed register check. +This can be done by reading a known register. By setting this flag the +driver will try to read the STATUS register after each failed +register check. This read may fail, but it will put the chip into a +known state. -- cgit v1.3.1 From ea541c185c358f870ccb0d5fce6f726c5146daae Mon Sep 17 00:00:00 2001 From: Erik Rosen Date: Fri, 7 May 2021 21:40:23 +0200 Subject: hwmon: (pmbus) Add support for additional Flex BMR converters to pmbus Add support for Flex BMR310, BMR456, BMR457, BMR458, BMR480, BMR490, BMR491 and BMR492 to the pmbus driver Signed-off-by: Erik Rosen Link: https://lore.kernel.org/r/20210507194023.61138-4-erik.rosen@metormote.com [groeck: Fixed minor whitespace error] Signed-off-by: Guenter Roeck --- Documentation/hwmon/pmbus.rst | 11 +++++++---- drivers/hwmon/pmbus/Kconfig | 7 ++++--- drivers/hwmon/pmbus/pmbus.c | 19 +++++++++++++++++-- 3 files changed, 28 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/pmbus.rst b/Documentation/hwmon/pmbus.rst index c44f14115413..7ecfec6ca2db 100644 --- a/Documentation/hwmon/pmbus.rst +++ b/Documentation/hwmon/pmbus.rst @@ -3,15 +3,18 @@ Kernel driver pmbus Supported chips: - * Ericsson BMR453, BMR454 + * Flex BMR310, BMR453, BMR454, BMR456, BMR457, BMR458, BMR480, + BMR490, BMR491, BMR492 - Prefixes: 'bmr453', 'bmr454' + Prefixes: 'bmr310', 'bmr453', 'bmr454', 'bmr456', 'bmr457', 'bmr458', 'bmr480', + 'bmr490', 'bmr491', 'bmr492' Addresses scanned: - - Datasheet: + Datasheets: + + https://flexpowermodules.com/products - http://archive.ericsson.net/service/internet/picov/get?DocNo=28701-EN/LZT146395 * ON Semiconductor ADP4000, NCP4200, NCP4208 diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 37a5c39784fa..6275dcf78675 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -19,9 +19,10 @@ config SENSORS_PMBUS default y help If you say yes here you get hardware monitoring support for generic - PMBus devices, including but not limited to ADP4000, BMR453, BMR454, - MAX20796, MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, TPS40400, - TPS544B20, TPS544B25, TPS544C20, TPS544C25, and UDT020. + PMBus devices, including but not limited to ADP4000, BMR310, BMR453, + BMR454, BMR456, BMR457, BMR458, BMR480, BMR490, BMR491, BMR492, + MAX20796, MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, + TPS40400, TPS544B20, TPS544B25, TPS544C20, TPS544C25, and UDT020. This driver can also be built as a module. If so, the module will be called pmbus. diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index 618c377664c4..d0d386990af5 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -173,13 +173,13 @@ static int pmbus_probe(struct i2c_client *client) return -ENOMEM; device_info = (struct pmbus_device_info *)i2c_match_id(pmbus_id, client)->driver_data; - if (device_info->flags & PMBUS_SKIP_STATUS_CHECK) { + if (device_info->flags) { pdata = devm_kzalloc(dev, sizeof(struct pmbus_platform_data), GFP_KERNEL); if (!pdata) return -ENOMEM; - pdata->flags = PMBUS_SKIP_STATUS_CHECK; + pdata->flags = device_info->flags; } info->pages = device_info->pages; @@ -193,22 +193,37 @@ static const struct pmbus_device_info pmbus_info_one = { .pages = 1, .flags = 0 }; + static const struct pmbus_device_info pmbus_info_zero = { .pages = 0, .flags = 0 }; + static const struct pmbus_device_info pmbus_info_one_skip = { .pages = 1, .flags = PMBUS_SKIP_STATUS_CHECK }; +static const struct pmbus_device_info pmbus_info_one_status = { + .pages = 1, + .flags = PMBUS_READ_STATUS_AFTER_FAILED_CHECK +}; + /* * Use driver_data to set the number of pages supported by the chip. */ static const struct i2c_device_id pmbus_id[] = { {"adp4000", (kernel_ulong_t)&pmbus_info_one}, + {"bmr310", (kernel_ulong_t)&pmbus_info_one_status}, {"bmr453", (kernel_ulong_t)&pmbus_info_one}, {"bmr454", (kernel_ulong_t)&pmbus_info_one}, + {"bmr456", (kernel_ulong_t)&pmbus_info_one}, + {"bmr457", (kernel_ulong_t)&pmbus_info_one}, + {"bmr458", (kernel_ulong_t)&pmbus_info_one_status}, + {"bmr480", (kernel_ulong_t)&pmbus_info_one_status}, + {"bmr490", (kernel_ulong_t)&pmbus_info_one_status}, + {"bmr491", (kernel_ulong_t)&pmbus_info_one_status}, + {"bmr492", (kernel_ulong_t)&pmbus_info_one}, {"dps460", (kernel_ulong_t)&pmbus_info_one_skip}, {"dps650ab", (kernel_ulong_t)&pmbus_info_one_skip}, {"dps800", (kernel_ulong_t)&pmbus_info_one_skip}, -- cgit v1.3.1 From e4db7719d037b820024a213f74703ae1abf5b00c Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Tue, 11 May 2021 08:56:18 +0300 Subject: hwmon: (pmbus) Add support for MPS Multi-phase mp2888 controller Add support for mp2888 device from Monolithic Power Systems, Inc. (MPS) vendor. This is a digital, multi-phase, pulse-width modulation controller. This device supports: - One power rail. - Programmable Multi-Phase up to 10 Phases. - PWM-VID Interface - One pages 0 for telemetry. - Programmable pins for PMBus Address. - Built-In EEPROM to Store Custom Configurations. - Can configured VOUT readout in direct or VID format and allows setting of different formats on rails 1 and 2. For VID the following protocols are available: VR13 mode with 5-mV DAC; VR13 mode with 10-mV DAC, IMVP9 mode with 5-mV DAC. Signed-off-by: Vadim Pasternak Reported-by: kernel test robot Link: https://lore.kernel.org/r/20210511055619.118104-3-vadimp@nvidia.com [groeck: Add MODULE_IMPORT_NS] Signed-off-by: Guenter Roeck --- Documentation/hwmon/mp2888.rst | 113 ++++++++++++ drivers/hwmon/pmbus/Kconfig | 9 + drivers/hwmon/pmbus/Makefile | 1 + drivers/hwmon/pmbus/mp2888.c | 408 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 531 insertions(+) create mode 100644 Documentation/hwmon/mp2888.rst create mode 100644 drivers/hwmon/pmbus/mp2888.c (limited to 'Documentation') diff --git a/Documentation/hwmon/mp2888.rst b/Documentation/hwmon/mp2888.rst new file mode 100644 index 000000000000..5e578fd7b147 --- /dev/null +++ b/Documentation/hwmon/mp2888.rst @@ -0,0 +1,113 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver mp2888 +==================== + +Supported chips: + + * MPS MP12254 + + Prefix: 'mp2888' + +Author: + + Vadim Pasternak + +Description +----------- + +This driver implements support for Monolithic Power Systems, Inc. (MPS) +vendor dual-loop, digital, multi-phase controller MP2888. + +This device: supports: + +- One power rail. +- Programmable Multi-Phase up to 10 Phases. +- PWM-VID Interface +- One pages 0 for telemetry. +- Programmable pins for PMBus Address. +- Built-In EEPROM to Store Custom Configurations. + +Device complaint with: + +- PMBus rev 1.3 interface. + +Device supports direct format for reading output current, output voltage, +input and output power and temperature. +Device supports linear format for reading input voltage and input power. + +The driver provides the next attributes for the current: + +- for current out input and maximum alarm; +- for phase current: input and label. + +The driver exports the following attributes via the 'sysfs' files, where: + +- 'n' is number of configured phases (from 1 to 10); +- index 1 for "iout"; +- indexes 2 ... 1 + n for phases. + +**curr[1-{1+n}]_input** + +**curr[1-{1+n}]_label** + +**curr1_max** + +**curr1_max_alarm** + +The driver provides the next attributes for the voltage: + +- for voltage in: input, low and high critical thresholds, low and high + critical alarms; +- for voltage out: input and high alarm; + +The driver exports the following attributes via the 'sysfs' files, where + +**in1_crit** + +**in1_crit_alarm** + +**in1_input** + +**in1_label** + +**in1_min** + +**in1_min_alarm** + +**in2_alarm** + +**in2_input** + +**in2_label** + +The driver provides the next attributes for the power: + +- for power in alarm and input. +- for power out: cap, cap alarm an input. + +The driver exports the following attributes via the 'sysfs' files, where +- indexes 1 for "pin"; +- indexes 2 for "pout"; + +**power1_alarm** + +**power1_input** + +**power1_label** + +**power2_input** + +**power2_label** + +**power2_max** + +**power2_max_alarm** + +The driver provides the next attributes for the temperature: + +**temp1_input** + +**temp1_max** + +**temp1_max_alarm** diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 6275dcf78675..52d8cd63603e 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -249,6 +249,15 @@ config SENSORS_MAX8688 This driver can also be built as a module. If so, the module will be called max8688. +config SENSORS_MP2888 + tristate "MPS MP2888" + help + If you say yes here you get hardware monitoring support for MPS + MP2888 Digital, Multi-Phase, Pulse-Width Modulation Controller. + + This driver can also be built as a module. If so, the module will + be called mp2888. + config SENSORS_MP2975 tristate "MPS MP2975" help diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index f8dcc27cd56a..35d293bb44bf 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_SENSORS_MAX20751) += max20751.o obj-$(CONFIG_SENSORS_MAX31785) += max31785.o obj-$(CONFIG_SENSORS_MAX34440) += max34440.o obj-$(CONFIG_SENSORS_MAX8688) += max8688.o +obj-$(CONFIG_SENSORS_MP2888) += mp2888.o obj-$(CONFIG_SENSORS_MP2975) += mp2975.o obj-$(CONFIG_SENSORS_PM6764TR) += pm6764tr.o obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o diff --git a/drivers/hwmon/pmbus/mp2888.c b/drivers/hwmon/pmbus/mp2888.c new file mode 100644 index 000000000000..8ecd4adfef40 --- /dev/null +++ b/drivers/hwmon/pmbus/mp2888.c @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers + * + * Copyright (C) 2020 Nvidia Technologies Ltd. + */ + +#include +#include +#include +#include +#include +#include "pmbus.h" + +/* Vendor specific registers. */ +#define MP2888_MFR_SYS_CONFIG 0x44 +#define MP2888_MFR_READ_CS1_2 0x73 +#define MP2888_MFR_READ_CS3_4 0x74 +#define MP2888_MFR_READ_CS5_6 0x75 +#define MP2888_MFR_READ_CS7_8 0x76 +#define MP2888_MFR_READ_CS9_10 0x77 +#define MP2888_MFR_VR_CONFIG1 0xe1 + +#define MP2888_TOTAL_CURRENT_RESOLUTION BIT(3) +#define MP2888_PHASE_CURRENT_RESOLUTION BIT(4) +#define MP2888_DRMOS_KCS GENMASK(2, 0) +#define MP2888_TEMP_UNIT 10 +#define MP2888_MAX_PHASE 10 + +struct mp2888_data { + struct pmbus_driver_info info; + int total_curr_resolution; + int phase_curr_resolution; + int curr_sense_gain; +}; + +#define to_mp2888_data(x) container_of(x, struct mp2888_data, info) + +static int mp2888_read_byte_data(struct i2c_client *client, int page, int reg) +{ + switch (reg) { + case PMBUS_VOUT_MODE: + /* Enforce VOUT direct format. */ + return PB_VOUT_MODE_DIRECT; + default: + return -ENODATA; + } +} + +static int +mp2888_current_sense_gain_and_resolution_get(struct i2c_client *client, struct mp2888_data *data) +{ + int ret; + + /* + * Obtain DrMOS current sense gain of power stage from the register + * , bits 0-2. The value is selected as below: + * 00b - 5µA/A, 01b - 8.5µA/A, 10b - 9.7µA/A, 11b - 10µA/A. Other + * values are reserved. + */ + ret = i2c_smbus_read_word_data(client, MP2888_MFR_SYS_CONFIG); + if (ret < 0) + return ret; + + switch (ret & MP2888_DRMOS_KCS) { + case 0: + data->curr_sense_gain = 85; + break; + case 1: + data->curr_sense_gain = 97; + break; + case 2: + data->curr_sense_gain = 100; + break; + case 3: + data->curr_sense_gain = 50; + break; + default: + return -EINVAL; + } + + /* + * Obtain resolution selector for total and phase current report and protection. + * 0: original resolution; 1: half resolution (in such case phase current value should + * be doubled. + */ + data->total_curr_resolution = (ret & MP2888_TOTAL_CURRENT_RESOLUTION) >> 3; + data->phase_curr_resolution = (ret & MP2888_PHASE_CURRENT_RESOLUTION) >> 4; + + return 0; +} + +static int +mp2888_read_phase(struct i2c_client *client, struct mp2888_data *data, int page, int phase, u8 reg) +{ + int ret; + + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + + if (!((phase + 1) % 2)) + ret >>= 8; + ret &= 0xff; + + /* + * Output value is calculated as: (READ_CSx / 80 – 1.23) / (Kcs * Rcs) + * where: + * - Kcs is the DrMOS current sense gain of power stage, which is obtained from the + * register MP2888_MFR_VR_CONFIG1, bits 13-12 with the following selection of DrMOS + * (data->curr_sense_gain): + * 00b - 5µA/A, 01b - 8.5µA/A, 10b - 9.7µA/A, 11b - 10µA/A. + * - Rcs is the internal phase current sense resistor. This parameter depends on hardware + * assembly. By default it is set to 1kΩ. In case of different assembly, user should + * scale this parameter by dividing it by Rcs. + * If phase current resolution bit is set to 1, READ_CSx value should be doubled. + * Note, that current phase sensing, providing by the device is not accurate. This is + * because sampling of current occurrence of bit weight has a big deviation, especially for + * light load. + */ + ret = DIV_ROUND_CLOSEST(ret * 100 - 9800, data->curr_sense_gain); + ret = (data->phase_curr_resolution) ? ret * 2 : ret; + /* Scale according to total current resolution. */ + ret = (data->total_curr_resolution) ? ret * 8 : ret * 4; + return ret; +} + +static int +mp2888_read_phases(struct i2c_client *client, struct mp2888_data *data, int page, int phase) +{ + int ret; + + switch (phase) { + case 0 ... 1: + ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS1_2); + break; + case 2 ... 3: + ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS3_4); + break; + case 4 ... 5: + ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS5_6); + break; + case 6 ... 7: + ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS7_8); + break; + case 8 ... 9: + ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS9_10); + break; + default: + return -ENODATA; + } + return ret; +} + +static int mp2888_read_word_data(struct i2c_client *client, int page, int phase, int reg) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct mp2888_data *data = to_mp2888_data(info); + int ret; + + switch (reg) { + case PMBUS_READ_VIN: + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret <= 0) + return ret; + + /* + * READ_VIN requires fixup to scale it to linear11 format. Register data format + * provides 10 bits for mantissa and 6 bits for exponent. Bits 15:10 are set with + * the fixed value 111011b. + */ + ret = (ret & GENMASK(9, 0)) | ((ret & GENMASK(31, 10)) << 1); + break; + case PMBUS_OT_WARN_LIMIT: + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + /* + * Chip reports limits in degrees C, but the actual temperature in 10th of + * degrees C - scaling is needed to match both. + */ + ret *= MP2888_TEMP_UNIT; + break; + case PMBUS_READ_IOUT: + if (phase != 0xff) + return mp2888_read_phases(client, data, page, phase); + + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + /* + * READ_IOUT register has unused bits 15:12 with fixed value 1110b. Clear these + * bits and scale with total current resolution. Data is provided in direct format. + */ + ret &= GENMASK(11, 0); + ret = data->total_curr_resolution ? ret * 2 : ret; + break; + case PMBUS_IOUT_OC_WARN_LIMIT: + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + ret &= GENMASK(9, 0); + /* + * Chip reports limits with resolution 1A or 2A, if total current resolution bit is + * set 1. Actual current is reported with 0.25A or respectively 0.5A resolution. + * Scaling is needed to match both. + */ + ret = data->total_curr_resolution ? ret * 8 : ret * 4; + break; + case PMBUS_READ_POUT: + case PMBUS_READ_PIN: + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + ret = data->total_curr_resolution ? ret * 2 : ret; + break; + case PMBUS_POUT_OP_WARN_LIMIT: + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + /* + * Chip reports limits with resolution 1W or 2W, if total current resolution bit is + * set 1. Actual power is reported with 0.5W or 1W respectively resolution. Scaling + * is needed to match both. + */ + ret = data->total_curr_resolution ? ret * 4 : ret * 2; + break; + /* + * The below registers are not implemented by device or implemented not according to the + * spec. Skip all of them to avoid exposing non-relevant inputs to sysfs. + */ + case PMBUS_OT_FAULT_LIMIT: + case PMBUS_UT_WARN_LIMIT: + case PMBUS_UT_FAULT_LIMIT: + case PMBUS_VIN_UV_FAULT_LIMIT: + case PMBUS_VOUT_UV_WARN_LIMIT: + case PMBUS_VOUT_OV_WARN_LIMIT: + case PMBUS_VOUT_UV_FAULT_LIMIT: + case PMBUS_VOUT_OV_FAULT_LIMIT: + case PMBUS_VIN_OV_WARN_LIMIT: + case PMBUS_IOUT_OC_LV_FAULT_LIMIT: + case PMBUS_IOUT_OC_FAULT_LIMIT: + case PMBUS_POUT_MAX: + case PMBUS_IOUT_UC_FAULT_LIMIT: + case PMBUS_POUT_OP_FAULT_LIMIT: + case PMBUS_PIN_OP_WARN_LIMIT: + case PMBUS_MFR_VIN_MIN: + case PMBUS_MFR_VOUT_MIN: + case PMBUS_MFR_VIN_MAX: + case PMBUS_MFR_VOUT_MAX: + case PMBUS_MFR_IIN_MAX: + case PMBUS_MFR_IOUT_MAX: + case PMBUS_MFR_PIN_MAX: + case PMBUS_MFR_POUT_MAX: + case PMBUS_MFR_MAX_TEMP_1: + return -ENXIO; + default: + return -ENODATA; + } + + return ret; +} + +static int mp2888_write_word_data(struct i2c_client *client, int page, int reg, u16 word) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct mp2888_data *data = to_mp2888_data(info); + + switch (reg) { + case PMBUS_OT_WARN_LIMIT: + word = DIV_ROUND_CLOSEST(word, MP2888_TEMP_UNIT); + /* Drop unused bits 15:8. */ + word = clamp_val(word, 0, GENMASK(7, 0)); + break; + case PMBUS_IOUT_OC_WARN_LIMIT: + /* Fix limit according to total curent resolution. */ + word = data->total_curr_resolution ? DIV_ROUND_CLOSEST(word, 8) : + DIV_ROUND_CLOSEST(word, 4); + /* Drop unused bits 15:10. */ + word = clamp_val(word, 0, GENMASK(9, 0)); + break; + case PMBUS_POUT_OP_WARN_LIMIT: + /* Fix limit according to total curent resolution. */ + word = data->total_curr_resolution ? DIV_ROUND_CLOSEST(word, 4) : + DIV_ROUND_CLOSEST(word, 2); + /* Drop unused bits 15:10. */ + word = clamp_val(word, 0, GENMASK(9, 0)); + break; + default: + return -ENODATA; + } + return pmbus_write_word_data(client, page, reg, word); +} + +static int +mp2888_identify_multiphase(struct i2c_client *client, struct mp2888_data *data, + struct pmbus_driver_info *info) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); + if (ret < 0) + return ret; + + /* Identify multiphase number - could be from 1 to 10. */ + ret = i2c_smbus_read_word_data(client, MP2888_MFR_VR_CONFIG1); + if (ret <= 0) + return ret; + + info->phases[0] = ret & GENMASK(3, 0); + + /* + * The device provides a total of 10 PWM pins, and can be configured to different phase + * count applications for rail. + */ + if (info->phases[0] > MP2888_MAX_PHASE) + return -EINVAL; + + return 0; +} + +static struct pmbus_driver_info mp2888_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_TEMPERATURE] = direct, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_CURRENT_OUT] = direct, + .format[PSC_POWER] = direct, + .m[PSC_TEMPERATURE] = 1, + .R[PSC_TEMPERATURE] = 1, + .m[PSC_VOLTAGE_OUT] = 1, + .R[PSC_VOLTAGE_OUT] = 3, + .m[PSC_CURRENT_OUT] = 4, + .m[PSC_POWER] = 1, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT | + PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | + PMBUS_PHASE_VIRTUAL, + .pfunc[0] = PMBUS_HAVE_IOUT, + .pfunc[1] = PMBUS_HAVE_IOUT, + .pfunc[2] = PMBUS_HAVE_IOUT, + .pfunc[3] = PMBUS_HAVE_IOUT, + .pfunc[4] = PMBUS_HAVE_IOUT, + .pfunc[5] = PMBUS_HAVE_IOUT, + .pfunc[6] = PMBUS_HAVE_IOUT, + .pfunc[7] = PMBUS_HAVE_IOUT, + .pfunc[8] = PMBUS_HAVE_IOUT, + .pfunc[9] = PMBUS_HAVE_IOUT, + .read_byte_data = mp2888_read_byte_data, + .read_word_data = mp2888_read_word_data, + .write_word_data = mp2888_write_word_data, +}; + +static int mp2888_probe(struct i2c_client *client) +{ + struct pmbus_driver_info *info; + struct mp2888_data *data; + int ret; + + data = devm_kzalloc(&client->dev, sizeof(struct mp2888_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + memcpy(&data->info, &mp2888_info, sizeof(*info)); + info = &data->info; + + /* Identify multiphase configuration. */ + ret = mp2888_identify_multiphase(client, data, info); + if (ret) + return ret; + + /* Obtain current sense gain of power stage and current resolution. */ + ret = mp2888_current_sense_gain_and_resolution_get(client, data); + if (ret) + return ret; + + return pmbus_do_probe(client, info); +} + +static const struct i2c_device_id mp2888_id[] = { + {"mp2888", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, mp2888_id); + +static const struct of_device_id __maybe_unused mp2888_of_match[] = { + {.compatible = "mps,mp2888"}, + {} +}; +MODULE_DEVICE_TABLE(of, mp2888_of_match); + +static struct i2c_driver mp2888_driver = { + .driver = { + .name = "mp2888", + .of_match_table = of_match_ptr(mp2888_of_match), + }, + .probe_new = mp2888_probe, + .id_table = mp2888_id, +}; + +module_i2c_driver(mp2888_driver); + +MODULE_AUTHOR("Vadim Pasternak "); +MODULE_DESCRIPTION("PMBus driver for MPS MP2888 device"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); -- cgit v1.3.1 From 9abfb52b502889f1528316cf0b7d4116d40abebe Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Tue, 11 May 2021 08:56:19 +0300 Subject: dt-bindings: Add MP2888 voltage regulator device Monolithic Power Systems, Inc. (MPS) dual-loop, digital, multi-phase controller. Signed-off-by: Vadim Pasternak Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210511055619.118104-4-vadimp@nvidia.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/trivial-devices.yaml | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 8341e9d23c1e..f8824e1dd24c 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -103,6 +103,8 @@ properties: - fsl,mpl3115 # MPR121: Proximity Capacitive Touch Sensor Controller - fsl,mpr121 + # Monolithic Power Systems Inc. multi-phase controller mp2888 + - mps,mp2888 # Monolithic Power Systems Inc. multi-phase controller mp2975 - mps,mp2975 # G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface -- cgit v1.3.1 From f20f7363e7e1d24defc27b1cb814071791a535b0 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 21 May 2021 14:22:18 -0300 Subject: docs: hwmon: Add an entry for mp2888 The entry for mp2888 is missing and it causes the following 'make htmldocs' build warning: Documentation/hwmon/mp2888.rst: WARNING: document isn't included in any toctree Add the mp2888 entry. Signed-off-by: Fabio Estevam Link: https://lore.kernel.org/r/20210521172218.37592-1-festevam@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/index.rst | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 9ed60fa84cbe..6925a8a70511 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -137,6 +137,7 @@ Hardware Monitoring Kernel Drivers mcp3021 menf21bmc mlxreg-fan + mp2888 mp2975 nct6683 nct6775 -- cgit v1.3.1 From 505c2549373f3aa9ee16493f872e57876ffb70b1 Mon Sep 17 00:00:00 2001 From: Navin Sankar Velliangiri Date: Mon, 24 May 2021 19:50:38 +0530 Subject: hwmon: Add sht4x Temperature and Humidity Sensor Driver This patch adds a hwmon driver for the SHT4x Temperature and Humidity sensor. Signed-off-by: Navin Sankar Velliangiri [groeck: dropped unnecessary empty line and continuation lines] Signed-off-by: Guenter Roeck --- Documentation/hwmon/index.rst | 1 + Documentation/hwmon/sht4x.rst | 45 +++++++ drivers/hwmon/Kconfig | 11 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/sht4x.c | 301 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 359 insertions(+) create mode 100644 Documentation/hwmon/sht4x.rst create mode 100644 drivers/hwmon/sht4x.c (limited to 'Documentation') diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 6925a8a70511..61e5d4532622 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -165,6 +165,7 @@ Hardware Monitoring Kernel Drivers sht15 sht21 sht3x + sht4x shtc1 sis5595 sl28cpld diff --git a/Documentation/hwmon/sht4x.rst b/Documentation/hwmon/sht4x.rst new file mode 100644 index 000000000000..3b37abcd4a46 --- /dev/null +++ b/Documentation/hwmon/sht4x.rst @@ -0,0 +1,45 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver sht4x +=================== + +Supported Chips: + + * Sensirion SHT4X + + Prefix: 'sht4x' + + Addresses scanned: None + + Datasheet: + + English: https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHT4x_Datasheet.pdf + +Author: Navin Sankar Velliangiri + + +Description +----------- + +This driver implements support for the Sensirion SHT4x chip, a humidity +and temperature sensor. Temperature is measured in degree celsius, relative +humidity is expressed as a percentage. In sysfs interface, all values are +scaled by 1000, i.e. the value for 31.5 degrees celsius is 31500. + +Usage Notes +----------- + +The device communicates with the I2C protocol. Sensors can have the I2C +address 0x44. See Documentation/i2c/instantiating-devices.rst for methods +to instantiate the device. + +Sysfs entries +------------- + +=============== ============================================ +temp1_input Measured temperature in millidegrees Celcius +humidity1_input Measured humidity in %H +update_interval The minimum interval for polling the sensor, + in milliseconds. Writable. Must be at least + 2000. +============== ============================================= diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 87624902ea80..e3675377bc5d 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1583,6 +1583,17 @@ config SENSORS_SHT3x This driver can also be built as a module. If so, the module will be called sht3x. +config SENSORS_SHT4x + tristate "Sensiron humidity and temperature sensors. SHT4x and compat." + depends on I2C + select CRC8 + help + If you say yes here you get support for the Sensiron SHT40, SHT41 and + SHT45 humidity and temperature sensors. + + This driver can also be built as a module. If so, the module + will be called sht4x. + config SENSORS_SHTC1 tristate "Sensiron humidity and temperature sensors. SHTC1 and compat." depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 59e78bc212cf..d712c61c1f5e 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -171,6 +171,7 @@ obj-$(CONFIG_SENSORS_SL28CPLD) += sl28cpld-hwmon.o obj-$(CONFIG_SENSORS_SHT15) += sht15.o obj-$(CONFIG_SENSORS_SHT21) += sht21.o obj-$(CONFIG_SENSORS_SHT3x) += sht3x.o +obj-$(CONFIG_SENSORS_SHT4x) += sht4x.o obj-$(CONFIG_SENSORS_SHTC1) += shtc1.o obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o obj-$(CONFIG_SENSORS_SMM665) += smm665.o diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c new file mode 100644 index 000000000000..1dc51ee2a72b --- /dev/null +++ b/drivers/hwmon/sht4x.c @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (c) Linumiz 2021 + * + * sht4x.c - Linux hwmon driver for SHT4x Temperature and Humidity sensor + * + * Author: Navin Sankar Velliangiri + */ + +#include +#include +#include +#include +#include +#include + +/* + * Poll intervals (in milliseconds) + */ +#define SHT4X_MIN_POLL_INTERVAL 2000 + +/* + * I2C command delays (in microseconds) + */ +#define SHT4X_MEAS_DELAY 1000 +#define SHT4X_DELAY_EXTRA 10000 + +/* + * Command Bytes + */ +#define SHT4X_CMD_MEASURE_HPM 0b11111101 +#define SHT4X_CMD_RESET 0b10010100 + +#define SHT4X_CMD_LEN 1 +#define SHT4X_CRC8_LEN 1 +#define SHT4X_WORD_LEN 2 +#define SHT4X_RESPONSE_LENGTH 6 +#define SHT4X_CRC8_POLYNOMIAL 0x31 +#define SHT4X_CRC8_INIT 0xff +#define SHT4X_MIN_TEMPERATURE -45000 +#define SHT4X_MAX_TEMPERATURE 125000 +#define SHT4X_MIN_HUMIDITY 0 +#define SHT4X_MAX_HUMIDITY 100000 + +DECLARE_CRC8_TABLE(sht4x_crc8_table); + +/** + * struct sht4x_data - All the data required to operate an SHT4X chip + * @client: the i2c client associated with the SHT4X + * @lock: a mutex that is used to prevent parallel access to the i2c client + * @update_interval: the minimum poll interval + * @last_updated: the previous time that the SHT4X was polled + * @temperature: the latest temperature value received from the SHT4X + * @humidity: the latest humidity value received from the SHT4X + */ +struct sht4x_data { + struct i2c_client *client; + struct mutex lock; /* atomic read data updates */ + bool valid; /* validity of fields below */ + long update_interval; /* in milli-seconds */ + long last_updated; /* in jiffies */ + s32 temperature; + s32 humidity; +}; + +/** + * sht4x_read_values() - read and parse the raw data from the SHT4X + * @sht4x_data: the struct sht4x_data to use for the lock + * Return: 0 if succesfull, 1 if not + */ +static int sht4x_read_values(struct sht4x_data *data) +{ + int ret = 0; + u16 t_ticks, rh_ticks; + unsigned long next_update; + struct i2c_client *client = data->client; + u8 crc, raw_data[SHT4X_RESPONSE_LENGTH], + cmd[] = {SHT4X_CMD_MEASURE_HPM}; + + mutex_lock(&data->lock); + next_update = data->last_updated + + msecs_to_jiffies(data->update_interval); + if (!data->valid || time_after(jiffies, next_update)) { + ret = i2c_master_send(client, cmd, SHT4X_CMD_LEN); + if (ret < 0) + goto unlock; + + usleep_range(SHT4X_MEAS_DELAY, + SHT4X_MEAS_DELAY + SHT4X_DELAY_EXTRA); + + ret = i2c_master_recv(client, raw_data, SHT4X_RESPONSE_LENGTH); + if (ret != SHT4X_RESPONSE_LENGTH) { + if (ret >= 0) + ret = -ENODATA; + + goto unlock; + } + + t_ticks = raw_data[0] << 8 | raw_data[1]; + rh_ticks = raw_data[3] << 8 | raw_data[4]; + + crc = crc8(sht4x_crc8_table, &raw_data[0], SHT4X_WORD_LEN, CRC8_INIT_VALUE); + if (crc != raw_data[2]) { + dev_err(&client->dev, "data integrity check failed\n"); + ret = -EIO; + goto unlock; + } + + crc = crc8(sht4x_crc8_table, &raw_data[3], SHT4X_WORD_LEN, CRC8_INIT_VALUE); + if (crc != raw_data[5]) { + dev_err(&client->dev, "data integrity check failed\n"); + ret = -EIO; + goto unlock; + } + + data->temperature = ((21875 * (int32_t)t_ticks) >> 13) - 45000; + data->humidity = ((15625 * (int32_t)rh_ticks) >> 13) - 6000; + data->last_updated = jiffies; + data->valid = true; + } + +unlock: + mutex_unlock(&data->lock); + return ret; +} + +static ssize_t sht4x_interval_write(struct sht4x_data *data, long val) +{ + data->update_interval = clamp_val(val, SHT4X_MIN_POLL_INTERVAL, UINT_MAX); + + return 0; +} + +/** + * sht4x_interval_read() - read the minimum poll interval + * in milliseconds + */ +static size_t sht4x_interval_read(struct sht4x_data *data, long *val) +{ + *val = data->update_interval; + return 0; +} + +/** + * sht4x_temperature1_read() - read the temperature in millidegrees + */ +static int sht4x_temperature1_read(struct sht4x_data *data, long *val) +{ + int ret; + + ret = sht4x_read_values(data); + if (ret < 0) + return ret; + + *val = data->temperature; + + return 0; +} + +/** + * sht4x_humidity1_read() - read a relative humidity in millipercent + */ +static int sht4x_humidity1_read(struct sht4x_data *data, long *val) +{ + int ret; + + ret = sht4x_read_values(data); + if (ret < 0) + return ret; + + *val = data->humidity; + + return 0; +} + +static umode_t sht4x_hwmon_visible(const void *data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_temp: + case hwmon_humidity: + return 0444; + case hwmon_chip: + return 0644; + default: + return 0; + } +} + +static int sht4x_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct sht4x_data *data = dev_get_drvdata(dev); + + switch (type) { + case hwmon_temp: + return sht4x_temperature1_read(data, val); + case hwmon_humidity: + return sht4x_humidity1_read(data, val); + case hwmon_chip: + return sht4x_interval_read(data, val); + default: + return -EOPNOTSUPP; + } +} + +static int sht4x_hwmon_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + struct sht4x_data *data = dev_get_drvdata(dev); + + switch (type) { + case hwmon_chip: + return sht4x_interval_write(data, val); + default: + return -EOPNOTSUPP; + } +} + +static const struct hwmon_channel_info *sht4x_info[] = { + HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL), + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), + HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT), + NULL, +}; + +static const struct hwmon_ops sht4x_hwmon_ops = { + .is_visible = sht4x_hwmon_visible, + .read = sht4x_hwmon_read, + .write = sht4x_hwmon_write, +}; + +static const struct hwmon_chip_info sht4x_chip_info = { + .ops = &sht4x_hwmon_ops, + .info = sht4x_info, +}; + +static int sht4x_probe(struct i2c_client *client, + const struct i2c_device_id *sht4x_id) +{ + struct device *device = &client->dev; + struct device *hwmon_dev; + struct sht4x_data *data; + u8 cmd[] = {SHT4X_CMD_RESET}; + int ret; + + /* + * we require full i2c support since the sht4x uses multi-byte read and + * writes as well as multi-byte commands which are not supported by + * the smbus protocol + */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -EOPNOTSUPP; + + data = devm_kzalloc(device, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->update_interval = SHT4X_MIN_POLL_INTERVAL; + data->client = client; + + mutex_init(&data->lock); + + crc8_populate_msb(sht4x_crc8_table, SHT4X_CRC8_POLYNOMIAL); + + ret = i2c_master_send(client, cmd, SHT4X_CMD_LEN); + if (ret < 0) + return ret; + if (ret != SHT4X_CMD_LEN) + return -EIO; + + hwmon_dev = devm_hwmon_device_register_with_info(device, + client->name, + data, + &sht4x_chip_info, + NULL); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct i2c_device_id sht4x_id[] = { + { "sht4x", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, sht4x_id); + +static struct i2c_driver sht4x_driver = { + .driver = { + .name = "sht4x", + }, + .probe = sht4x_probe, + .id_table = sht4x_id, +}; + +module_i2c_driver(sht4x_driver); + +MODULE_AUTHOR("Navin Sankar Velliangiri "); +MODULE_DESCRIPTION("Sensirion SHT4x humidity and temperature sensor driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.3.1 From 897f6339893b741a5d68ae8e2475df65946041c2 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 26 May 2021 08:40:17 -0700 Subject: hwmon: (max31790) Report correct current pwm duty cycles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MAX31790 has two sets of registers for pwm duty cycles, one to request a duty cycle and one to read the actual current duty cycle. Both do not have to be the same. When reporting the pwm duty cycle to the user, the actual pwm duty cycle from pwm duty cycle registers needs to be reported. When setting it, the pwm target duty cycle needs to be written. Since we don't know the actual pwm duty cycle after a target pwm duty cycle has been written, set the valid flag to false to indicate that actual pwm duty cycle should be read from the chip instead of using cached values. Cc: Jan Kundrát Cc: Václav Kubernát Signed-off-by: Guenter Roeck Tested-by: Václav Kubernát Reviewed-by: Jan Kundrát Link: https://lore.kernel.org/r/20210526154022.3223012-3-linux@roeck-us.net --- Documentation/hwmon/max31790.rst | 3 ++- drivers/hwmon/max31790.c | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/max31790.rst b/Documentation/hwmon/max31790.rst index f301385d8cef..54ff0f49e28f 100644 --- a/Documentation/hwmon/max31790.rst +++ b/Documentation/hwmon/max31790.rst @@ -39,5 +39,6 @@ fan[1-12]_input RO fan tachometer speed in RPM fan[1-12]_fault RO fan experienced fault fan[1-6]_target RW desired fan speed in RPM pwm[1-6]_enable RW regulator mode, 0=disabled, 1=manual mode, 2=rpm mode -pwm[1-6] RW fan target duty cycle (0-255) +pwm[1-6] RW read: current pwm duty cycle, + write: target pwm duty cycle (0-255) ================== === ======================================================= diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c index f6d4fc0a2f13..693497e09ac0 100644 --- a/drivers/hwmon/max31790.c +++ b/drivers/hwmon/max31790.c @@ -104,7 +104,7 @@ static struct max31790_data *max31790_update_device(struct device *dev) data->tach[NR_CHANNEL + i] = rv; } else { rv = i2c_smbus_read_word_swapped(client, - MAX31790_REG_PWMOUT(i)); + MAX31790_REG_PWM_DUTY_CYCLE(i)); if (rv < 0) goto abort; data->pwm[i] = rv; @@ -299,10 +299,10 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel, err = -EINVAL; break; } - data->pwm[channel] = val << 8; + data->valid = false; err = i2c_smbus_write_word_swapped(client, MAX31790_REG_PWMOUT(channel), - data->pwm[channel]); + val << 8); break; case hwmon_pwm_enable: fan_config = data->fan_config[channel]; -- cgit v1.3.1 From 148c847c9e5a54b99850617bf9c143af9a344f92 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 26 May 2021 08:40:18 -0700 Subject: hwmon: (max31790) Fix pwmX_enable attributes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pwmX_enable supports three possible values: 0: Fan control disabled. Duty cycle is fixed to 0% 1: Fan control enabled, pwm mode. Duty cycle is determined by values written into Target Duty Cycle registers. 2: Fan control enabled, rpm mode Duty cycle is adjusted such that fan speed matches the values in Target Count registers The current code does not do this; instead, it mixes pwm control configuration with fan speed monitoring configuration. Worse, it reports that pwm control would be disabled (pwmX_enable==0) when it is in fact enabled in pwm mode. Part of the problem may be that the chip sets the "TACH input enable" bit on its own whenever the mode bit is set to RPM mode, but that doesn't mean that "TACH input enable" accurately reflects the pwm mode. Fix it up and only handle pwm control with the pwmX_enable attributes. In the documentation, clarify that disabling pwm control (pwmX_enable=0) sets the pwm duty cycle to 0%. In the code, explain why TACH_INPUT_EN is set together with RPM_MODE. While at it, only update the configuration register if the configuration has changed, and only update the cached configuration if updating the chip configuration was successful. Cc: Jan Kundrát Cc: Václav Kubernát Signed-off-by: Guenter Roeck Tested-by: Václav Kubernát Reviewed-by: Jan Kundrát Link: https://lore.kernel.org/r/20210526154022.3223012-4-linux@roeck-us.net --- Documentation/hwmon/max31790.rst | 2 +- drivers/hwmon/max31790.c | 41 +++++++++++++++++++++++++--------------- 2 files changed, 27 insertions(+), 16 deletions(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/max31790.rst b/Documentation/hwmon/max31790.rst index 54ff0f49e28f..7b097c3b9b90 100644 --- a/Documentation/hwmon/max31790.rst +++ b/Documentation/hwmon/max31790.rst @@ -38,7 +38,7 @@ Sysfs entries fan[1-12]_input RO fan tachometer speed in RPM fan[1-12]_fault RO fan experienced fault fan[1-6]_target RW desired fan speed in RPM -pwm[1-6]_enable RW regulator mode, 0=disabled, 1=manual mode, 2=rpm mode +pwm[1-6]_enable RW regulator mode, 0=disabled (duty cycle=0%), 1=manual mode, 2=rpm mode pwm[1-6] RW read: current pwm duty cycle, write: target pwm duty cycle (0-255) ================== === ======================================================= diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c index 693497e09ac0..67677c437768 100644 --- a/drivers/hwmon/max31790.c +++ b/drivers/hwmon/max31790.c @@ -27,6 +27,7 @@ /* Fan Config register bits */ #define MAX31790_FAN_CFG_RPM_MODE 0x80 +#define MAX31790_FAN_CFG_CTRL_MON 0x10 #define MAX31790_FAN_CFG_TACH_INPUT_EN 0x08 #define MAX31790_FAN_CFG_TACH_INPUT 0x01 @@ -271,12 +272,12 @@ static int max31790_read_pwm(struct device *dev, u32 attr, int channel, *val = data->pwm[channel] >> 8; return 0; case hwmon_pwm_enable: - if (fan_config & MAX31790_FAN_CFG_RPM_MODE) + if (fan_config & MAX31790_FAN_CFG_CTRL_MON) + *val = 0; + else if (fan_config & MAX31790_FAN_CFG_RPM_MODE) *val = 2; - else if (fan_config & MAX31790_FAN_CFG_TACH_INPUT_EN) - *val = 1; else - *val = 0; + *val = 1; return 0; default: return -EOPNOTSUPP; @@ -307,23 +308,33 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel, case hwmon_pwm_enable: fan_config = data->fan_config[channel]; if (val == 0) { - fan_config &= ~(MAX31790_FAN_CFG_TACH_INPUT_EN | - MAX31790_FAN_CFG_RPM_MODE); + fan_config |= MAX31790_FAN_CFG_CTRL_MON; + /* + * Disable RPM mode; otherwise disabling fan speed + * monitoring is not possible. + */ + fan_config &= ~MAX31790_FAN_CFG_RPM_MODE; } else if (val == 1) { - fan_config = (fan_config | - MAX31790_FAN_CFG_TACH_INPUT_EN) & - ~MAX31790_FAN_CFG_RPM_MODE; + fan_config &= ~(MAX31790_FAN_CFG_CTRL_MON | MAX31790_FAN_CFG_RPM_MODE); } else if (val == 2) { - fan_config |= MAX31790_FAN_CFG_TACH_INPUT_EN | - MAX31790_FAN_CFG_RPM_MODE; + fan_config &= ~MAX31790_FAN_CFG_CTRL_MON; + /* + * The chip sets MAX31790_FAN_CFG_TACH_INPUT_EN on its + * own if MAX31790_FAN_CFG_RPM_MODE is set. + * Do it here as well to reflect the actual register + * value in the cache. + */ + fan_config |= (MAX31790_FAN_CFG_RPM_MODE | MAX31790_FAN_CFG_TACH_INPUT_EN); } else { err = -EINVAL; break; } - data->fan_config[channel] = fan_config; - err = i2c_smbus_write_byte_data(client, - MAX31790_REG_FAN_CONFIG(channel), - fan_config); + if (fan_config != data->fan_config[channel]) { + err = i2c_smbus_write_byte_data(client, MAX31790_REG_FAN_CONFIG(channel), + fan_config); + if (!err) + data->fan_config[channel] = fan_config; + } break; default: err = -EOPNOTSUPP; -- cgit v1.3.1 From ff53b77e1e1bc9fd21e087e37a8444e8559d8d36 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Jun 2021 15:18:21 +0200 Subject: docs: hwmon: adm1177.rst: avoid using ReSt :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/32b0db7e79a3ed0e817213113c607a1b819e3867.1622898327.git.mchehab+huawei@kernel.org Signed-off-by: Guenter Roeck --- Documentation/hwmon/adm1177.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/hwmon/adm1177.rst b/Documentation/hwmon/adm1177.rst index 471be1e98d6f..1c85a2af92bf 100644 --- a/Documentation/hwmon/adm1177.rst +++ b/Documentation/hwmon/adm1177.rst @@ -20,7 +20,8 @@ Usage Notes ----------- This driver does not auto-detect devices. You will have to instantiate the -devices explicitly. Please see :doc:`/i2c/instantiating-devices` for details. +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst +for details. Sysfs entries -- cgit v1.3.1 From bf8e0cd8d6b2c9be365ea53d36e9368f07880a2f Mon Sep 17 00:00:00 2001 From: Erik Rosen Date: Wed, 9 Jun 2021 11:32:09 +0200 Subject: hwmon: (pmbus/pim4328) Add documentation for the pim4328 PMBus driver Add documentation and index link for pim4328 PMBus driver. Signed-off-by: Erik Rosen Signed-off-by: Guenter Roeck --- Documentation/hwmon/index.rst | 1 + Documentation/hwmon/pim4328.rst | 105 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 Documentation/hwmon/pim4328.rst (limited to 'Documentation') diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 61e5d4532622..9d4f5b2b84b0 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -151,6 +151,7 @@ Hardware Monitoring Kernel Drivers pc87360 pc87427 pcf8591 + pim4328 pm6764tr pmbus powr1220 diff --git a/Documentation/hwmon/pim4328.rst b/Documentation/hwmon/pim4328.rst new file mode 100644 index 000000000000..70c9e7a6882c --- /dev/null +++ b/Documentation/hwmon/pim4328.rst @@ -0,0 +1,105 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver pim4328 +===================== + +Supported chips: + + * Flex PIM4328 + + Prefix: 'pim4328', 'bmr455' + + Addresses scanned: - + + Datasheet: + +https://flexpowermodules.com/resources/fpm-techspec-pim4328 + + * Flex PIM4820 + + Prefixes: 'pim4820' + + Addresses scanned: - + + Datasheet: https://flexpowermodules.com/resources/fpm-techspec-pim4820 + + * Flex PIM4006, PIM4106, PIM4206, PIM4306, PIM4406 + + Prefixes: 'pim4006', 'pim4106', 'pim4206', 'pim4306', 'pim4406' + + Addresses scanned: - + + Datasheet: https://flexpowermodules.com/resources/fpm-techspec-pim4006 + +Author: Erik Rosen + + +Description +----------- + +This driver supports hardware monitoring for Flex PIM4328 and +compatible digital power interface modules. + +The driver is a client driver to the core PMBus driver. Please see +Documentation/hwmon/pmbus.rst and Documentation.hwmon/pmbus-core for details +on PMBus client drivers. + + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for +details. + + +Platform data support +--------------------- + +The driver supports standard PMBus driver platform data. + + +Sysfs entries +------------- + +The following attributes are supported. All attributes are read-only. + +======================= ======================================================== +in1_label "vin" +in1_input Measured input voltage. +in1_alarm Input voltage alarm. + +in2_label "vin.0" +in2_input Measured input voltage on input A. + + PIM4328 and PIM4X06 + +in3_label "vin.1" +in3_input Measured input voltage on input B. + + PIM4328 and PIM4X06 + +in4_label "vcap" +in4_input Measured voltage on holdup capacitor. + + PIM4328 + +curr1_label "iin.0" +curr1_input Measured input current on input A. + + PIM4X06 + +curr2_label "iin.1" +curr2_input Measured input current on input B. + + PIM4X06 + +currX_label "iout1" +currX_input Measured output current. +currX_alarm Output current alarm. + + X is 1 for PIM4820, 3 otherwise. + +temp1_input Measured temperature. +temp1_alarm High temperature alarm. +======================= ======================================================== -- cgit v1.3.1 From 3efbcee8d4029795fa0a1ef90dc5b9ea763ed207 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Mon, 7 Jun 2021 12:34:29 +0200 Subject: hwmon: (pmbus) Add driver for Delta DPS-920AB PSU This adds support for the Delta DPS-920AB PSU. Only missing feature is fan control which the PSU supports. Signed-off-by: Robert Marko Link: https://lore.kernel.org/r/20210607103431.2039073-1-robert.marko@sartura.hr [groeck: Add MODULE_IMPORT_NS(PMBUS);] Signed-off-by: Guenter Roeck --- Documentation/hwmon/dps920ab.rst | 73 ++++++++++++++ Documentation/hwmon/index.rst | 1 + drivers/hwmon/pmbus/Kconfig | 9 ++ drivers/hwmon/pmbus/Makefile | 1 + drivers/hwmon/pmbus/dps920ab.c | 208 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 292 insertions(+) create mode 100644 Documentation/hwmon/dps920ab.rst create mode 100644 drivers/hwmon/pmbus/dps920ab.c (limited to 'Documentation') diff --git a/Documentation/hwmon/dps920ab.rst b/Documentation/hwmon/dps920ab.rst new file mode 100644 index 000000000000..c33b4cdc0a60 --- /dev/null +++ b/Documentation/hwmon/dps920ab.rst @@ -0,0 +1,73 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Kernel driver dps920ab +======================== + +Supported chips: + + * Delta DPS920AB + + Prefix: 'dps920ab' + + Addresses scanned: - + +Authors: + Robert Marko + + +Description +----------- + +This driver implements support for Delta DPS920AB 920W 54V DC single output +power supply with PMBus support. + +The driver is a client driver to the core PMBus driver. +Please see Documentation/hwmon/pmbus.rst for details on PMBus client drivers. + + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for +details. + + +Sysfs entries +------------- + +======================= ====================================================== +curr1_label "iin" +curr1_input Measured input current +curr1_alarm Input current high alarm + +curr2_label "iout1" +curr2_input Measured output current +curr2_max Maximum output current +curr2_rated_max Maximum rated output current + +in1_label "vin" +in1_input Measured input voltage +in1_alarm Input voltage alarm + +in2_label "vout1" +in2_input Measured output voltage +in2_rated_min Minimum rated output voltage +in2_rated_max Maximum rated output voltage +in2_alarm Output voltage alarm + +power1_label "pin" +power1_input Measured input power +power1_alarm Input power high alarm + +power2_label "pout1" +power2_input Measured output power +power2_rated_max Maximum rated output power + +temp[1-3]_input Measured temperature +temp[1-3]_alarm Temperature alarm + +fan1_alarm Fan 1 warning. +fan1_fault Fan 1 fault. +fan1_input Fan 1 speed in RPM. +======================= ====================================================== diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 9d4f5b2b84b0..bc01601ea81a 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -53,6 +53,7 @@ Hardware Monitoring Kernel Drivers da9055 dell-smm-hwmon dme1737 + dps920ab drivetemp ds1621 ds620 diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 10ef548f74a4..ffb609cee3a4 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -86,6 +86,15 @@ config SENSORS_IBM_CFFPS This driver can also be built as a module. If so, the module will be called ibm-cffps. +config SENSORS_DPS920AB + tristate "Delta DPS920AB Power Supply" + help + If you say yes here you get hardware monitoring support for Delta + DPS920AB Power Supplies. + + This driver can also be built as a module. If so, the module will + be called dps920ab. + config SENSORS_INSPUR_IPSPS tristate "INSPUR Power System Power Supply" help diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index b3354518f66f..0ed4d596a948 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_SENSORS_BEL_PFE) += bel-pfe.o obj-$(CONFIG_SENSORS_BPA_RS600) += bpa-rs600.o obj-$(CONFIG_SENSORS_FSP_3Y) += fsp-3y.o obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o +obj-$(CONFIG_SENSORS_DPS920AB) += dps920ab.o obj-$(CONFIG_SENSORS_INSPUR_IPSPS) += inspur-ipsps.o obj-$(CONFIG_SENSORS_IR35221) += ir35221.o obj-$(CONFIG_SENSORS_IR36021) += ir36021.o diff --git a/drivers/hwmon/pmbus/dps920ab.c b/drivers/hwmon/pmbus/dps920ab.c new file mode 100644 index 000000000000..bd2df2a3c8e3 --- /dev/null +++ b/drivers/hwmon/pmbus/dps920ab.c @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for Delta DPS920AB PSU + * + * Copyright (C) 2021 Delta Networks, Inc. + * Copyright (C) 2021 Sartura Ltd. + */ + +#include +#include +#include +#include +#include "pmbus.h" + +struct dps920ab_data { + char *mfr_model; + char *mfr_id; +}; + +static int dps920ab_read_word_data(struct i2c_client *client, int page, int phase, int reg) +{ + /* + * This masks commands which are not supported. + * PSU advertises that all features are supported, + * in reality that unfortunately is not true. + * So enable only those that the datasheet confirms. + */ + switch (reg) { + case PMBUS_FAN_COMMAND_1: + case PMBUS_IOUT_OC_WARN_LIMIT: + case PMBUS_STATUS_WORD: + case PMBUS_READ_VIN: + case PMBUS_READ_IIN: + case PMBUS_READ_VOUT: + case PMBUS_READ_IOUT: + case PMBUS_READ_TEMPERATURE_1: + case PMBUS_READ_TEMPERATURE_2: + case PMBUS_READ_TEMPERATURE_3: + case PMBUS_READ_FAN_SPEED_1: + case PMBUS_READ_POUT: + case PMBUS_READ_PIN: + case PMBUS_MFR_VOUT_MIN: + case PMBUS_MFR_VOUT_MAX: + case PMBUS_MFR_IOUT_MAX: + case PMBUS_MFR_POUT_MAX: + return pmbus_read_word_data(client, page, phase, reg); + default: + return -ENXIO; + } +} + +static int dps920ab_write_word_data(struct i2c_client *client, int page, int reg, + u16 word) +{ + /* + * This masks commands which are not supported. + * PSU only has one R/W register and that is + * for the fan. + */ + switch (reg) { + case PMBUS_FAN_COMMAND_1: + return pmbus_write_word_data(client, page, reg, word); + default: + return -EACCES; + } +} + +static struct pmbus_driver_info dps920ab_info = { + .pages = 1, + + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = linear, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .format[PSC_FAN] = linear, + .format[PSC_TEMPERATURE] = linear, + + .func[0] = + PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | + PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 | + PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 | + PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP, + .read_word_data = dps920ab_read_word_data, + .write_word_data = dps920ab_write_word_data, +}; + +static int dps920ab_mfr_id_show(struct seq_file *s, void *data) +{ + struct dps920ab_data *priv = s->private; + + seq_printf(s, "%s\n", priv->mfr_id); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(dps920ab_mfr_id); + +static int dps920ab_mfr_model_show(struct seq_file *s, void *data) +{ + struct dps920ab_data *priv = s->private; + + seq_printf(s, "%s\n", priv->mfr_model); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(dps920ab_mfr_model); + +static void dps920ab_init_debugfs(struct dps920ab_data *data, struct i2c_client *client) +{ + struct dentry *debugfs_dir; + struct dentry *root; + + root = pmbus_get_debugfs_dir(client); + if (!root) + return; + + debugfs_dir = debugfs_create_dir(client->name, root); + if (!debugfs_dir) + return; + + debugfs_create_file("mfr_id", + 0400, + debugfs_dir, + data, + &dps920ab_mfr_id_fops); + + debugfs_create_file("mfr_model", + 0400, + debugfs_dir, + data, + &dps920ab_mfr_model_fops); +} + +static int dps920ab_probe(struct i2c_client *client) +{ + u8 buf[I2C_SMBUS_BLOCK_MAX + 1]; + struct dps920ab_data *data; + int ret; + + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf); + if (ret < 0) { + dev_err(&client->dev, "Failed to read Manufacturer ID\n"); + return ret; + } + + buf[ret] = '\0'; + if (ret != 5 || strncmp(buf, "DELTA", 5)) { + buf[ret] = '\0'; + dev_err(&client->dev, "Unsupported Manufacturer ID '%s'\n", buf); + return -ENODEV; + } + data->mfr_id = devm_kstrdup(&client->dev, buf, GFP_KERNEL); + if (!data->mfr_id) + return -ENOMEM; + + ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf); + if (ret < 0) { + dev_err(&client->dev, "Failed to read Manufacturer Model\n"); + return ret; + } + + buf[ret] = '\0'; + if (ret != 11 || strncmp(buf, "DPS-920AB", 9)) { + dev_err(&client->dev, "Unsupported Manufacturer Model '%s'\n", buf); + return -ENODEV; + } + data->mfr_model = devm_kstrdup(&client->dev, buf, GFP_KERNEL); + if (!data->mfr_model) + return -ENOMEM; + + ret = pmbus_do_probe(client, &dps920ab_info); + if (ret) + return ret; + + dps920ab_init_debugfs(data, client); + + return 0; +} + +static const struct of_device_id __maybe_unused dps920ab_of_match[] = { + { .compatible = "delta,dps920ab", }, + {} +}; + +MODULE_DEVICE_TABLE(of, dps920ab_of_match); + +static struct i2c_driver dps920ab_driver = { + .driver = { + .name = "dps920ab", + .of_match_table = of_match_ptr(dps920ab_of_match), + }, + .probe_new = dps920ab_probe, +}; + +module_i2c_driver(dps920ab_driver); + +MODULE_AUTHOR("Robert Marko "); +MODULE_DESCRIPTION("PMBus driver for Delta DPS920AB PSU"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); -- cgit v1.3.1 From 8b1d61cd47ccea482a3f68c99d7358e3daea35fa Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Mon, 7 Jun 2021 12:34:30 +0200 Subject: dt-bindings: trivial-devices: Add Delta DPS920AB Add trivial device entry for Delta DPS920AB PSU. Signed-off-by: Robert Marko Link: https://lore.kernel.org/r/20210607103431.2039073-2-robert.marko@sartura.hr Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/trivial-devices.yaml | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index f8824e1dd24c..37ac0a3ae3b4 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -73,6 +73,8 @@ properties: - dallas,ds4510 # Digital Thermometer and Thermostat - dallas,ds75 + # Delta Electronics DPS920AB 920W 54V Power Supply + - delta,dps920ab # 1/4 Brick DC/DC Regulated Power Module - delta,q54sj108a2 # Devantech SRF02 ultrasonic ranger in I2C mode -- cgit v1.3.1 From aa7968682a2b8a9cecf1d7d07e1c8ae8c08d211e Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Sat, 5 Jun 2021 09:38:11 +0900 Subject: spi: convert Cadence SPI bindings to YAML Convert spi for Cadence SPI bindings documentation to YAML. Signed-off-by: Nobuhiro Iwamatsu Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210605003811.858676-1-iwamatsu@nigauri.org Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-cadence.txt | 30 ---------- .../devicetree/bindings/spi/spi-cadence.yaml | 66 ++++++++++++++++++++++ 2 files changed, 66 insertions(+), 30 deletions(-) delete mode 100644 Documentation/devicetree/bindings/spi/spi-cadence.txt create mode 100644 Documentation/devicetree/bindings/spi/spi-cadence.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-cadence.txt b/Documentation/devicetree/bindings/spi/spi-cadence.txt deleted file mode 100644 index 05a2ef945664..000000000000 --- a/Documentation/devicetree/bindings/spi/spi-cadence.txt +++ /dev/null @@ -1,30 +0,0 @@ -Cadence SPI controller Device Tree Bindings -------------------------------------------- - -Required properties: -- compatible : Should be "cdns,spi-r1p6" or "xlnx,zynq-spi-r1p6". -- reg : Physical base address and size of SPI registers map. -- interrupts : Property with a value describing the interrupt - number. -- clock-names : List of input clock names - "ref_clk", "pclk" - (See clock bindings for details). -- clocks : Clock phandles (see clock bindings for details). - -Optional properties: -- num-cs : Number of chip selects used. - If a decoder is used, this will be the number of - chip selects after the decoder. -- is-decoded-cs : Flag to indicate whether decoder is used or not. - -Example: - - spi@e0007000 { - compatible = "xlnx,zynq-spi-r1p6"; - clock-names = "ref_clk", "pclk"; - clocks = <&clkc 26>, <&clkc 35>; - interrupt-parent = <&intc>; - interrupts = <0 49 4>; - num-cs = <4>; - is-decoded-cs = <0>; - reg = <0xe0007000 0x1000>; - } ; diff --git a/Documentation/devicetree/bindings/spi/spi-cadence.yaml b/Documentation/devicetree/bindings/spi/spi-cadence.yaml new file mode 100644 index 000000000000..9787be21318e --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-cadence.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/spi-cadence.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cadence SPI controller Device Tree Bindings + +maintainers: + - Michal Simek + +allOf: + - $ref: "spi-controller.yaml#" + +properties: + compatible: + enum: + - cdns,spi-r1p6 + - xlnx,zynq-spi-r1p6 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clock-names: + items: + - const: ref_clk + - const: pclk + + clocks: + maxItems: 2 + + num-cs: + description: | + Number of chip selects used. If a decoder is used, + this will be the number of chip selects after the + decoder. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 4 + default: 4 + + is-decoded-cs: + description: | + Flag to indicate whether decoder is used or not. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 1 ] + default: 0 + +unevaluatedProperties: false + +examples: + - | + spi@e0007000 { + compatible = "xlnx,zynq-spi-r1p6"; + clock-names = "ref_clk", "pclk"; + clocks = <&clkc 26>, <&clkc 35>; + interrupt-parent = <&intc>; + interrupts = <0 49 4>; + num-cs = <4>; + is-decoded-cs = <0>; + reg = <0xe0007000 0x1000>; + }; +... -- cgit v1.3.1 From 476ad3ff8952db3569a77d9ed4a067c5f0f4b733 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Sat, 5 Jun 2021 09:29:31 +0900 Subject: spi: xilinx: convert to yaml Convert SPI for Xilinx bindings documentation to YAML schemas. Signed-off-by: Nobuhiro Iwamatsu Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210605002931.858031-1-iwamatsu@nigauri.org Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-xilinx.txt | 23 --------- .../devicetree/bindings/spi/spi-xilinx.yaml | 57 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 23 deletions(-) delete mode 100644 Documentation/devicetree/bindings/spi/spi-xilinx.txt create mode 100644 Documentation/devicetree/bindings/spi/spi-xilinx.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-xilinx.txt b/Documentation/devicetree/bindings/spi/spi-xilinx.txt deleted file mode 100644 index 5f4ed3e5c994..000000000000 --- a/Documentation/devicetree/bindings/spi/spi-xilinx.txt +++ /dev/null @@ -1,23 +0,0 @@ -Xilinx SPI controller Device Tree Bindings -------------------------------------------------- - -Required properties: -- compatible : Should be "xlnx,xps-spi-2.00.a", "xlnx,xps-spi-2.00.b" or "xlnx,axi-quad-spi-1.00.a" -- reg : Physical base address and size of SPI registers map. -- interrupts : Property with a value describing the interrupt - number. - -Optional properties: -- xlnx,num-ss-bits : Number of chip selects used. -- xlnx,num-transfer-bits : Number of bits per transfer. This will be 8 if not specified - -Example: - axi_quad_spi@41e00000 { - compatible = "xlnx,xps-spi-2.00.a"; - interrupt-parent = <&intc>; - interrupts = <0 31 1>; - reg = <0x41e00000 0x10000>; - xlnx,num-ss-bits = <0x1>; - xlnx,num-transfer-bits = <32>; - }; - diff --git a/Documentation/devicetree/bindings/spi/spi-xilinx.yaml b/Documentation/devicetree/bindings/spi/spi-xilinx.yaml new file mode 100644 index 000000000000..593f7693bace --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-xilinx.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/spi-xilinx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Xilinx SPI controller Device Tree Bindings + +maintainers: + - Michal Simek + +allOf: + - $ref: "spi-controller.yaml#" + +properties: + compatible: + enum: + - xlnx,xps-spi-2.00.a + - xlnx,xps-spi-2.00.b + - xlnx,axi-quad-spi-1.00.a + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + xlnx,num-ss-bits: + description: Number of chip selects used. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 32 + + xlnx,num-transfer-bits: + description: Number of bits per transfer. This will be 8 if not specified. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [8, 16, 32] + default: 8 + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + spi0: spi@41e00000 { + compatible = "xlnx,xps-spi-2.00.a"; + interrupt-parent = <&intc>; + interrupts = <0 31 1>; + reg = <0x41e00000 0x10000>; + xlnx,num-ss-bits = <0x1>; + xlnx,num-transfer-bits = <32>; + }; +... -- cgit v1.3.1 From b10a038e84d188e15819058b2978b2daa9853aeb Mon Sep 17 00:00:00 2001 From: Ben Gardon Date: Tue, 18 May 2021 10:34:11 -0700 Subject: KVM: mmu: Add slots_arch_lock for memslot arch fields Add a new lock to protect the arch-specific fields of memslots if they need to be modified in a kvm->srcu read critical section. A future commit will use this lock to lazily allocate memslot rmaps for x86. Signed-off-by: Ben Gardon Message-Id: <20210518173414.450044-5-bgardon@google.com> [Add Documentation/ hunk. - Paolo] Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/locking.rst | 5 ++++ include/linux/kvm_host.h | 9 +++++++ virt/kvm/kvm_main.c | 54 +++++++++++++++++++++++++++++++++----- 3 files changed, 62 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/locking.rst b/Documentation/virt/kvm/locking.rst index 1fc860c007a3..35eca377543d 100644 --- a/Documentation/virt/kvm/locking.rst +++ b/Documentation/virt/kvm/locking.rst @@ -16,6 +16,11 @@ The acquisition orders for mutexes are as follows: - kvm->slots_lock is taken outside kvm->irq_lock, though acquiring them together is quite rare. +- Unlike kvm->slots_lock, kvm->slots_arch_lock is released before + synchronize_srcu(&kvm->srcu). Therefore kvm->slots_arch_lock + can be taken inside a kvm->srcu read-side critical section, + while kvm->slots_lock cannot. + On x86: - vcpu->mutex is taken outside kvm->arch.hyperv.hv_lock diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 8583ed3ff344..11b9b11a5e9b 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -523,6 +523,15 @@ struct kvm { #endif /* KVM_HAVE_MMU_RWLOCK */ struct mutex slots_lock; + + /* + * Protects the arch-specific fields of struct kvm_memory_slots in + * use by the VM. To be used under the slots_lock (above) or in a + * kvm->srcu critical section where acquiring the slots_lock would + * lead to deadlock with the synchronize_srcu in + * install_new_memslots. + */ + struct mutex slots_arch_lock; struct mm_struct *mm; /* userspace tied to this vm */ struct kvm_memslots __rcu *memslots[KVM_ADDRESS_SPACE_NUM]; struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index d65be9461493..fa7e7ebefc79 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -909,6 +909,7 @@ static struct kvm *kvm_create_vm(unsigned long type) mutex_init(&kvm->lock); mutex_init(&kvm->irq_lock); mutex_init(&kvm->slots_lock); + mutex_init(&kvm->slots_arch_lock); INIT_LIST_HEAD(&kvm->devices); BUILD_BUG_ON(KVM_MEM_SLOTS_NUM > SHRT_MAX); @@ -1281,6 +1282,14 @@ static struct kvm_memslots *install_new_memslots(struct kvm *kvm, slots->generation = gen | KVM_MEMSLOT_GEN_UPDATE_IN_PROGRESS; rcu_assign_pointer(kvm->memslots[as_id], slots); + + /* + * Acquired in kvm_set_memslot. Must be released before synchronize + * SRCU below in order to avoid deadlock with another thread + * acquiring the slots_arch_lock in an srcu critical section. + */ + mutex_unlock(&kvm->slots_arch_lock); + synchronize_srcu_expedited(&kvm->srcu); /* @@ -1352,9 +1361,27 @@ static int kvm_set_memslot(struct kvm *kvm, struct kvm_memslots *slots; int r; + /* + * Released in install_new_memslots. + * + * Must be held from before the current memslots are copied until + * after the new memslots are installed with rcu_assign_pointer, + * then released before the synchronize srcu in install_new_memslots. + * + * When modifying memslots outside of the slots_lock, must be held + * before reading the pointer to the current memslots until after all + * changes to those memslots are complete. + * + * These rules ensure that installing new memslots does not lose + * changes made to the previous memslots. + */ + mutex_lock(&kvm->slots_arch_lock); + slots = kvm_dup_memslots(__kvm_memslots(kvm, as_id), change); - if (!slots) + if (!slots) { + mutex_unlock(&kvm->slots_arch_lock); return -ENOMEM; + } if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) { /* @@ -1365,10 +1392,9 @@ static int kvm_set_memslot(struct kvm *kvm, slot->flags |= KVM_MEMSLOT_INVALID; /* - * We can re-use the old memslots, the only difference from the - * newly installed memslots is the invalid flag, which will get - * dropped by update_memslots anyway. We'll also revert to the - * old memslots if preparing the new memory region fails. + * We can re-use the memory from the old memslots. + * It will be overwritten with a copy of the new memslots + * after reacquiring the slots_arch_lock below. */ slots = install_new_memslots(kvm, as_id, slots); @@ -1380,6 +1406,17 @@ static int kvm_set_memslot(struct kvm *kvm, * - kvm_is_visible_gfn (mmu_check_root) */ kvm_arch_flush_shadow_memslot(kvm, slot); + + /* Released in install_new_memslots. */ + mutex_lock(&kvm->slots_arch_lock); + + /* + * The arch-specific fields of the memslots could have changed + * between releasing the slots_arch_lock in + * install_new_memslots and here, so get a fresh copy of the + * slots. + */ + kvm_copy_memslots(slots, __kvm_memslots(kvm, as_id)); } r = kvm_arch_prepare_memory_region(kvm, new, mem, change); @@ -1395,8 +1432,13 @@ static int kvm_set_memslot(struct kvm *kvm, return 0; out_slots: - if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) + if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) { + slot = id_to_memslot(slots, old->id); + slot->flags &= ~KVM_MEMSLOT_INVALID; slots = install_new_memslots(kvm, as_id, slots); + } else { + mutex_unlock(&kvm->slots_arch_lock); + } kvfree(slots); return r; } -- cgit v1.3.1 From 644f706719f0297bc5f65c8891de1c32f042eae5 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Fri, 21 May 2021 11:51:36 +0200 Subject: KVM: x86: hyper-v: Introduce KVM_CAP_HYPERV_ENFORCE_CPUID Modeled after KVM_CAP_ENFORCE_PV_FEATURE_CPUID, the new capability allows for limiting Hyper-V features to those exposed to the guest in Hyper-V CPUIDs (0x40000003, 0x40000004, ...). Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini Message-Id: <20210521095204.2161214-3-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 11 +++++++++++ arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/hyperv.c | 21 +++++++++++++++++++++ arch/x86/kvm/hyperv.h | 1 + arch/x86/kvm/x86.c | 4 ++++ include/uapi/linux/kvm.h | 1 + 6 files changed, 39 insertions(+) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 7fcb2fd38f42..80154d5d98a1 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6891,3 +6891,14 @@ This capability is always enabled. This capability indicates that the KVM virtual PTP service is supported in the host. A VMM can check whether the service is available to the guest on migration. + +8.33 KVM_CAP_HYPERV_ENFORCE_CPUID +----------------------------- + +Architectures: x86 + +When enabled, KVM will disable emulated Hyper-V features provided to the +guest according to the bits Hyper-V CPUID feature leaves. Otherwise, all +currently implmented Hyper-V features are provided unconditionally when +Hyper-V identification is set in the HYPERV_CPUID_INTERFACE (0x40000001) +leaf. diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 1fdb212127c4..556a8ec89451 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -543,6 +543,7 @@ struct kvm_vcpu_hv { struct kvm_vcpu_hv_stimer stimer[HV_SYNIC_STIMER_COUNT]; DECLARE_BITMAP(stimer_pending_bitmap, HV_SYNIC_STIMER_COUNT); cpumask_t tlb_flush; + bool enforce_cpuid; }; /* Xen HVM per vcpu emulation context */ diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index dbd3152b1379..02b0ee189f82 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1853,6 +1853,27 @@ void kvm_hv_set_cpuid(struct kvm_vcpu *vcpu) vcpu->arch.hyperv_enabled = false; } +int kvm_hv_set_enforce_cpuid(struct kvm_vcpu *vcpu, bool enforce) +{ + struct kvm_vcpu_hv *hv_vcpu; + int ret = 0; + + if (!to_hv_vcpu(vcpu)) { + if (enforce) { + ret = kvm_hv_vcpu_init(vcpu); + if (ret) + return ret; + } else { + return 0; + } + } + + hv_vcpu = to_hv_vcpu(vcpu); + hv_vcpu->enforce_cpuid = enforce; + + return ret; +} + bool kvm_hv_hypercall_enabled(struct kvm_vcpu *vcpu) { return vcpu->arch.hyperv_enabled && to_kvm_hv(vcpu->kvm)->hv_guest_os_id; diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h index 60547d5cb6d7..730da8537d05 100644 --- a/arch/x86/kvm/hyperv.h +++ b/arch/x86/kvm/hyperv.h @@ -138,6 +138,7 @@ void kvm_hv_invalidate_tsc_page(struct kvm *kvm); void kvm_hv_init_vm(struct kvm *kvm); void kvm_hv_destroy_vm(struct kvm *kvm); void kvm_hv_set_cpuid(struct kvm_vcpu *vcpu); +int kvm_hv_set_enforce_cpuid(struct kvm_vcpu *vcpu, bool enforce); int kvm_vm_ioctl_hv_eventfd(struct kvm *kvm, struct kvm_hyperv_eventfd *args); int kvm_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid, struct kvm_cpuid_entry2 __user *entries); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 63e48738764e..475376a97419 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3955,6 +3955,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_HYPERV_TLBFLUSH: case KVM_CAP_HYPERV_SEND_IPI: case KVM_CAP_HYPERV_CPUID: + case KVM_CAP_HYPERV_ENFORCE_CPUID: case KVM_CAP_SYS_HYPERV_CPUID: case KVM_CAP_PCI_SEGMENT: case KVM_CAP_DEBUGREGS: @@ -4878,6 +4879,9 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, return static_call(kvm_x86_enable_direct_tlbflush)(vcpu); + case KVM_CAP_HYPERV_ENFORCE_CPUID: + return kvm_hv_set_enforce_cpuid(vcpu, cap->args[0]); + case KVM_CAP_ENFORCE_PV_FEATURE_CPUID: vcpu->arch.pv_cpuid.enforce = cap->args[0]; if (vcpu->arch.pv_cpuid.enforce) diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 79d9c44d1ad7..792816144092 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1083,6 +1083,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_SGX_ATTRIBUTE 196 #define KVM_CAP_VM_COPY_ENC_CONTEXT_FROM 197 #define KVM_CAP_PTP_KVM 198 +#define KVM_CAP_HYPERV_ENFORCE_CPUID 199 #ifdef KVM_CAP_IRQ_ROUTING -- cgit v1.3.1 From 6dba940352038b56db9b591b172fb2ec76a5fd5e Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 7 Jun 2021 12:02:02 +0300 Subject: KVM: x86: Introduce KVM_GET_SREGS2 / KVM_SET_SREGS2 This is a new version of KVM_GET_SREGS / KVM_SET_SREGS. It has the following changes: * Has flags for future extensions * Has vcpu's PDPTRs, allowing to save/restore them on migration. * Lacks obsolete interrupt bitmap (done now via KVM_SET_VCPU_EVENTS) New capability, KVM_CAP_SREGS2 is added to signal the userspace of this ioctl. Signed-off-by: Maxim Levitsky Message-Id: <20210607090203.133058-8-mlevitsk@redhat.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 48 ++++++++++++++ arch/x86/include/uapi/asm/kvm.h | 13 ++++ arch/x86/kvm/kvm_cache_regs.h | 5 ++ arch/x86/kvm/x86.c | 142 ++++++++++++++++++++++++++++++++-------- include/uapi/linux/kvm.h | 4 ++ 5 files changed, 185 insertions(+), 27 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 80154d5d98a1..cded99561adf 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -5034,6 +5034,54 @@ see KVM_XEN_VCPU_SET_ATTR above. The KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST type may not be used with the KVM_XEN_VCPU_GET_ATTR ioctl. + +4.131 KVM_GET_SREGS2 +------------------ + +:Capability: KVM_CAP_SREGS2 +:Architectures: x86 +:Type: vcpu ioctl +:Parameters: struct kvm_sregs2 (out) +:Returns: 0 on success, -1 on error + +Reads special registers from the vcpu. +This ioctl (when supported) replaces the KVM_GET_SREGS. + +:: + +struct kvm_sregs2 { + /* out (KVM_GET_SREGS2) / in (KVM_SET_SREGS2) */ + struct kvm_segment cs, ds, es, fs, gs, ss; + struct kvm_segment tr, ldt; + struct kvm_dtable gdt, idt; + __u64 cr0, cr2, cr3, cr4, cr8; + __u64 efer; + __u64 apic_base; + __u64 flags; + __u64 pdptrs[4]; +}; + +flags values for ``kvm_sregs2``: + +``KVM_SREGS2_FLAGS_PDPTRS_VALID`` + + Indicates thats the struct contain valid PDPTR values. + + +4.132 KVM_SET_SREGS2 +------------------ + +:Capability: KVM_CAP_SREGS2 +:Architectures: x86 +:Type: vcpu ioctl +:Parameters: struct kvm_sregs2 (in) +:Returns: 0 on success, -1 on error + +Writes special registers into the vcpu. +See KVM_GET_SREGS2 for the data structures. +This ioctl (when supported) replaces the KVM_SET_SREGS. + + 5. The kvm_run structure ======================== diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 0662f644aad9..a6c327f8ad9e 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -159,6 +159,19 @@ struct kvm_sregs { __u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64]; }; +struct kvm_sregs2 { + /* out (KVM_GET_SREGS2) / in (KVM_SET_SREGS2) */ + struct kvm_segment cs, ds, es, fs, gs, ss; + struct kvm_segment tr, ldt; + struct kvm_dtable gdt, idt; + __u64 cr0, cr2, cr3, cr4, cr8; + __u64 efer; + __u64 apic_base; + __u64 flags; + __u64 pdptrs[4]; +}; +#define KVM_SREGS2_FLAGS_PDPTRS_VALID 1 + /* for KVM_GET_FPU and KVM_SET_FPU */ struct kvm_fpu { __u8 fpr[8][16]; diff --git a/arch/x86/kvm/kvm_cache_regs.h b/arch/x86/kvm/kvm_cache_regs.h index 296d67f689ef..90e1ffdc05b7 100644 --- a/arch/x86/kvm/kvm_cache_regs.h +++ b/arch/x86/kvm/kvm_cache_regs.h @@ -125,6 +125,11 @@ static inline u64 kvm_pdptr_read(struct kvm_vcpu *vcpu, int index) return vcpu->arch.walk_mmu->pdptrs[index]; } +static inline void kvm_pdptr_write(struct kvm_vcpu *vcpu, int index, u64 value) +{ + vcpu->arch.walk_mmu->pdptrs[index] = value; +} + static inline ulong kvm_read_cr0_bits(struct kvm_vcpu *vcpu, ulong mask) { ulong tmask = mask & KVM_POSSIBLE_CR0_GUEST_BITS; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 188c180d9f6e..8085ab830c80 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -114,6 +114,9 @@ static void __kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags); static void store_regs(struct kvm_vcpu *vcpu); static int sync_regs(struct kvm_vcpu *vcpu); +static int __set_sregs2(struct kvm_vcpu *vcpu, struct kvm_sregs2 *sregs2); +static void __get_sregs2(struct kvm_vcpu *vcpu, struct kvm_sregs2 *sregs2); + struct kvm_x86_ops kvm_x86_ops __read_mostly; EXPORT_SYMBOL_GPL(kvm_x86_ops); @@ -817,7 +820,6 @@ int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3) memcpy(mmu->pdptrs, pdpte, sizeof(mmu->pdptrs)); kvm_register_mark_dirty(vcpu, VCPU_EXREG_PDPTR); - out: return ret; @@ -3956,6 +3958,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_SGX_ATTRIBUTE: #endif case KVM_CAP_VM_COPY_ENC_CONTEXT_FROM: + case KVM_CAP_SREGS2: r = 1; break; case KVM_CAP_SET_GUEST_DEBUG2: @@ -4870,6 +4873,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, void __user *argp = (void __user *)arg; int r; union { + struct kvm_sregs2 *sregs2; struct kvm_lapic_state *lapic; struct kvm_xsave *xsave; struct kvm_xcrs *xcrs; @@ -5242,6 +5246,28 @@ long kvm_arch_vcpu_ioctl(struct file *filp, break; } #endif + case KVM_GET_SREGS2: { + u.sregs2 = kzalloc(sizeof(struct kvm_sregs2), GFP_KERNEL); + r = -ENOMEM; + if (!u.sregs2) + goto out; + __get_sregs2(vcpu, u.sregs2); + r = -EFAULT; + if (copy_to_user(argp, u.sregs2, sizeof(struct kvm_sregs2))) + goto out; + r = 0; + break; + } + case KVM_SET_SREGS2: { + u.sregs2 = memdup_user(argp, sizeof(struct kvm_sregs2)); + if (IS_ERR(u.sregs2)) { + r = PTR_ERR(u.sregs2); + u.sregs2 = NULL; + goto out; + } + r = __set_sregs2(vcpu, u.sregs2); + break; + } default: r = -EINVAL; } @@ -9937,7 +9963,7 @@ void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) } EXPORT_SYMBOL_GPL(kvm_get_cs_db_l_bits); -static void __get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) +static void __get_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { struct desc_ptr dt; @@ -9970,14 +9996,36 @@ skip_protected_regs: sregs->cr8 = kvm_get_cr8(vcpu); sregs->efer = vcpu->arch.efer; sregs->apic_base = kvm_get_apic_base(vcpu); +} - memset(sregs->interrupt_bitmap, 0, sizeof(sregs->interrupt_bitmap)); +static void __get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) +{ + __get_sregs_common(vcpu, sregs); + + if (vcpu->arch.guest_state_protected) + return; if (vcpu->arch.interrupt.injected && !vcpu->arch.interrupt.soft) set_bit(vcpu->arch.interrupt.nr, (unsigned long *)sregs->interrupt_bitmap); } +static void __get_sregs2(struct kvm_vcpu *vcpu, struct kvm_sregs2 *sregs2) +{ + int i; + + __get_sregs_common(vcpu, (struct kvm_sregs *)sregs2); + + if (vcpu->arch.guest_state_protected) + return; + + if (is_pae_paging(vcpu)) { + for (i = 0 ; i < 4 ; i++) + sregs2->pdptrs[i] = kvm_pdptr_read(vcpu, i); + sregs2->flags |= KVM_SREGS2_FLAGS_PDPTRS_VALID; + } +} + int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { @@ -10096,24 +10144,23 @@ static bool kvm_is_valid_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) return kvm_is_valid_cr4(vcpu, sregs->cr4); } -static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) +static int __set_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs, + int *mmu_reset_needed, bool update_pdptrs) { struct msr_data apic_base_msr; - int mmu_reset_needed = 0; - int pending_vec, max_bits, idx; + int idx; struct desc_ptr dt; - int ret = -EINVAL; if (!kvm_is_valid_sregs(vcpu, sregs)) - goto out; + return -EINVAL; apic_base_msr.data = sregs->apic_base; apic_base_msr.host_initiated = true; if (kvm_set_apic_base(vcpu, &apic_base_msr)) - goto out; + return -EINVAL; if (vcpu->arch.guest_state_protected) - goto skip_protected_regs; + return 0; dt.size = sregs->idt.limit; dt.address = sregs->idt.base; @@ -10123,31 +10170,30 @@ static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) static_call(kvm_x86_set_gdt)(vcpu, &dt); vcpu->arch.cr2 = sregs->cr2; - mmu_reset_needed |= kvm_read_cr3(vcpu) != sregs->cr3; + *mmu_reset_needed |= kvm_read_cr3(vcpu) != sregs->cr3; vcpu->arch.cr3 = sregs->cr3; kvm_register_mark_available(vcpu, VCPU_EXREG_CR3); kvm_set_cr8(vcpu, sregs->cr8); - mmu_reset_needed |= vcpu->arch.efer != sregs->efer; + *mmu_reset_needed |= vcpu->arch.efer != sregs->efer; static_call(kvm_x86_set_efer)(vcpu, sregs->efer); - mmu_reset_needed |= kvm_read_cr0(vcpu) != sregs->cr0; + *mmu_reset_needed |= kvm_read_cr0(vcpu) != sregs->cr0; static_call(kvm_x86_set_cr0)(vcpu, sregs->cr0); vcpu->arch.cr0 = sregs->cr0; - mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4; + *mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4; static_call(kvm_x86_set_cr4)(vcpu, sregs->cr4); - idx = srcu_read_lock(&vcpu->kvm->srcu); - if (is_pae_paging(vcpu)) { - load_pdptrs(vcpu, vcpu->arch.walk_mmu, kvm_read_cr3(vcpu)); - mmu_reset_needed = 1; + if (update_pdptrs) { + idx = srcu_read_lock(&vcpu->kvm->srcu); + if (is_pae_paging(vcpu)) { + load_pdptrs(vcpu, vcpu->arch.walk_mmu, kvm_read_cr3(vcpu)); + *mmu_reset_needed = 1; + } + srcu_read_unlock(&vcpu->kvm->srcu, idx); } - srcu_read_unlock(&vcpu->kvm->srcu, idx); - - if (mmu_reset_needed) - kvm_mmu_reset_context(vcpu); kvm_set_segment(vcpu, &sregs->cs, VCPU_SREG_CS); kvm_set_segment(vcpu, &sregs->ds, VCPU_SREG_DS); @@ -10167,20 +10213,62 @@ static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) !is_protmode(vcpu)) vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; -skip_protected_regs: + return 0; +} + +static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) +{ + int pending_vec, max_bits; + int mmu_reset_needed = 0; + int ret = __set_sregs_common(vcpu, sregs, &mmu_reset_needed, true); + + if (ret) + return ret; + + if (mmu_reset_needed) + kvm_mmu_reset_context(vcpu); + max_bits = KVM_NR_INTERRUPTS; pending_vec = find_first_bit( (const unsigned long *)sregs->interrupt_bitmap, max_bits); + if (pending_vec < max_bits) { kvm_queue_interrupt(vcpu, pending_vec, false); pr_debug("Set back pending irq %d\n", pending_vec); + kvm_make_request(KVM_REQ_EVENT, vcpu); } + return 0; +} - kvm_make_request(KVM_REQ_EVENT, vcpu); +static int __set_sregs2(struct kvm_vcpu *vcpu, struct kvm_sregs2 *sregs2) +{ + int mmu_reset_needed = 0; + bool valid_pdptrs = sregs2->flags & KVM_SREGS2_FLAGS_PDPTRS_VALID; + bool pae = (sregs2->cr0 & X86_CR0_PG) && (sregs2->cr4 & X86_CR4_PAE) && + !(sregs2->efer & EFER_LMA); + int i, ret; - ret = 0; -out: - return ret; + if (sregs2->flags & ~KVM_SREGS2_FLAGS_PDPTRS_VALID) + return -EINVAL; + + if (valid_pdptrs && (!pae || vcpu->arch.guest_state_protected)) + return -EINVAL; + + ret = __set_sregs_common(vcpu, (struct kvm_sregs *)sregs2, + &mmu_reset_needed, !valid_pdptrs); + if (ret) + return ret; + + if (valid_pdptrs) { + for (i = 0; i < 4 ; i++) + kvm_pdptr_write(vcpu, i, sregs2->pdptrs[i]); + + kvm_register_mark_dirty(vcpu, VCPU_EXREG_PDPTR); + mmu_reset_needed = 1; + } + if (mmu_reset_needed) + kvm_mmu_reset_context(vcpu); + return 0; } int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 792816144092..90d44138dbfb 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1084,6 +1084,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_VM_COPY_ENC_CONTEXT_FROM 197 #define KVM_CAP_PTP_KVM 198 #define KVM_CAP_HYPERV_ENFORCE_CPUID 199 +#define KVM_CAP_SREGS2 200 #ifdef KVM_CAP_IRQ_ROUTING @@ -1622,6 +1623,9 @@ struct kvm_xen_hvm_attr { #define KVM_XEN_VCPU_GET_ATTR _IOWR(KVMIO, 0xca, struct kvm_xen_vcpu_attr) #define KVM_XEN_VCPU_SET_ATTR _IOW(KVMIO, 0xcb, struct kvm_xen_vcpu_attr) +#define KVM_GET_SREGS2 _IOR(KVMIO, 0xcc, struct kvm_sregs2) +#define KVM_SET_SREGS2 _IOW(KVMIO, 0xcd, struct kvm_sregs2) + struct kvm_xen_vcpu_attr { __u16 type; __u16 pad[3]; -- cgit v1.3.1 From 0dbb11230437895f7cd6fc55da61cef011e997d8 Mon Sep 17 00:00:00 2001 From: Ashish Kalra Date: Tue, 8 Jun 2021 18:05:43 +0000 Subject: KVM: X86: Introduce KVM_HC_MAP_GPA_RANGE hypercall This hypercall is used by the SEV guest to notify a change in the page encryption status to the hypervisor. The hypercall should be invoked only when the encryption attribute is changed from encrypted -> decrypted and vice versa. By default all guest pages are considered encrypted. The hypercall exits to userspace to manage the guest shared regions and integrate with the userspace VMM's migration code. Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Paolo Bonzini Cc: Joerg Roedel Cc: Borislav Petkov Cc: Tom Lendacky Cc: x86@kernel.org Cc: kvm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Reviewed-by: Steve Rutherford Signed-off-by: Brijesh Singh Signed-off-by: Ashish Kalra Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson Co-developed-by: Paolo Bonzini Signed-off-by: Paolo Bonzini Message-Id: <90778988e1ee01926ff9cac447aacb745f954c8c.1623174621.git.ashish.kalra@amd.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 19 +++++++++++++++ Documentation/virt/kvm/cpuid.rst | 7 ++++++ Documentation/virt/kvm/hypercalls.rst | 21 ++++++++++++++++ Documentation/virt/kvm/msr.rst | 13 ++++++++++ arch/x86/include/asm/kvm_host.h | 2 ++ arch/x86/include/uapi/asm/kvm_para.h | 13 ++++++++++ arch/x86/kvm/x86.c | 46 +++++++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 1 + include/uapi/linux/kvm_para.h | 1 + 9 files changed, 123 insertions(+) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index cded99561adf..e328caa35d6c 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6950,3 +6950,22 @@ guest according to the bits Hyper-V CPUID feature leaves. Otherwise, all currently implmented Hyper-V features are provided unconditionally when Hyper-V identification is set in the HYPERV_CPUID_INTERFACE (0x40000001) leaf. + +8.34 KVM_CAP_EXIT_HYPERCALL +--------------------------- + +:Capability: KVM_CAP_EXIT_HYPERCALL +:Architectures: x86 +:Type: vm + +This capability, if enabled, will cause KVM to exit to userspace +with KVM_EXIT_HYPERCALL exit reason to process some hypercalls. + +Calling KVM_CHECK_EXTENSION for this capability will return a bitmask +of hypercalls that can be configured to exit to userspace. +Right now, the only such hypercall is KVM_HC_MAP_GPA_RANGE. + +The argument to KVM_ENABLE_CAP is also a bitmask, and must be a subset +of the result of KVM_CHECK_EXTENSION. KVM will forward to userspace +the hypercalls whose corresponding bit is in the argument, and return +ENOSYS for the others. diff --git a/Documentation/virt/kvm/cpuid.rst b/Documentation/virt/kvm/cpuid.rst index cf62162d4be2..bda3e3e737d7 100644 --- a/Documentation/virt/kvm/cpuid.rst +++ b/Documentation/virt/kvm/cpuid.rst @@ -96,6 +96,13 @@ KVM_FEATURE_MSI_EXT_DEST_ID 15 guest checks this feature bit before using extended destination ID bits in MSI address bits 11-5. +KVM_FEATURE_HC_MAP_GPA_RANGE 16 guest checks this feature bit before + using the map gpa range hypercall + to notify the page state change + +KVM_FEATURE_MIGRATION_CONTROL 17 guest checks this feature bit before + using MSR_KVM_MIGRATION_CONTROL + KVM_FEATURE_CLOCKSOURCE_STABLE_BIT 24 host will warn if no guest-side per-cpu warps are expected in kvmclock diff --git a/Documentation/virt/kvm/hypercalls.rst b/Documentation/virt/kvm/hypercalls.rst index ed4fddd364ea..e56fa8b9cfca 100644 --- a/Documentation/virt/kvm/hypercalls.rst +++ b/Documentation/virt/kvm/hypercalls.rst @@ -169,3 +169,24 @@ a0: destination APIC ID :Usage example: When sending a call-function IPI-many to vCPUs, yield if any of the IPI target vCPUs was preempted. + +8. KVM_HC_MAP_GPA_RANGE +------------------------- +:Architecture: x86 +:Status: active +:Purpose: Request KVM to map a GPA range with the specified attributes. + +a0: the guest physical address of the start page +a1: the number of (4kb) pages (must be contiguous in GPA space) +a2: attributes + + Where 'attributes' : + * bits 3:0 - preferred page size encoding 0 = 4kb, 1 = 2mb, 2 = 1gb, etc... + * bit 4 - plaintext = 0, encrypted = 1 + * bits 63:5 - reserved (must be zero) + +**Implementation note**: this hypercall is implemented in userspace via +the KVM_CAP_EXIT_HYPERCALL capability. Userspace must enable that capability +before advertising KVM_FEATURE_HC_MAP_GPA_RANGE in the guest CPUID. In +addition, if the guest supports KVM_FEATURE_MIGRATION_CONTROL, userspace +must also set up an MSR filter to process writes to MSR_KVM_MIGRATION_CONTROL. diff --git a/Documentation/virt/kvm/msr.rst b/Documentation/virt/kvm/msr.rst index e37a14c323d2..9315fc385fb0 100644 --- a/Documentation/virt/kvm/msr.rst +++ b/Documentation/virt/kvm/msr.rst @@ -376,3 +376,16 @@ data: write '1' to bit 0 of the MSR, this causes the host to re-scan its queue and check if there are more notifications pending. The MSR is available if KVM_FEATURE_ASYNC_PF_INT is present in CPUID. + +MSR_KVM_MIGRATION_CONTROL: + 0x4b564d08 + +data: + This MSR is available if KVM_FEATURE_MIGRATION_CONTROL is present in + CPUID. Bit 0 represents whether live migration of the guest is allowed. + + When a guest is started, bit 0 will be 0 if the guest has encrypted + memory and 1 if the guest does not have encrypted memory. If the + guest is communicating page encryption status to the host using the + ``KVM_HC_MAP_GPA_RANGE`` hypercall, it can set bit 0 in this MSR to + allow live migration of the guest. diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index a0c29e29dd48..e11d64aa0bcd 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1087,6 +1087,8 @@ struct kvm_arch { u32 user_space_msr_mask; struct kvm_x86_msr_filter __rcu *msr_filter; + u32 hypercall_exit_enabled; + /* Guest can access the SGX PROVISIONKEY. */ bool sgx_provisioning_allowed; diff --git a/arch/x86/include/uapi/asm/kvm_para.h b/arch/x86/include/uapi/asm/kvm_para.h index 950afebfba88..5146bbab84d4 100644 --- a/arch/x86/include/uapi/asm/kvm_para.h +++ b/arch/x86/include/uapi/asm/kvm_para.h @@ -33,6 +33,8 @@ #define KVM_FEATURE_PV_SCHED_YIELD 13 #define KVM_FEATURE_ASYNC_PF_INT 14 #define KVM_FEATURE_MSI_EXT_DEST_ID 15 +#define KVM_FEATURE_HC_MAP_GPA_RANGE 16 +#define KVM_FEATURE_MIGRATION_CONTROL 17 #define KVM_HINTS_REALTIME 0 @@ -54,6 +56,7 @@ #define MSR_KVM_POLL_CONTROL 0x4b564d05 #define MSR_KVM_ASYNC_PF_INT 0x4b564d06 #define MSR_KVM_ASYNC_PF_ACK 0x4b564d07 +#define MSR_KVM_MIGRATION_CONTROL 0x4b564d08 struct kvm_steal_time { __u64 steal; @@ -90,6 +93,16 @@ struct kvm_clock_pairing { /* MSR_KVM_ASYNC_PF_INT */ #define KVM_ASYNC_PF_VEC_MASK GENMASK(7, 0) +/* MSR_KVM_MIGRATION_CONTROL */ +#define KVM_MIGRATION_READY (1 << 0) + +/* KVM_HC_MAP_GPA_RANGE */ +#define KVM_MAP_GPA_RANGE_PAGE_SZ_4K 0 +#define KVM_MAP_GPA_RANGE_PAGE_SZ_2M (1 << 0) +#define KVM_MAP_GPA_RANGE_PAGE_SZ_1G (1 << 1) +#define KVM_MAP_GPA_RANGE_ENC_STAT(n) (n << 4) +#define KVM_MAP_GPA_RANGE_ENCRYPTED KVM_MAP_GPA_RANGE_ENC_STAT(1) +#define KVM_MAP_GPA_RANGE_DECRYPTED KVM_MAP_GPA_RANGE_ENC_STAT(0) /* Operations for KVM_HC_MMU_OP */ #define KVM_MMU_OP_WRITE_PTE 1 diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ceb60f64085c..8b898ec8d349 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -103,6 +103,8 @@ static u64 __read_mostly efer_reserved_bits = ~((u64)EFER_SCE); static u64 __read_mostly cr4_reserved_bits = CR4_RESERVED_BITS; +#define KVM_EXIT_HYPERCALL_VALID_MASK (1 << KVM_HC_MAP_GPA_RANGE) + #define KVM_X2APIC_API_VALID_FLAGS (KVM_X2APIC_API_USE_32BIT_IDS | \ KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK) @@ -3996,6 +3998,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_SREGS2: r = 1; break; + case KVM_CAP_EXIT_HYPERCALL: + r = KVM_EXIT_HYPERCALL_VALID_MASK; + break; case KVM_CAP_SET_GUEST_DEBUG2: return KVM_GUESTDBG_VALID_MASK; #ifdef CONFIG_KVM_XEN @@ -5622,6 +5627,14 @@ split_irqchip_unlock: if (kvm_x86_ops.vm_copy_enc_context_from) r = kvm_x86_ops.vm_copy_enc_context_from(kvm, cap->args[0]); return r; + case KVM_CAP_EXIT_HYPERCALL: + if (cap->args[0] & ~KVM_EXIT_HYPERCALL_VALID_MASK) { + r = -EINVAL; + break; + } + kvm->arch.hypercall_exit_enabled = cap->args[0]; + r = 0; + break; default: r = -EINVAL; break; @@ -8548,6 +8561,17 @@ no_yield: return; } +static int complete_hypercall_exit(struct kvm_vcpu *vcpu) +{ + u64 ret = vcpu->run->hypercall.ret; + + if (!is_64_bit_mode(vcpu)) + ret = (u32)ret; + kvm_rax_write(vcpu, ret); + ++vcpu->stat.hypercalls; + return kvm_skip_emulated_instruction(vcpu); +} + int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) { unsigned long nr, a0, a1, a2, a3, ret; @@ -8613,6 +8637,28 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) kvm_sched_yield(vcpu, a0); ret = 0; break; + case KVM_HC_MAP_GPA_RANGE: { + u64 gpa = a0, npages = a1, attrs = a2; + + ret = -KVM_ENOSYS; + if (!(vcpu->kvm->arch.hypercall_exit_enabled & (1 << KVM_HC_MAP_GPA_RANGE))) + break; + + if (!PAGE_ALIGNED(gpa) || !npages || + gpa_to_gfn(gpa) + npages <= gpa_to_gfn(gpa)) { + ret = -KVM_EINVAL; + break; + } + + vcpu->run->exit_reason = KVM_EXIT_HYPERCALL; + vcpu->run->hypercall.nr = KVM_HC_MAP_GPA_RANGE; + vcpu->run->hypercall.args[0] = gpa; + vcpu->run->hypercall.args[1] = npages; + vcpu->run->hypercall.args[2] = attrs; + vcpu->run->hypercall.longmode = op_64_bit; + vcpu->arch.complete_userspace_io = complete_hypercall_exit; + return 0; + } default: ret = -KVM_ENOSYS; break; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 90d44138dbfb..9febe1412f7a 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1085,6 +1085,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_PTP_KVM 198 #define KVM_CAP_HYPERV_ENFORCE_CPUID 199 #define KVM_CAP_SREGS2 200 +#define KVM_CAP_EXIT_HYPERCALL 201 #ifdef KVM_CAP_IRQ_ROUTING diff --git a/include/uapi/linux/kvm_para.h b/include/uapi/linux/kvm_para.h index 8b86609849b9..960c7e93d1a9 100644 --- a/include/uapi/linux/kvm_para.h +++ b/include/uapi/linux/kvm_para.h @@ -29,6 +29,7 @@ #define KVM_HC_CLOCK_PAIRING 9 #define KVM_HC_SEND_IPI 10 #define KVM_HC_SCHED_YIELD 11 +#define KVM_HC_MAP_GPA_RANGE 12 /* * hypercalls use architecture specific -- cgit v1.3.1 From ae1b2aaee7e215f985bf10aad8978f524d8dca60 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Thu, 17 Jun 2021 10:33:00 +0800 Subject: Documentation: ACPI: fix error script name The correct script name should be 'divergence.sh' instead of 'divergences.sh'. I didn't find divergences.sh in the path of acpica/generate/linux/. Signed-off-by: Hao Chen Link: https://lore.kernel.org/r/20210617023300.30114-1-chenhaoa@uniontech.com Signed-off-by: Jonathan Corbet --- Documentation/driver-api/acpi/linuxized-acpica.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/driver-api/acpi/linuxized-acpica.rst b/Documentation/driver-api/acpi/linuxized-acpica.rst index 6bee03383225..cc234353d2c4 100644 --- a/Documentation/driver-api/acpi/linuxized-acpica.rst +++ b/Documentation/driver-api/acpi/linuxized-acpica.rst @@ -276,4 +276,4 @@ before they become available from the ACPICA release process. # git clone https://github.com/acpica/acpica # git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git # cd acpica - # generate/linux/divergences.sh -s ../linux + # generate/linux/divergence.sh -s ../linux -- cgit v1.3.1 From 349660e944b5bcb82df1dbb2156ced9fc9c05351 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:55:07 +0200 Subject: docs: admin-guide: reporting-issues.rst: replace some characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion tools used during DocBook/LaTeX/html/Markdown->ReST conversion and some cut-and-pasted text contain some characters that aren't easily reachable on standard keyboards and/or could cause troubles when parsed by the documentation build system. Replace the occurences of the following characters: - U+00a0 (' '): NO-BREAK SPACE as it can cause lines being truncated on PDF output Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/551a2af0e654226067e5c376d3e2d959cc738f39.1623826294.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/admin-guide/reporting-issues.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/reporting-issues.rst b/Documentation/admin-guide/reporting-issues.rst index 18d8e25ba9df..d7ac13f789cc 100644 --- a/Documentation/admin-guide/reporting-issues.rst +++ b/Documentation/admin-guide/reporting-issues.rst @@ -1248,7 +1248,7 @@ paragraph makes the severeness obvious. In case you performed a successful bisection, use the title of the change that introduced the regression as the second part of your subject. Make the report -also mention the commit id of the culprit. In case of an unsuccessful bisection, +also mention the commit id of the culprit. In case of an unsuccessful bisection, make your report mention the latest tested version that's working fine (say 5.7) and the oldest where the issue occurs (say 5.8-rc1). -- cgit v1.3.1 From 90f40f514f907f0b12873a7337ea638731848ff2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:55:08 +0200 Subject: docs: trace: coresight: coresight-etm4x-reference.rst: replace some characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion tools used during DocBook/LaTeX/html/Markdown->ReST conversion and some cut-and-pasted text contain some characters that aren't easily reachable on standard keyboards and/or could cause troubles when parsed by the documentation build system. Replace the occurences of the following characters: - U+00a0 (' '): NO-BREAK SPACE as it can cause lines being truncated on PDF output Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/b6a04e881bc80a3c1d3d23ccbc8208ca3c9053fd.1623826294.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/trace/coresight/coresight-etm4x-reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/trace/coresight/coresight-etm4x-reference.rst b/Documentation/trace/coresight/coresight-etm4x-reference.rst index b64d9a9c79df..d25dfe86af9b 100644 --- a/Documentation/trace/coresight/coresight-etm4x-reference.rst +++ b/Documentation/trace/coresight/coresight-etm4x-reference.rst @@ -427,7 +427,7 @@ the ‘TRC’ prefix. :Syntax: ``echo idx > vmid_idx`` - Where idx <  numvmidc + Where idx < numvmidc ---- -- cgit v1.3.1 From f40c2a25b9c33b08ad2098f64b7d1cbaa3daab9f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:55:09 +0200 Subject: docs: driver-api: ioctl.rst: replace some characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion tools used during DocBook/LaTeX/html/Markdown->ReST conversion and some cut-and-pasted text contain some characters that aren't easily reachable on standard keyboards and/or could cause troubles when parsed by the documentation build system. Replace the occurences of the following characters: - U+00a0 (' '): NO-BREAK SPACE as it can cause lines being truncated on PDF output Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/b2186e313f990488ded56d9b8d35a2d1fe479aa1.1623826294.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/driver-api/ioctl.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/driver-api/ioctl.rst b/Documentation/driver-api/ioctl.rst index c455db0e1627..5b76e765827d 100644 --- a/Documentation/driver-api/ioctl.rst +++ b/Documentation/driver-api/ioctl.rst @@ -25,9 +25,9 @@ ioctl commands that follow modern conventions: ``_IO``, ``_IOR``, with the correct parameters: _IO/_IOR/_IOW/_IOWR - The macro name specifies how the argument will be used.  It may be a + The macro name specifies how the argument will be used. It may be a pointer to data to be passed into the kernel (_IOW), out of the kernel - (_IOR), or both (_IOWR).  _IO can indicate either commands with no + (_IOR), or both (_IOWR). _IO can indicate either commands with no argument or those passing an integer value instead of a pointer. It is recommended to only use _IO for commands without arguments, and use pointers for passing data. @@ -200,10 +200,10 @@ cause an information leak, which can be used to defeat kernel address space layout randomization (KASLR), helping in an attack. For this reason (and for compat support) it is best to avoid any -implicit padding in data structures.  Where there is implicit padding +implicit padding in data structures. Where there is implicit padding in an existing structure, kernel drivers must be careful to fully initialize an instance of the structure before copying it to user -space.  This is usually done by calling memset() before assigning to +space. This is usually done by calling memset() before assigning to individual members. Subsystem abstractions -- cgit v1.3.1 From 570eb861243c07f2c3923af428ed20cd3f9d0a29 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:55:10 +0200 Subject: docs: usb: replace some characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion tools used during DocBook/LaTeX/html/Markdown->ReST conversion and some cut-and-pasted text contain some characters that aren't easily reachable on standard keyboards and/or could cause troubles when parsed by the documentation build system. Replace the occurences of the following characters: - U+feff (''): BOM as it is not needed on UTF-8 Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/0a4b0c38a9cd1133402a04a7ff60fefd9682d42e.1623826294.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/usb/ehci.rst | 2 +- Documentation/usb/gadget_printer.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/usb/ehci.rst b/Documentation/usb/ehci.rst index 31f650e7c1b4..76190501907a 100644 --- a/Documentation/usb/ehci.rst +++ b/Documentation/usb/ehci.rst @@ -1,4 +1,4 @@ -=========== +=========== EHCI driver =========== diff --git a/Documentation/usb/gadget_printer.rst b/Documentation/usb/gadget_printer.rst index 5e5516c69075..e611a6d91093 100644 --- a/Documentation/usb/gadget_printer.rst +++ b/Documentation/usb/gadget_printer.rst @@ -1,4 +1,4 @@ -=============================== +=============================== Linux USB Printer Gadget Driver =============================== -- cgit v1.3.1 From 1a967a312270356c249466b10bb39890a96e301e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:55:11 +0200 Subject: docs: vm: zswap.rst: replace some characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion tools used during DocBook/LaTeX/html/Markdown->ReST conversion and some cut-and-pasted text contain some characters that aren't easily reachable on standard keyboards and/or could cause troubles when parsed by the documentation build system. Replace the occurences of the following characters: - U+00a0 (' '): NO-BREAK SPACE as it can cause lines being truncated on PDF output Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/9a93b72f99f8f3328269076ceff50248ac9c5af5.1623826294.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/vm/zswap.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/vm/zswap.rst b/Documentation/vm/zswap.rst index d8d9fa4a1f0d..8edb8d578caf 100644 --- a/Documentation/vm/zswap.rst +++ b/Documentation/vm/zswap.rst @@ -10,7 +10,7 @@ Overview Zswap is a lightweight compressed cache for swap pages. It takes pages that are in the process of being swapped out and attempts to compress them into a dynamically allocated RAM-based memory pool. zswap basically trades CPU cycles -for potentially reduced swap I/O.  This trade-off can also result in a +for potentially reduced swap I/O. This trade-off can also result in a significant performance improvement if reads from the compressed cache are faster than reads from a swap device. @@ -26,7 +26,7 @@ faster than reads from a swap device. performance impact of swapping. * Overcommitted guests that share a common I/O resource can dramatically reduce their swap I/O pressure, avoiding heavy handed I/O - throttling by the hypervisor. This allows more work to get done with less + throttling by the hypervisor. This allows more work to get done with less impact to the guest workload and guests sharing the I/O subsystem * Users with SSDs as swap devices can extend the life of the device by drastically reducing life-shortening writes. -- cgit v1.3.1 From d9d2c82738b7cacefde30b701d2ddc4879f6c39a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:55:12 +0200 Subject: docs: filesystems: ext4: blockgroup.rst: replace some characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion tools used during DocBook/LaTeX/html/Markdown->ReST conversion and some cut-and-pasted text contain some characters that aren't easily reachable on standard keyboards and/or could cause troubles when parsed by the documentation build system. Replace the occurences of the following characters: - U+2217 ('∗'): ASTERISK OPERATOR use ASCII asterisk instead of the ASTERISK OPERATOR Signed-off-by: Mauro Carvalho Chehab Acked-by: Theodore Ts'o Link: https://lore.kernel.org/r/c5c3c384c48779ca7c9dcd90183cefe20ac82928.1623826294.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/filesystems/ext4/blockgroup.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/ext4/blockgroup.rst b/Documentation/filesystems/ext4/blockgroup.rst index 3da156633339..d5d652addce5 100644 --- a/Documentation/filesystems/ext4/blockgroup.rst +++ b/Documentation/filesystems/ext4/blockgroup.rst @@ -84,7 +84,7 @@ Without the option META\_BG, for safety concerns, all block group descriptors copies are kept in the first block group. Given the default 128MiB(2^27 bytes) block group size and 64-byte group descriptors, ext4 can have at most 2^27/64 = 2^21 block groups. This limits the entire -filesystem size to 2^21 ∗ 2^27 = 2^48bytes or 256TiB. +filesystem size to 2^21 * 2^27 = 2^48bytes or 256TiB. The solution to this problem is to use the metablock group feature (META\_BG), which is already in ext3 for all 2.6 releases. With the -- cgit v1.3.1 From 729979ebef22b7527ea377bb2814df97ad7d4078 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:55:13 +0200 Subject: docs: networking: device_drivers: replace some characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion tools used during DocBook/LaTeX/html/Markdown->ReST conversion and some cut-and-pasted text contain some characters that aren't easily reachable on standard keyboards and/or could cause troubles when parsed by the documentation build system. Replace the occurences of the following characters: - U+00a0 (' '): NO-BREAK SPACE as it can cause lines being truncated on PDF output Reviewed-by: Jesse Brandeburg Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/9bd9f5c067c4b068a974730a14fe8d68e1be0c9a.1623826294.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/networking/device_drivers/ethernet/intel/i40e.rst | 6 +++--- Documentation/networking/device_drivers/ethernet/intel/iavf.rst | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/device_drivers/ethernet/intel/i40e.rst b/Documentation/networking/device_drivers/ethernet/intel/i40e.rst index 2d3f6bd969a2..ac35bd472bdc 100644 --- a/Documentation/networking/device_drivers/ethernet/intel/i40e.rst +++ b/Documentation/networking/device_drivers/ethernet/intel/i40e.rst @@ -466,7 +466,7 @@ network. PTP support varies among Intel devices that support this driver. Use "ethtool -T " to get a definitive list of PTP capabilities supported by the device. -IEEE 802.1ad (QinQ) Support +IEEE 802.1ad (QinQ) Support --------------------------- The IEEE 802.1ad standard, informally known as QinQ, allows for multiple VLAN IDs within a single Ethernet frame. VLAN IDs are sometimes referred to as @@ -523,8 +523,8 @@ of a port's bandwidth (should it be available). The sum of all the values for Maximum Bandwidth is not restricted, because no more than 100% of a port's bandwidth can ever be used. -NOTE: X710/XXV710 devices fail to enable Max VFs (64) when Multiple Functions -per Port (MFP) and SR-IOV are enabled. An error from i40e is logged that says +NOTE: X710/XXV710 devices fail to enable Max VFs (64) when Multiple Functions +per Port (MFP) and SR-IOV are enabled. An error from i40e is logged that says "add vsi failed for VF N, aq_err 16". To workaround the issue, enable less than 64 virtual functions (VFs). diff --git a/Documentation/networking/device_drivers/ethernet/intel/iavf.rst b/Documentation/networking/device_drivers/ethernet/intel/iavf.rst index 25330b7b5168..151af0a8da9c 100644 --- a/Documentation/networking/device_drivers/ethernet/intel/iavf.rst +++ b/Documentation/networking/device_drivers/ethernet/intel/iavf.rst @@ -113,7 +113,7 @@ which the AVF is associated. The following are base mode features: - AVF device ID - HW mailbox is used for VF to PF communications (including on Windows) -IEEE 802.1ad (QinQ) Support +IEEE 802.1ad (QinQ) Support --------------------------- The IEEE 802.1ad standard, informally known as QinQ, allows for multiple VLAN IDs within a single Ethernet frame. VLAN IDs are sometimes referred to as -- cgit v1.3.1 From a557f67cd70344bf28442baac4c9b6c94aecb60b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:55:14 +0200 Subject: docs: PCI: Replace non-breaking spaces to avoid PDF issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion tools used during DocBook/LaTeX/html/Markdown->ReST conversion and some cut-and-pasted text contain some characters that aren't easily reachable on standard keyboards and/or could cause troubles when parsed by the documentation build system. Replace the occurences of the following characters: - U+00a0 (' '): NO-BREAK SPACE as it can cause lines being truncated on PDF output Acked-by: Bjorn Helgaas Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/8036126a59adb720dbc9233341ad5a08531cf73f.1623826294.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/PCI/acpi-info.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/PCI/acpi-info.rst b/Documentation/PCI/acpi-info.rst index 060217081c79..34c64a5a66ec 100644 --- a/Documentation/PCI/acpi-info.rst +++ b/Documentation/PCI/acpi-info.rst @@ -22,9 +22,9 @@ or if the device has INTx interrupts connected by platform interrupt controllers and a _PRT is needed to describe those connections. ACPI resource description is done via _CRS objects of devices in the ACPI -namespace [2].   The _CRS is like a generalized PCI BAR: the OS can read +namespace [2]. The _CRS is like a generalized PCI BAR: the OS can read _CRS and figure out what resource is being consumed even if it doesn't have -a driver for the device [3].  That's important because it means an old OS +a driver for the device [3]. That's important because it means an old OS can work correctly even on a system with new devices unknown to the OS. The new devices might not do anything, but the OS can at least make sure no resources conflict with them. @@ -41,15 +41,15 @@ ACPI, that device will have a specific _HID/_CID that tells the OS what driver to bind to it, and the _CRS tells the OS and the driver where the device's registers are. -PCI host bridges are PNP0A03 or PNP0A08 devices.  Their _CRS should -describe all the address space they consume.  This includes all the windows +PCI host bridges are PNP0A03 or PNP0A08 devices. Their _CRS should +describe all the address space they consume. This includes all the windows they forward down to the PCI bus, as well as registers of the host bridge -itself that are not forwarded to PCI.  The host bridge registers include +itself that are not forwarded to PCI. The host bridge registers include things like secondary/subordinate bus registers that determine the bus range below the bridge, window registers that describe the apertures, etc. These are all device-specific, non-architected things, so the only way a PNP0A03/PNP0A08 driver can manage them is via _PRS/_CRS/_SRS, which contain -the device-specific details.  The host bridge registers also include ECAM +the device-specific details. The host bridge registers also include ECAM space, since it is consumed by the host bridge. ACPI defines a Consumer/Producer bit to distinguish the bridge registers @@ -66,7 +66,7 @@ the PNP0A03/PNP0A08 device itself. The workaround was to describe the bridge registers (including ECAM space) in PNP0C02 catch-all devices [6]. With the exception of ECAM, the bridge register space is device-specific anyway, so the generic PNP0A03/PNP0A08 driver (pci_root.c) has no need to -know about it.   +know about it. New architectures should be able to use "Consumer" Extended Address Space descriptors in the PNP0A03 device for bridge registers, including ECAM, @@ -75,9 +75,9 @@ ia64 kernels assume all address space descriptors, including "Consumer" Extended Address Space ones, are windows, so it would not be safe to describe bridge registers this way on those architectures. -PNP0C02 "motherboard" devices are basically a catch-all.  There's no +PNP0C02 "motherboard" devices are basically a catch-all. There's no programming model for them other than "don't use these resources for -anything else."  So a PNP0C02 _CRS should claim any address space that is +anything else." So a PNP0C02 _CRS should claim any address space that is (1) not claimed by _CRS under any other device object in the ACPI namespace and (2) should not be assigned by the OS to something else. -- cgit v1.3.1 From 559a66b868d987dca55894218d11d59e5bafafe0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:16 +0200 Subject: docs: devices.rst: better reference documentation docs There's no need to use either :file: or :doc: tags for documentation, as automarkup.py automatically converts Documentation/*.rst into a cross-reference. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/5d9c9949a104d10b537a2d780bccad69a2dc58f9.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/driver-api/pm/devices.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/driver-api/pm/devices.rst b/Documentation/driver-api/pm/devices.rst index 6b3bfd29fd84..d448cb57df86 100644 --- a/Documentation/driver-api/pm/devices.rst +++ b/Documentation/driver-api/pm/devices.rst @@ -217,7 +217,7 @@ system-wide transition to a sleep state even though its :c:member:`runtime_auto` flag is clear. For more information about the runtime power management framework, refer to -:file:`Documentation/power/runtime_pm.rst`. +Documentation/power/runtime_pm.rst. Calling Drivers to Enter and Leave System Sleep States @@ -655,7 +655,7 @@ been thawed. Generally speaking, the PM notifiers are suitable for performing actions that either require user space to be available, or at least won't interfere with user space. -For details refer to :doc:`notifiers`. +For details refer to Documentation/driver-api/pm/notifiers.rst. Device Low-Power (suspend) States @@ -726,7 +726,7 @@ it into account in any way. Devices may be defined as IRQ-safe which indicates to the PM core that their runtime PM callbacks may be invoked with disabled interrupts (see -:file:`Documentation/power/runtime_pm.rst` for more information). If an +Documentation/power/runtime_pm.rst for more information). If an IRQ-safe device belongs to a PM domain, the runtime PM of the domain will be disallowed, unless the domain itself is defined as IRQ-safe. However, it makes sense to define a PM domain as IRQ-safe only if all the devices in it @@ -805,7 +805,7 @@ The ``DPM_FLAG_MAY_SKIP_RESUME`` Driver Flag -------------------------------------------- During system-wide resume from a sleep state it's easiest to put devices into -the full-power state, as explained in :file:`Documentation/power/runtime_pm.rst`. +the full-power state, as explained in Documentation/power/runtime_pm.rst. [Refer to that document for more information regarding this particular issue as well as for information on the device runtime power management framework in general.] However, it often is desirable to leave devices in suspend after -- cgit v1.3.1 From 9129faf9040d9005e70c604a163faa9f183b00ee Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:17 +0200 Subject: docs: dev-tools: kunit: don't use a table for docs name We'll be replacing :doc:`foo` references to Documentation/foo.rst. Yet, here it happens inside a table. Doing a search-and-replace would break it. Yet, as there's no good reason to use a table there, let's just convert it into a list. Reviewed-by: David Gow Acked-by: Brendan Higgins Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/07d3a8ccafbb6345d6e78fb090290859e84361a1.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/dev-tools/kunit/api/index.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/dev-tools/kunit/api/index.rst b/Documentation/dev-tools/kunit/api/index.rst index 9b9bffe5d41a..b33ad72bcf0b 100644 --- a/Documentation/dev-tools/kunit/api/index.rst +++ b/Documentation/dev-tools/kunit/api/index.rst @@ -10,7 +10,7 @@ API Reference This section documents the KUnit kernel testing API. It is divided into the following sections: -================================= ============================================== -:doc:`test` documents all of the standard testing API - excluding mocking or mocking related features. -================================= ============================================== +Documentation/dev-tools/kunit/api/test.rst + + - documents all of the standard testing API excluding mocking + or mocking related features. -- cgit v1.3.1 From 17420f3138b957e571144f337b866f8c7a7c1682 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:18 +0200 Subject: docs: admin-guide: pm: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/04616d9fc0b4a0d33486fa0018631a2db2eba860.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/admin-guide/pm/intel_idle.rst | 16 ++++++++++------ Documentation/admin-guide/pm/intel_pstate.rst | 9 +++++---- 2 files changed, 15 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/pm/intel_idle.rst b/Documentation/admin-guide/pm/intel_idle.rst index 89309e1b0e48..b799a43da62e 100644 --- a/Documentation/admin-guide/pm/intel_idle.rst +++ b/Documentation/admin-guide/pm/intel_idle.rst @@ -20,8 +20,8 @@ Nehalem and later generations of Intel processors, but the level of support for a particular processor model in it depends on whether or not it recognizes that processor model and may also depend on information coming from the platform firmware. [To understand ``intel_idle`` it is necessary to know how ``CPUIdle`` -works in general, so this is the time to get familiar with :doc:`cpuidle` if you -have not done that yet.] +works in general, so this is the time to get familiar with +Documentation/admin-guide/pm/cpuidle.rst if you have not done that yet.] ``intel_idle`` uses the ``MWAIT`` instruction to inform the processor that the logical CPU executing it is idle and so it may be possible to put some of the @@ -53,7 +53,8 @@ processor) corresponding to them depends on the processor model and it may also depend on the configuration of the platform. In order to create a list of available idle states required by the ``CPUIdle`` -subsystem (see :ref:`idle-states-representation` in :doc:`cpuidle`), +subsystem (see :ref:`idle-states-representation` in +Documentation/admin-guide/pm/cpuidle.rst), ``intel_idle`` can use two sources of information: static tables of idle states for different processor models included in the driver itself and the ACPI tables of the system. The former are always used if the processor model at hand is @@ -98,7 +99,8 @@ states may not be enabled by default if there are no matching entries in the preliminary list of idle states coming from the ACPI tables. In that case user space still can enable them later (on a per-CPU basis) with the help of the ``disable`` idle state attribute in ``sysfs`` (see -:ref:`idle-states-representation` in :doc:`cpuidle`). This basically means that +:ref:`idle-states-representation` in +Documentation/admin-guide/pm/cpuidle.rst). This basically means that the idle states "known" to the driver may not be enabled by default if they have not been exposed by the platform firmware (through the ACPI tables). @@ -186,7 +188,8 @@ be desirable. In practice, it is only really necessary to do that if the idle states in question cannot be enabled during system startup, because in the working state of the system the CPU power management quality of service (PM QoS) feature can be used to prevent ``CPUIdle`` from touching those idle states -even if they have been enumerated (see :ref:`cpu-pm-qos` in :doc:`cpuidle`). +even if they have been enumerated (see :ref:`cpu-pm-qos` in +Documentation/admin-guide/pm/cpuidle.rst). Setting ``max_cstate`` to 0 causes the ``intel_idle`` initialization to fail. The ``no_acpi`` and ``use_acpi`` module parameters (recognized by ``intel_idle`` @@ -202,7 +205,8 @@ Namely, the positions of the bits that are set in the ``states_off`` value are the indices of idle states to be disabled by default (as reflected by the names of the corresponding idle state directories in ``sysfs``, :file:`state0`, :file:`state1` ... :file:`state` ..., where ```` is the index of the given -idle state; see :ref:`idle-states-representation` in :doc:`cpuidle`). +idle state; see :ref:`idle-states-representation` in +Documentation/admin-guide/pm/cpuidle.rst). For example, if ``states_off`` is equal to 3, the driver will disable idle states 0 and 1 by default, and if it is equal to 8, idle state 3 will be diff --git a/Documentation/admin-guide/pm/intel_pstate.rst b/Documentation/admin-guide/pm/intel_pstate.rst index df29b4f1f219..7a7d4b041eac 100644 --- a/Documentation/admin-guide/pm/intel_pstate.rst +++ b/Documentation/admin-guide/pm/intel_pstate.rst @@ -18,8 +18,8 @@ General Information (``CPUFreq``). It is a scaling driver for the Sandy Bridge and later generations of Intel processors. Note, however, that some of those processors may not be supported. [To understand ``intel_pstate`` it is necessary to know -how ``CPUFreq`` works in general, so this is the time to read :doc:`cpufreq` if -you have not done that yet.] +how ``CPUFreq`` works in general, so this is the time to read +Documentation/admin-guide/pm/cpufreq.rst if you have not done that yet.] For the processors supported by ``intel_pstate``, the P-state concept is broader than just an operating frequency or an operating performance point (see the @@ -445,8 +445,9 @@ Interpretation of Policy Attributes ----------------------------------- The interpretation of some ``CPUFreq`` policy attributes described in -:doc:`cpufreq` is special with ``intel_pstate`` as the current scaling driver -and it generally depends on the driver's `operation mode `_. +Documentation/admin-guide/pm/cpufreq.rst is special with ``intel_pstate`` +as the current scaling driver and it generally depends on the driver's +`operation mode `_. First of all, the values of the ``cpuinfo_max_freq``, ``cpuinfo_min_freq`` and ``scaling_cur_freq`` attributes are produced by applying a processor-specific -- cgit v1.3.1 From e499f4c297e9136a579b4eaee75a3c6ba7172eac Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:19 +0200 Subject: docs: admin-guide: hw-vuln: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/4e378517761f3df07165d5ecdac5a0a81577e68f.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- .../admin-guide/hw-vuln/special-register-buffer-data-sampling.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/hw-vuln/special-register-buffer-data-sampling.rst b/Documentation/admin-guide/hw-vuln/special-register-buffer-data-sampling.rst index 3b1ce68d2456..966c9b3296ea 100644 --- a/Documentation/admin-guide/hw-vuln/special-register-buffer-data-sampling.rst +++ b/Documentation/admin-guide/hw-vuln/special-register-buffer-data-sampling.rst @@ -3,7 +3,8 @@ SRBDS - Special Register Buffer Data Sampling ============================================= -SRBDS is a hardware vulnerability that allows MDS :doc:`mds` techniques to +SRBDS is a hardware vulnerability that allows MDS +Documentation/admin-guide/hw-vuln/mds.rst techniques to infer values returned from special register accesses. Special register accesses are accesses to off core registers. According to Intel's evaluation, the special register reads that have a security expectation of privacy are -- cgit v1.3.1 From 2793e19d63275304da0359409a1f28b689df1ed8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:20 +0200 Subject: docs: admin-guide: sysctl: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/12abd2290c7ebc05c89178d2556bea740bd70fac.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/admin-guide/sysctl/abi.rst | 2 +- Documentation/admin-guide/sysctl/kernel.rst | 37 ++++++++++++++++------------- 2 files changed, 21 insertions(+), 18 deletions(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/sysctl/abi.rst b/Documentation/admin-guide/sysctl/abi.rst index 77b1d1b2ad42..4e6db0a2a4c0 100644 --- a/Documentation/admin-guide/sysctl/abi.rst +++ b/Documentation/admin-guide/sysctl/abi.rst @@ -11,7 +11,7 @@ Documentation for /proc/sys/abi/ Copyright (c) 2020, Stephen Kitt -For general info, see :doc:`index`. +For general info, see Documentation/admin-guide/sysctl/index.rst. ------------------------------------------------------------------------------ diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst index c24f57f2c782..10df7fc6495f 100644 --- a/Documentation/admin-guide/sysctl/kernel.rst +++ b/Documentation/admin-guide/sysctl/kernel.rst @@ -9,7 +9,8 @@ Copyright (c) 1998, 1999, Rik van Riel Copyright (c) 2009, Shen Feng -For general info and legal blurb, please look in :doc:`index`. +For general info and legal blurb, please look in +Documentation/admin-guide/sysctl/index.rst. ------------------------------------------------------------------------------ @@ -54,7 +55,7 @@ free space valid for 30 seconds. acpi_video_flags ================ -See :doc:`/power/video`. This allows the video resume mode to be set, +See Documentation/power/video.rst. This allows the video resume mode to be set, in a similar fashion to the ``acpi_sleep`` kernel parameter, by combining the following values: @@ -89,7 +90,7 @@ is 0x15 and the full version number is 0x234, this file will contain the value 340 = 0x154. See the ``type_of_loader`` and ``ext_loader_type`` fields in -:doc:`/x86/boot` for additional information. +Documentation/x86/boot.rst for additional information. bootloader_version (x86 only) @@ -99,7 +100,7 @@ The complete bootloader version number. In the example above, this file will contain the value 564 = 0x234. See the ``type_of_loader`` and ``ext_loader_ver`` fields in -:doc:`/x86/boot` for additional information. +Documentation/x86/boot.rst for additional information. bpf_stats_enabled @@ -269,7 +270,7 @@ see the ``hostname(1)`` man page. firmware_config =============== -See :doc:`/driver-api/firmware/fallback-mechanisms`. +See Documentation/driver-api/firmware/fallback-mechanisms.rst. The entries in this directory allow the firmware loader helper fallback to be controlled: @@ -297,7 +298,7 @@ crashes and outputting them to a serial console. ftrace_enabled, stack_tracer_enabled ==================================== -See :doc:`/trace/ftrace`. +See Documentation/trace/ftrace.rst. hardlockup_all_cpu_backtrace @@ -325,7 +326,7 @@ when a hard lockup is detected. 1 Panic on hard lockup. = =========================== -See :doc:`/admin-guide/lockup-watchdogs` for more information. +See Documentation/admin-guide/lockup-watchdogs.rst for more information. This can also be set using the nmi_watchdog kernel parameter. @@ -586,7 +587,8 @@ in a KVM virtual machine. This default can be overridden by adding:: nmi_watchdog=1 -to the guest kernel command line (see :doc:`/admin-guide/kernel-parameters`). +to the guest kernel command line (see +Documentation/admin-guide/kernel-parameters.rst). numa_balancing @@ -1071,7 +1073,7 @@ that support this feature. real-root-dev ============= -See :doc:`/admin-guide/initrd`. +See Documentation/admin-guide/initrd.rst. reboot-cmd (SPARC only) @@ -1158,7 +1160,7 @@ will take effect. seccomp ======= -See :doc:`/userspace-api/seccomp_filter`. +See Documentation/userspace-api/seccomp_filter.rst. sg-big-buff @@ -1329,7 +1331,7 @@ the boot PROM. sysrq ===== -See :doc:`/admin-guide/sysrq`. +See Documentation/admin-guide/sysrq.rst. tainted @@ -1359,15 +1361,16 @@ ORed together. The letters are seen in "Tainted" line of Oops reports. 131072 `(T)` The kernel was built with the struct randomization plugin ====== ===== ============================================================== -See :doc:`/admin-guide/tainted-kernels` for more information. +See Documentation/admin-guide/tainted-kernels.rst for more information. Note: writes to this sysctl interface will fail with ``EINVAL`` if the kernel is booted with the command line option ``panic_on_taint=,nousertaint`` and any of the ORed together values being written to ``tainted`` match with the bitmask declared on panic_on_taint. - See :doc:`/admin-guide/kernel-parameters` for more details on that particular - kernel command line option and its optional ``nousertaint`` switch. + See Documentation/admin-guide/kernel-parameters.rst for more details on + that particular kernel command line option and its optional + ``nousertaint`` switch. threads-max =========== @@ -1391,7 +1394,7 @@ If a value outside of this range is written to ``threads-max`` an traceoff_on_warning =================== -When set, disables tracing (see :doc:`/trace/ftrace`) when a +When set, disables tracing (see Documentation/trace/ftrace.rst) when a ``WARN()`` is hit. @@ -1411,8 +1414,8 @@ will send them to printk() again. This only works if the kernel was booted with ``tp_printk`` enabled. -See :doc:`/admin-guide/kernel-parameters` and -:doc:`/trace/boottime-trace`. +See Documentation/admin-guide/kernel-parameters.rst and +Documentation/trace/boottime-trace.rst. .. _unaligned-dump-stack: -- cgit v1.3.1 From 4cd4bdf85c79a87a3510b2e729b074d97546ee52 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:21 +0200 Subject: docs: block: biodoc.rst: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/1d26256b305e02da82a6a990910a5b5fb9a0355e.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/block/biodoc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/block/biodoc.rst b/Documentation/block/biodoc.rst index 1d4d71e391af..2098477851a4 100644 --- a/Documentation/block/biodoc.rst +++ b/Documentation/block/biodoc.rst @@ -196,7 +196,7 @@ a virtual address mapping (unlike the earlier scheme of virtual address do not have a corresponding kernel virtual address space mapping) and low-memory pages. -Note: Please refer to :doc:`/core-api/dma-api-howto` for a discussion +Note: Please refer to Documentation/core-api/dma-api-howto.rst for a discussion on PCI high mem DMA aspects and mapping of scatter gather lists, and support for 64 bit PCI. -- cgit v1.3.1 From 6aadf740aab962702ef97cdba29877867cbc0e31 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:22 +0200 Subject: docs: bpf: bpf_lsm.rst: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/fcee73b9bb55a8d0efd07cf04076c66278a42db4.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/bpf/bpf_lsm.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/bpf/bpf_lsm.rst b/Documentation/bpf/bpf_lsm.rst index 1c0a75a51d79..0dc3fb0d9544 100644 --- a/Documentation/bpf/bpf_lsm.rst +++ b/Documentation/bpf/bpf_lsm.rst @@ -20,10 +20,10 @@ LSM hook: Other LSM hooks which can be instrumented can be found in ``include/linux/lsm_hooks.h``. -eBPF programs that use :doc:`/bpf/btf` do not need to include kernel headers -for accessing information from the attached eBPF program's context. They can -simply declare the structures in the eBPF program and only specify the fields -that need to be accessed. +eBPF programs that use Documentation/bpf/btf.rst do not need to include kernel +headers for accessing information from the attached eBPF program's context. +They can simply declare the structures in the eBPF program and only specify +the fields that need to be accessed. .. code-block:: c @@ -88,8 +88,9 @@ example: The ``__attribute__((preserve_access_index))`` is a clang feature that allows the BPF verifier to update the offsets for the access at runtime using the -:doc:`/bpf/btf` information. Since the BPF verifier is aware of the types, it -also validates all the accesses made to the various types in the eBPF program. +Documentation/bpf/btf.rst information. Since the BPF verifier is aware of the +types, it also validates all the accesses made to the various types in the +eBPF program. Loading ------- -- cgit v1.3.1 From a822b2ee266587c3665c471f0de86a3ccbc280b1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:23 +0200 Subject: docs: core-api: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/d967d490b6655735b7df292f88859b5a1b07d0d7.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/core-api/bus-virt-phys-mapping.rst | 2 +- Documentation/core-api/dma-api.rst | 5 +++-- Documentation/core-api/dma-isa-lpc.rst | 2 +- Documentation/core-api/index.rst | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/core-api/bus-virt-phys-mapping.rst b/Documentation/core-api/bus-virt-phys-mapping.rst index c7bc99cd2e21..c72b24a7d52c 100644 --- a/Documentation/core-api/bus-virt-phys-mapping.rst +++ b/Documentation/core-api/bus-virt-phys-mapping.rst @@ -8,7 +8,7 @@ How to access I/O mapped memory from within device drivers The virt_to_bus() and bus_to_virt() functions have been superseded by the functionality provided by the PCI DMA interface - (see :doc:`/core-api/dma-api-howto`). They continue + (see Documentation/core-api/dma-api-howto.rst). They continue to be documented below for historical purposes, but new code must not use them. --davidm 00/12/12 diff --git a/Documentation/core-api/dma-api.rst b/Documentation/core-api/dma-api.rst index 00a1d4fa3f9e..6d6d0edd2d27 100644 --- a/Documentation/core-api/dma-api.rst +++ b/Documentation/core-api/dma-api.rst @@ -5,7 +5,7 @@ Dynamic DMA mapping using the generic device :Author: James E.J. Bottomley This document describes the DMA API. For a more gentle introduction -of the API (and actual examples), see :doc:`/core-api/dma-api-howto`. +of the API (and actual examples), see Documentation/core-api/dma-api-howto.rst. This API is split into two pieces. Part I describes the basic API. Part II describes extensions for supporting non-consistent memory @@ -479,7 +479,8 @@ without the _attrs suffixes, except that they pass an optional dma_attrs. The interpretation of DMA attributes is architecture-specific, and -each attribute should be documented in :doc:`/core-api/dma-attributes`. +each attribute should be documented in +Documentation/core-api/dma-attributes.rst. If dma_attrs are 0, the semantics of each of these functions is identical to those of the corresponding function diff --git a/Documentation/core-api/dma-isa-lpc.rst b/Documentation/core-api/dma-isa-lpc.rst index e59a3d35a93d..17b193603f0a 100644 --- a/Documentation/core-api/dma-isa-lpc.rst +++ b/Documentation/core-api/dma-isa-lpc.rst @@ -17,7 +17,7 @@ To do ISA style DMA you need to include two headers:: #include The first is the generic DMA API used to convert virtual addresses to -bus addresses (see :doc:`/core-api/dma-api` for details). +bus addresses (see Documentation/core-api/dma-api.rst for details). The second contains the routines specific to ISA DMA transfers. Since this is not present on all platforms make sure you construct your diff --git a/Documentation/core-api/index.rst b/Documentation/core-api/index.rst index f1c9d20bd42d..5de2c7a4b1b3 100644 --- a/Documentation/core-api/index.rst +++ b/Documentation/core-api/index.rst @@ -48,7 +48,7 @@ Concurrency primitives ====================== How Linux keeps everything from happening at the same time. See -:doc:`/locking/index` for more related documentation. +Documentation/locking/index.rst for more related documentation. .. toctree:: :maxdepth: 1 @@ -77,7 +77,7 @@ Memory management ================= How to allocate and use memory in the kernel. Note that there is a lot -more memory-management documentation in :doc:`/vm/index`. +more memory-management documentation in Documentation/vm/index.rst. .. toctree:: :maxdepth: 1 -- cgit v1.3.1 From 3a8b57d27a19a341e8d6222630a2c532ef594c42 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:24 +0200 Subject: docs: dev-tools: testing-overview.rst: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/6bbecd4170ee08f36f8060b0719a46c64a21aefc.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/dev-tools/testing-overview.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/dev-tools/testing-overview.rst b/Documentation/dev-tools/testing-overview.rst index b5b46709969c..65feb81edb14 100644 --- a/Documentation/dev-tools/testing-overview.rst +++ b/Documentation/dev-tools/testing-overview.rst @@ -71,15 +71,15 @@ can be used to verify that a test is executing particular functions or lines of code. This is useful for determining how much of the kernel is being tested, and for finding corner-cases which are not covered by the appropriate test. -:doc:`gcov` is GCC's coverage testing tool, which can be used with the kernel -to get global or per-module coverage. Unlike KCOV, it does not record per-task -coverage. Coverage data can be read from debugfs, and interpreted using the -usual gcov tooling. - -:doc:`kcov` is a feature which can be built in to the kernel to allow -capturing coverage on a per-task level. It's therefore useful for fuzzing and -other situations where information about code executed during, for example, a -single syscall is useful. +Documentation/dev-tools/gcov.rst is GCC's coverage testing tool, which can be +used with the kernel to get global or per-module coverage. Unlike KCOV, it +does not record per-task coverage. Coverage data can be read from debugfs, +and interpreted using the usual gcov tooling. + +Documentation/dev-tools/kcov.rst is a feature which can be built in to the +kernel to allow capturing coverage on a per-task level. It's therefore useful +for fuzzing and other situations where information about code executed during, +for example, a single syscall is useful. Dynamic Analysis Tools -- cgit v1.3.1 From 654a5bd0eadbef5f7196215b755dcecd965f11c1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:25 +0200 Subject: docs: dev-tools: kunit: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Reviewed-by: David Gow Acked-by: Brendan Higgins Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/6fde409079959a95b62b9b2692503608d7ff0dbd.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/dev-tools/kunit/faq.rst | 2 +- Documentation/dev-tools/kunit/index.rst | 14 +++++++------- Documentation/dev-tools/kunit/start.rst | 4 ++-- Documentation/dev-tools/kunit/tips.rst | 5 +++-- Documentation/dev-tools/kunit/usage.rst | 8 +++++--- 5 files changed, 18 insertions(+), 15 deletions(-) (limited to 'Documentation') diff --git a/Documentation/dev-tools/kunit/faq.rst b/Documentation/dev-tools/kunit/faq.rst index 8d5029ad210a..5c6555d020f3 100644 --- a/Documentation/dev-tools/kunit/faq.rst +++ b/Documentation/dev-tools/kunit/faq.rst @@ -97,7 +97,7 @@ things to try. modules will automatically execute associated tests when loaded. Test results can be collected from ``/sys/kernel/debug/kunit//results``, and can be parsed with ``kunit.py parse``. For more details, see "KUnit on - non-UML architectures" in :doc:`usage`. + non-UML architectures" in Documentation/dev-tools/kunit/usage.rst. If none of the above tricks help, you are always welcome to email any issues to kunit-dev@googlegroups.com. diff --git a/Documentation/dev-tools/kunit/index.rst b/Documentation/dev-tools/kunit/index.rst index 848478838347..25d92a9a05ea 100644 --- a/Documentation/dev-tools/kunit/index.rst +++ b/Documentation/dev-tools/kunit/index.rst @@ -36,7 +36,7 @@ To make running these tests (and reading the results) easier, KUnit offers results. This provides a quick way of running KUnit tests during development, without requiring a virtual machine or separate hardware. -Get started now: :doc:`start` +Get started now: Documentation/dev-tools/kunit/start.rst Why KUnit? ========== @@ -88,9 +88,9 @@ it takes to read their test log? How do I use it? ================ -* :doc:`start` - for new users of KUnit -* :doc:`tips` - for short examples of best practices -* :doc:`usage` - for a more detailed explanation of KUnit features -* :doc:`api/index` - for the list of KUnit APIs used for testing -* :doc:`kunit-tool` - for more information on the kunit_tool helper script -* :doc:`faq` - for answers to some common questions about KUnit +* Documentation/dev-tools/kunit/start.rst - for new users of KUnit +* Documentation/dev-tools/kunit/tips.rst - for short examples of best practices +* Documentation/dev-tools/kunit/usage.rst - for a more detailed explanation of KUnit features +* Documentation/dev-tools/kunit/api/index.rst - for the list of KUnit APIs used for testing +* Documentation/dev-tools/kunit/kunit-tool.rst - for more information on the kunit_tool helper script +* Documentation/dev-tools/kunit/faq.rst - for answers to some common questions about KUnit diff --git a/Documentation/dev-tools/kunit/start.rst b/Documentation/dev-tools/kunit/start.rst index 0e65cabe08eb..63ef7b625c13 100644 --- a/Documentation/dev-tools/kunit/start.rst +++ b/Documentation/dev-tools/kunit/start.rst @@ -21,7 +21,7 @@ The wrapper can be run with: ./tools/testing/kunit/kunit.py run For more information on this wrapper (also called kunit_tool) check out the -:doc:`kunit-tool` page. +Documentation/dev-tools/kunit/kunit-tool.rst page. Creating a .kunitconfig ----------------------- @@ -234,7 +234,7 @@ Congrats! You just wrote your first KUnit test! Next Steps ========== -* Check out the :doc:`tips` page for tips on +* Check out the Documentation/dev-tools/kunit/tips.rst page for tips on writing idiomatic KUnit tests. * Optional: see the :doc:`usage` page for a more in-depth explanation of KUnit. diff --git a/Documentation/dev-tools/kunit/tips.rst b/Documentation/dev-tools/kunit/tips.rst index 8d8c238f7f79..492d2ded2f5a 100644 --- a/Documentation/dev-tools/kunit/tips.rst +++ b/Documentation/dev-tools/kunit/tips.rst @@ -125,7 +125,8 @@ Here's a slightly in-depth example of how one could implement "mocking": Note: here we're able to get away with using ``test->priv``, but if you wanted -something more flexible you could use a named ``kunit_resource``, see :doc:`api/test`. +something more flexible you could use a named ``kunit_resource``, see +Documentation/dev-tools/kunit/api/test.rst. Failing the current test ------------------------ @@ -185,5 +186,5 @@ Alternatively, one can take full control over the error message by using ``KUNIT Next Steps ========== -* Optional: see the :doc:`usage` page for a more +* Optional: see the Documentation/dev-tools/kunit/usage.rst page for a more in-depth explanation of KUnit. diff --git a/Documentation/dev-tools/kunit/usage.rst b/Documentation/dev-tools/kunit/usage.rst index 650f99590df5..3ee7ab91f712 100644 --- a/Documentation/dev-tools/kunit/usage.rst +++ b/Documentation/dev-tools/kunit/usage.rst @@ -10,7 +10,7 @@ understand it. This guide assumes a working knowledge of the Linux kernel and some basic knowledge of testing. For a high level introduction to KUnit, including setting up KUnit for your -project, see :doc:`start`. +project, see Documentation/dev-tools/kunit/start.rst. Organization of this document ============================= @@ -99,7 +99,8 @@ violated; however, the test will continue running, potentially trying other expectations until the test case ends or is otherwise terminated. This is as opposed to *assertions* which are discussed later. -To learn about more expectations supported by KUnit, see :doc:`api/test`. +To learn about more expectations supported by KUnit, see +Documentation/dev-tools/kunit/api/test.rst. .. note:: A single test case should be pretty short, pretty easy to understand, @@ -216,7 +217,8 @@ test suite in a special linker section so that it can be run by KUnit either after late_init, or when the test module is loaded (depending on whether the test was built in or not). -For more information on these types of things see the :doc:`api/test`. +For more information on these types of things see the +Documentation/dev-tools/kunit/api/test.rst. Common Patterns =============== -- cgit v1.3.1 From 6dce82b28a93492af7a817b2b3166aaf775e4aba Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:26 +0200 Subject: docs: devicetree: bindings: submitting-patches.rst: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/0048c23d47b582dd1a1959628fd2b895209ac826.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/devicetree/bindings/submitting-patches.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/submitting-patches.rst b/Documentation/devicetree/bindings/submitting-patches.rst index 104fa8fb2c17..8087780f1685 100644 --- a/Documentation/devicetree/bindings/submitting-patches.rst +++ b/Documentation/devicetree/bindings/submitting-patches.rst @@ -7,8 +7,8 @@ Submitting Devicetree (DT) binding patches I. For patch submitters ======================= - 0) Normal patch submission rules from Documentation/process/submitting-patches.rst - applies. + 0) Normal patch submission rules from + Documentation/process/submitting-patches.rst applies. 1) The Documentation/ and include/dt-bindings/ portion of the patch should be a separate patch. The preferred subject prefix for binding patches is:: @@ -25,8 +25,8 @@ I. For patch submitters make dt_binding_check - See Documentation/devicetree/bindings/writing-schema.rst for more details about - schema and tools setup. + See Documentation/devicetree/bindings/writing-schema.rst for more details + about schema and tools setup. 3) DT binding files should be dual licensed. The preferred license tag is (GPL-2.0-only OR BSD-2-Clause). @@ -84,7 +84,8 @@ II. For kernel maintainers III. Notes ========== - 0) Please see :doc:`ABI` for details regarding devicetree ABI. + 0) Please see Documentation/devicetree/bindings/ABI.rst for details + regarding devicetree ABI. 1) This document is intended as a general familiarization with the process as decided at the 2013 Kernel Summit. When in doubt, the current word of the -- cgit v1.3.1 From fd88d2e598dcd13807ecabfc6e1170d2c0ab830a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:27 +0200 Subject: docs: doc-guide: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/d6cbe5183406e3378ed4bd0f84f4bcf85a15009c.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/doc-guide/contributing.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/doc-guide/contributing.rst b/Documentation/doc-guide/contributing.rst index 67ee3691f91f..207fd93d7c80 100644 --- a/Documentation/doc-guide/contributing.rst +++ b/Documentation/doc-guide/contributing.rst @@ -237,10 +237,10 @@ We have been trying to improve the situation through the creation of a set of "books" that group documentation for specific readers. These include: - - :doc:`../admin-guide/index` - - :doc:`../core-api/index` - - :doc:`../driver-api/index` - - :doc:`../userspace-api/index` + - Documentation/admin-guide/index.rst + - Documentation/core-api/index.rst + - Documentation/driver-api/index.rst + - Documentation/userspace-api/index.rst As well as this book on documentation itself. -- cgit v1.3.1 From 29602b7c1ecc4a4692e903ac85b09d6b79e0e57d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:28 +0200 Subject: docs: driver-api: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/095b04bff6d49b4097382398bb91102eaa3f0fd3.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/driver-api/ioctl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/driver-api/ioctl.rst b/Documentation/driver-api/ioctl.rst index 5b76e765827d..35795f6a151a 100644 --- a/Documentation/driver-api/ioctl.rst +++ b/Documentation/driver-api/ioctl.rst @@ -34,7 +34,7 @@ _IO/_IOR/_IOW/_IOWR type An 8-bit number, often a character literal, specific to a subsystem - or driver, and listed in :doc:`../userspace-api/ioctl/ioctl-number` + or driver, and listed in Documentation/userspace-api/ioctl/ioctl-number.rst nr An 8-bit number identifying the specific command, unique for a give -- cgit v1.3.1 From 85aa9afd7bf1b239480dd73d5535978b99300fe7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:29 +0200 Subject: docs: driver-api: gpio: using-gpio.rst: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Reviewed-by: Linus Walleij Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/506a41353937c455c2e79b5960b0976edc8aa9e9.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/driver-api/gpio/using-gpio.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/driver-api/gpio/using-gpio.rst b/Documentation/driver-api/gpio/using-gpio.rst index dda069444032..64c8d3f76c3a 100644 --- a/Documentation/driver-api/gpio/using-gpio.rst +++ b/Documentation/driver-api/gpio/using-gpio.rst @@ -9,13 +9,13 @@ with them. For examples of already existing generic drivers that will also be good examples for any other kernel drivers you want to author, refer to -:doc:`drivers-on-gpio` +Documentation/driver-api/gpio/drivers-on-gpio.rst For any kind of mass produced system you want to support, such as servers, laptops, phones, tablets, routers, and any consumer or office or business goods using appropriate kernel drivers is paramount. Submit your code for inclusion in the upstream Linux kernel when you feel it is mature enough and you will get -help to refine it, see :doc:`../../process/submitting-patches`. +help to refine it, see Documentation/process/submitting-patches.rst. In Linux GPIO lines also have a userspace ABI. -- cgit v1.3.1 From bbbaf2264db0f0a29d69e3690df67348d95f1cb3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:30 +0200 Subject: docs: driver-api: surface_aggregator: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Acked-by: Maximilian Luz Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/6097027b4de4c9015485cb73b297b98660c4296d.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- .../driver-api/surface_aggregator/clients/index.rst | 3 ++- Documentation/driver-api/surface_aggregator/internal.rst | 15 ++++++++------- Documentation/driver-api/surface_aggregator/overview.rst | 6 ++++-- 3 files changed, 14 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/driver-api/surface_aggregator/clients/index.rst b/Documentation/driver-api/surface_aggregator/clients/index.rst index 98ea9946b8a2..30160513afa5 100644 --- a/Documentation/driver-api/surface_aggregator/clients/index.rst +++ b/Documentation/driver-api/surface_aggregator/clients/index.rst @@ -5,7 +5,8 @@ Client Driver Documentation =========================== This is the documentation for client drivers themselves. Refer to -:doc:`../client` for documentation on how to write client drivers. +Documentation/driver-api/surface_aggregator/client.rst for documentation +on how to write client drivers. .. toctree:: :maxdepth: 1 diff --git a/Documentation/driver-api/surface_aggregator/internal.rst b/Documentation/driver-api/surface_aggregator/internal.rst index 72704734982a..8c7c80c9f418 100644 --- a/Documentation/driver-api/surface_aggregator/internal.rst +++ b/Documentation/driver-api/surface_aggregator/internal.rst @@ -87,10 +87,11 @@ native SSAM devices, i.e. devices that are not defined in ACPI and not implemented as platform devices, via |ssam_device| and |ssam_device_driver| simplify management of client devices and client drivers. -Refer to :doc:`client` for documentation regarding the client device/driver -API and interface options for other kernel drivers. It is recommended to -familiarize oneself with that chapter and the :doc:`ssh` before continuing -with the architectural overview below. +Refer to Documentation/driver-api/surface_aggregator/client.rst for +documentation regarding the client device/driver API and interface options +for other kernel drivers. It is recommended to familiarize oneself with +that chapter and the Documentation/driver-api/surface_aggregator/ssh.rst +before continuing with the architectural overview below. Packet Transport Layer @@ -190,9 +191,9 @@ with success on the transmitter thread. Transmission of sequenced packets is limited by the number of concurrently pending packets, i.e. a limit on how many packets may be waiting for an ACK -from the EC in parallel. This limit is currently set to one (see :doc:`ssh` -for the reasoning behind this). Control packets (i.e. ACK and NAK) can -always be transmitted. +from the EC in parallel. This limit is currently set to one (see +Documentation/driver-api/surface_aggregator/ssh.rst for the reasoning behind +this). Control packets (i.e. ACK and NAK) can always be transmitted. Receiver Thread --------------- diff --git a/Documentation/driver-api/surface_aggregator/overview.rst b/Documentation/driver-api/surface_aggregator/overview.rst index 1e9d57e50063..26415e1ab7da 100644 --- a/Documentation/driver-api/surface_aggregator/overview.rst +++ b/Documentation/driver-api/surface_aggregator/overview.rst @@ -73,5 +73,7 @@ being a direct response to a previous request. We may also refer to requests without response as commands. In general, events need to be enabled via one of multiple dedicated requests before they are sent by the EC. -See :doc:`ssh` for a more technical protocol documentation and -:doc:`internal` for an overview of the internal driver architecture. +See Documentation/driver-api/surface_aggregator/ssh.rst for a +more technical protocol documentation and +Documentation/driver-api/surface_aggregator/internal.rst for an +overview of the internal driver architecture. -- cgit v1.3.1 From ab8e8da694d4921252c2dd3fecbd2ab64eaf0eb2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:31 +0200 Subject: docs: driver-api: usb: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/2cd2dc3e6bacde587aeb09a3951594cfb0102014.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/driver-api/usb/dma.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/driver-api/usb/dma.rst b/Documentation/driver-api/usb/dma.rst index 2b3dbd3265b4..d32c27e11b90 100644 --- a/Documentation/driver-api/usb/dma.rst +++ b/Documentation/driver-api/usb/dma.rst @@ -10,7 +10,7 @@ API overview The big picture is that USB drivers can continue to ignore most DMA issues, though they still must provide DMA-ready buffers (see -:doc:`/core-api/dma-api-howto`). That's how they've worked through +Documentation/core-api/dma-api-howto.rst). That's how they've worked through the 2.4 (and earlier) kernels, or they can now be DMA-aware. DMA-aware usb drivers: @@ -60,7 +60,7 @@ and effects like cache-trashing can impose subtle penalties. force a consistent memory access ordering by using memory barriers. It's not using a streaming DMA mapping, so it's good for small transfers on systems where the I/O would otherwise thrash an IOMMU mapping. (See - :doc:`/core-api/dma-api-howto` for definitions of "coherent" and + Documentation/core-api/dma-api-howto.rst for definitions of "coherent" and "streaming" DMA mappings.) Asking for 1/Nth of a page (as well as asking for N pages) is reasonably @@ -91,7 +91,7 @@ Working with existing buffers Existing buffers aren't usable for DMA without first being mapped into the DMA address space of the device. However, most buffers passed to your driver can safely be used with such DMA mapping. (See the first section -of :doc:`/core-api/dma-api-howto`, titled "What memory is DMA-able?") +of Documentation/core-api/dma-api-howto.rst, titled "What memory is DMA-able?") - When you're using scatterlists, you can map everything at once. On some systems, this kicks in an IOMMU and turns the scatterlists into single -- cgit v1.3.1 From 4d361d6cc74512308beac8997e4b66d5231e8bfe Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:32 +0200 Subject: docs: firmware-guide: acpi: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Sakari Ailus Link: https://lore.kernel.org/r/7162043c18f1ea96c446b332400e44e8087ba142.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/firmware-guide/acpi/dsd/data-node-references.rst | 3 ++- Documentation/firmware-guide/acpi/dsd/graph.rst | 2 +- Documentation/firmware-guide/acpi/enumeration.rst | 7 ++++--- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/firmware-guide/acpi/dsd/data-node-references.rst b/Documentation/firmware-guide/acpi/dsd/data-node-references.rst index 9b17dc77d18c..b7ad47df49de 100644 --- a/Documentation/firmware-guide/acpi/dsd/data-node-references.rst +++ b/Documentation/firmware-guide/acpi/dsd/data-node-references.rst @@ -79,7 +79,8 @@ the ANOD object which is also the final target node of the reference. }) } -Please also see a graph example in :doc:`graph`. +Please also see a graph example in +Documentation/firmware-guide/acpi/dsd/graph.rst. References ========== diff --git a/Documentation/firmware-guide/acpi/dsd/graph.rst b/Documentation/firmware-guide/acpi/dsd/graph.rst index 7072db801aeb..4341299aa937 100644 --- a/Documentation/firmware-guide/acpi/dsd/graph.rst +++ b/Documentation/firmware-guide/acpi/dsd/graph.rst @@ -174,4 +174,4 @@ References referenced 2016-10-04. [7] _DSD Device Properties Usage Rules. - :doc:`../DSD-properties-rules` + Documentation/firmware-guide/acpi/DSD-properties-rules.rst diff --git a/Documentation/firmware-guide/acpi/enumeration.rst b/Documentation/firmware-guide/acpi/enumeration.rst index 9f0d5c854fa4..18074eb71860 100644 --- a/Documentation/firmware-guide/acpi/enumeration.rst +++ b/Documentation/firmware-guide/acpi/enumeration.rst @@ -339,8 +339,8 @@ a code like this:: There are also devm_* versions of these functions which release the descriptors once the device is released. -See Documentation/firmware-guide/acpi/gpio-properties.rst for more information about the -_DSD binding related to GPIOs. +See Documentation/firmware-guide/acpi/gpio-properties.rst for more information +about the _DSD binding related to GPIOs. MFD devices =========== @@ -460,7 +460,8 @@ the _DSD of the device object itself or the _DSD of its ancestor in the Otherwise, the _DSD itself is regarded as invalid and therefore the "compatible" property returned by it is meaningless. -Refer to :doc:`DSD-properties-rules` for more information. +Refer to Documentation/firmware-guide/acpi/DSD-properties-rules.rst for more +information. PCI hierarchy representation ============================ -- cgit v1.3.1 From 25edd3a1625f76ac2265f3357550a782bd2ac7ff Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:33 +0200 Subject: docs: i2c: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Acked-by: Wolfram Sang Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/569722e3f7d73d746c145ea78d2b4fbe5defee90.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/i2c/instantiating-devices.rst | 2 +- Documentation/i2c/old-module-parameters.rst | 3 ++- Documentation/i2c/smbus-protocol.rst | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/i2c/instantiating-devices.rst b/Documentation/i2c/instantiating-devices.rst index e558e0a77e0c..890c9360ce19 100644 --- a/Documentation/i2c/instantiating-devices.rst +++ b/Documentation/i2c/instantiating-devices.rst @@ -59,7 +59,7 @@ Declare the I2C devices via ACPI ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ACPI can also describe I2C devices. There is special documentation for this -which is currently located at :doc:`../firmware-guide/acpi/enumeration`. +which is currently located at Documentation/firmware-guide/acpi/enumeration.rst. Declare the I2C devices in board files diff --git a/Documentation/i2c/old-module-parameters.rst b/Documentation/i2c/old-module-parameters.rst index 38e55829dee8..b08b6daabce9 100644 --- a/Documentation/i2c/old-module-parameters.rst +++ b/Documentation/i2c/old-module-parameters.rst @@ -17,7 +17,8 @@ address), ``force`` (to forcibly attach the driver to a given device) and With the conversion of the I2C subsystem to the standard device driver binding model, it became clear that these per-module parameters were no longer needed, and that a centralized implementation was possible. The new, -sysfs-based interface is described in :doc:`instantiating-devices`, section +sysfs-based interface is described in +Documentation/i2c/instantiating-devices.rst, section "Method 4: Instantiate from user-space". Below is a mapping from the old module parameters to the new interface. diff --git a/Documentation/i2c/smbus-protocol.rst b/Documentation/i2c/smbus-protocol.rst index 64689d19dd51..9e07e6bbe6a3 100644 --- a/Documentation/i2c/smbus-protocol.rst +++ b/Documentation/i2c/smbus-protocol.rst @@ -27,8 +27,8 @@ a different protocol operation entirely. Each transaction type corresponds to a functionality flag. Before calling a transaction function, a device driver should always check (just once) for the corresponding functionality flag to ensure that the underlying I2C -adapter supports the transaction in question. See :doc:`functionality` for -the details. +adapter supports the transaction in question. See +Documentation/i2c/functionality.rst for the details. Key to symbols -- cgit v1.3.1 From 7f3f7bfbbe02cdfeacf9375c73fd33787554bf8f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:34 +0200 Subject: docs: kernel-hacking: hacking.rst: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/9537b74d897fab13552535d79337060a3b241b8c.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/kernel-hacking/hacking.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-hacking/hacking.rst b/Documentation/kernel-hacking/hacking.rst index 451523424942..df65c19aa7df 100644 --- a/Documentation/kernel-hacking/hacking.rst +++ b/Documentation/kernel-hacking/hacking.rst @@ -601,7 +601,7 @@ Defined in ``include/linux/export.h`` This is the variant of `EXPORT_SYMBOL()` that allows specifying a symbol namespace. Symbol Namespaces are documented in -:doc:`../core-api/symbol-namespaces` +Documentation/core-api/symbol-namespaces.rst :c:func:`EXPORT_SYMBOL_NS_GPL()` -------------------------------- @@ -610,7 +610,7 @@ Defined in ``include/linux/export.h`` This is the variant of `EXPORT_SYMBOL_GPL()` that allows specifying a symbol namespace. Symbol Namespaces are documented in -:doc:`../core-api/symbol-namespaces` +Documentation/core-api/symbol-namespaces.rst Routines and Conventions ======================== -- cgit v1.3.1 From 8d4a0adc9cab0d2a5643bacfd42cd64d1f09ae09 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:35 +0200 Subject: docs: networking: devlink: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/4553858bc9a5442eba6d71caff8047e84ece4d9b.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/networking/devlink/devlink-region.rst | 2 +- Documentation/networking/devlink/devlink-trap.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/devlink/devlink-region.rst b/Documentation/networking/devlink/devlink-region.rst index 3654c3e9658f..58fe95e9a49d 100644 --- a/Documentation/networking/devlink/devlink-region.rst +++ b/Documentation/networking/devlink/devlink-region.rst @@ -22,7 +22,7 @@ The major benefit to creating a region is to provide access to internal address regions that are otherwise inaccessible to the user. Regions may also be used to provide an additional way to debug complex error -states, but see also :doc:`devlink-health` +states, but see also Documentation/networking/devlink/devlink-health.rst Regions may optionally support capturing a snapshot on demand via the ``DEVLINK_CMD_REGION_NEW`` netlink message. A driver wishing to allow diff --git a/Documentation/networking/devlink/devlink-trap.rst b/Documentation/networking/devlink/devlink-trap.rst index 935b6397e8cf..efa5f7f42c88 100644 --- a/Documentation/networking/devlink/devlink-trap.rst +++ b/Documentation/networking/devlink/devlink-trap.rst @@ -495,8 +495,8 @@ help debug packet drops caused by these exceptions. The following list includes links to the description of driver-specific traps registered by various device drivers: - * :doc:`netdevsim` - * :doc:`mlxsw` + * Documentation/networking/devlink/netdevsim.rst + * Documentation/networking/devlink/mlxsw.rst .. _Generic-Packet-Trap-Groups: -- cgit v1.3.1 From e5424f0aec76abd6567e844fbd9a0eb7d138374b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:36 +0200 Subject: docs: PCI: endpoint: pci-endpoint-cfs.rst: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Acked-by: Bjorn Helgaas Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/4b18febe4a4f030dd9d43e5e6a2a0aa28bd5b734.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/PCI/endpoint/pci-endpoint-cfs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/PCI/endpoint/pci-endpoint-cfs.rst b/Documentation/PCI/endpoint/pci-endpoint-cfs.rst index 696f8eeb4738..db609b97ad58 100644 --- a/Documentation/PCI/endpoint/pci-endpoint-cfs.rst +++ b/Documentation/PCI/endpoint/pci-endpoint-cfs.rst @@ -125,4 +125,4 @@ all the EPF devices are created and linked with the EPC device. | interrupt_pin | function -[1] :doc:`pci-endpoint` +[1] Documentation/PCI/endpoint/pci-endpoint.rst -- cgit v1.3.1 From bffbae6d19edc72a408cdbe915d482be0c91e047 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:37 +0200 Subject: docs: PCI: pci.rst: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Acked-by: Bjorn Helgaas Link: https://lore.kernel.org/r/8697cf945390f6b45fefb4c5fe22ed1c8070e32e.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/PCI/pci.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/PCI/pci.rst b/Documentation/PCI/pci.rst index 814b40f8360b..fa651e25d98c 100644 --- a/Documentation/PCI/pci.rst +++ b/Documentation/PCI/pci.rst @@ -265,7 +265,7 @@ Set the DMA mask size --------------------- .. note:: If anything below doesn't make sense, please refer to - :doc:`/core-api/dma-api`. This section is just a reminder that + Documentation/core-api/dma-api.rst. This section is just a reminder that drivers need to indicate DMA capabilities of the device and is not an authoritative source for DMA interfaces. @@ -291,7 +291,7 @@ Many 64-bit "PCI" devices (before PCI-X) and some PCI-X devices are Setup shared control data ------------------------- Once the DMA masks are set, the driver can allocate "consistent" (a.k.a. shared) -memory. See :doc:`/core-api/dma-api` for a full description of +memory. See Documentation/core-api/dma-api.rst for a full description of the DMA APIs. This section is just a reminder that it needs to be done before enabling DMA on the device. @@ -421,7 +421,7 @@ owners if there is one. Then clean up "consistent" buffers which contain the control data. -See :doc:`/core-api/dma-api` for details on unmapping interfaces. +See Documentation/core-api/dma-api.rst for details on unmapping interfaces. Unregister from other subsystems -- cgit v1.3.1 From 9912d0bb9deeaa4b0680a94fbdaa3ae31e891c1b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:38 +0200 Subject: docs: process: submitting-patches.rst: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/d172ab629c3e32c8d27ed4b9d2a209933e2a7178.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/process/submitting-patches.rst | 32 +++++++++++++--------------- 1 file changed, 15 insertions(+), 17 deletions(-) (limited to 'Documentation') diff --git a/Documentation/process/submitting-patches.rst b/Documentation/process/submitting-patches.rst index c66a19201deb..0852bcf73630 100644 --- a/Documentation/process/submitting-patches.rst +++ b/Documentation/process/submitting-patches.rst @@ -10,10 +10,11 @@ can greatly increase the chances of your change being accepted. This document contains a large number of suggestions in a relatively terse format. For detailed information on how the kernel development process -works, see :doc:`development-process`. Also, read :doc:`submit-checklist` +works, see Documentation/process/development-process.rst. Also, read +Documentation/process/submit-checklist.rst for a list of items to check before submitting code. If you are submitting -a driver, also read :doc:`submitting-drivers`; for device tree binding patches, -read :doc:`submitting-patches`. +a driver, also read Documentation/process/submitting-drivers.rst; for device +tree binding patches, read Documentation/process/submitting-patches.rst. This documentation assumes that you're using ``git`` to prepare your patches. If you're unfamiliar with ``git``, you would be well-advised to learn how to @@ -178,8 +179,7 @@ Style-check your changes ------------------------ Check your patch for basic style violations, details of which can be -found in -:ref:`Documentation/process/coding-style.rst `. +found in Documentation/process/coding-style.rst. Failure to do so simply wastes the reviewers time and will get your patch rejected, probably without even being read. @@ -238,7 +238,7 @@ If you have a patch that fixes an exploitable security bug, send that patch to security@kernel.org. For severe bugs, a short embargo may be considered to allow distributors to get the patch out to users; in such cases, obviously, the patch should not be sent to any public lists. See also -:doc:`/admin-guide/security-bugs`. +Documentation/admin-guide/security-bugs.rst. Patches that fix a severe bug in a released kernel should be directed toward the stable maintainers by putting a line like this:: @@ -246,9 +246,8 @@ toward the stable maintainers by putting a line like this:: Cc: stable@vger.kernel.org into the sign-off area of your patch (note, NOT an email recipient). You -should also read -:ref:`Documentation/process/stable-kernel-rules.rst ` -in addition to this file. +should also read Documentation/process/stable-kernel-rules.rst +in addition to this document. If changes affect userland-kernel interfaces, please send the MAN-PAGES maintainer (as listed in the MAINTAINERS file) a man-pages patch, or at @@ -305,8 +304,8 @@ decreasing the likelihood of your MIME-attached change being accepted. Exception: If your mailer is mangling patches then someone may ask you to re-send them using MIME. -See :doc:`/process/email-clients` for hints about configuring your e-mail -client so that it sends your patches untouched. +See Documentation/process/email-clients.rst for hints about configuring +your e-mail client so that it sends your patches untouched. Respond to review comments -------------------------- @@ -324,7 +323,7 @@ for their time. Code review is a tiring and time-consuming process, and reviewers sometimes get grumpy. Even in that case, though, respond politely and address the problems they have pointed out. -See :doc:`email-clients` for recommendations on email +See Documentation/process/email-clients.rst for recommendations on email clients and mailing list etiquette. @@ -562,10 +561,10 @@ method for indicating a bug fixed by the patch. See :ref:`describe_changes` for more details. Note: Attaching a Fixes: tag does not subvert the stable kernel rules -process nor the requirement to Cc: stable@vger.kernel.org on all stable +process nor the requirement to Cc: stable@vger.kernel.org on all stable patch candidates. For more information, please read -:ref:`Documentation/process/stable-kernel-rules.rst ` - +Documentation/process/stable-kernel-rules.rst. + .. _the_canonical_patch_format: The canonical patch format @@ -824,8 +823,7 @@ Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer". NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people! -Kernel Documentation/process/coding-style.rst: - :ref:`Documentation/process/coding-style.rst ` +Kernel Documentation/process/coding-style.rst Linus Torvalds's mail on the canonical patch format: -- cgit v1.3.1 From d3122273bd852f532c0d4632b7ade1b11953873d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:39 +0200 Subject: docs: security: landlock.rst: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/9174021ef2c87f395a4cc0895a4b2f7fd97db626.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/security/landlock.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/security/landlock.rst b/Documentation/security/landlock.rst index 2e84925ae971..3df68cb1d10f 100644 --- a/Documentation/security/landlock.rst +++ b/Documentation/security/landlock.rst @@ -25,7 +25,8 @@ Any user can enforce Landlock rulesets on their processes. They are merged and evaluated according to the inherited ones in a way that ensures that only more constraints can be added. -User space documentation can be found here: :doc:`/userspace-api/landlock`. +User space documentation can be found here: +Documentation/userspace-api/landlock.rst. Guiding principles for safe access controls =========================================== -- cgit v1.3.1 From e480336c25d3dbdfdc5d18225b6f26804369ddba Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:40 +0200 Subject: docs: trace: coresight: coresight.rst: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Mathieu Poirier Link: https://lore.kernel.org/r/c79be625f7c90468e13d5380f0e4e1c1ccfa2fc8.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/trace/coresight/coresight.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/trace/coresight/coresight.rst b/Documentation/trace/coresight/coresight.rst index 169749efd8d1..1ec8dc35b1d8 100644 --- a/Documentation/trace/coresight/coresight.rst +++ b/Documentation/trace/coresight/coresight.rst @@ -315,7 +315,8 @@ intermediate links as required. Note: ``cti_sys0`` appears in two of the connections lists above. CTIs can connect to multiple devices and are arranged in a star topology -via the CTM. See (:doc:`coresight-ect`) [#fourth]_ for further details. +via the CTM. See (Documentation/trace/coresight/coresight-ect.rst) +[#fourth]_ for further details. Looking at this device we see 4 connections:: linaro-developer:~# ls -l /sys/bus/coresight/devices/cti_sys0/connections @@ -606,7 +607,8 @@ interface provided for that purpose by the generic STM API:: crw------- 1 root root 10, 61 Jan 3 18:11 /dev/stm0 root@genericarmv8:~# -Details on how to use the generic STM API can be found here:- :doc:`../stm` [#second]_. +Details on how to use the generic STM API can be found here: +- Documentation/trace/stm.rst [#second]_. The CTI & CTM Modules --------------------- @@ -616,7 +618,7 @@ individual CTIs and components, and can propagate these between all CTIs via channels on the CTM (Cross Trigger Matrix). A separate documentation file is provided to explain the use of these devices. -(:doc:`coresight-ect`) [#fourth]_. +(Documentation/trace/coresight/coresight-ect.rst) [#fourth]_. .. [#first] Documentation/ABI/testing/sysfs-bus-coresight-devices-stm -- cgit v1.3.1 From 81a2d57873d94b030de789ebe9b8009241abc775 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:41 +0200 Subject: docs: trace: ftrace.rst: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/cf9b03ff4b7917d9846503f198372bc6b821445b.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/trace/ftrace.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst index b88c6b79db3e..cfc81e98e0b8 100644 --- a/Documentation/trace/ftrace.rst +++ b/Documentation/trace/ftrace.rst @@ -40,7 +40,7 @@ See events.rst for more information. Implementation Details ---------------------- -See :doc:`ftrace-design` for details for arch porters and such. +See Documentation/trace/ftrace-design.rst for details for arch porters and such. The File System -- cgit v1.3.1 From 69fe5540153ff7d7ed4ee36ad4037603eb9c45c9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:42 +0200 Subject: docs: userspace-api: landlock.rst: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/24888a9c5da3c505b2bc274fcd83be348dbaf972.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/userspace-api/landlock.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/landlock.rst b/Documentation/userspace-api/landlock.rst index 62c9361a3c7f..f35552ff19ba 100644 --- a/Documentation/userspace-api/landlock.rst +++ b/Documentation/userspace-api/landlock.rst @@ -145,7 +145,8 @@ Bind mounts and OverlayFS Landlock enables to restrict access to file hierarchies, which means that these access rights can be propagated with bind mounts (cf. -:doc:`/filesystems/sharedsubtree`) but not with :doc:`/filesystems/overlayfs`. +Documentation/filesystems/sharedsubtree.rst) but not with +Documentation/filesystems/overlayfs.rst. A bind mount mirrors a source file hierarchy to a destination. The destination hierarchy is then composed of the exact same files, on which Landlock rules can @@ -170,8 +171,8 @@ Inheritance Every new thread resulting from a :manpage:`clone(2)` inherits Landlock domain restrictions from its parent. This is similar to the seccomp inheritance (cf. -:doc:`/userspace-api/seccomp_filter`) or any other LSM dealing with task's -:manpage:`credentials(7)`. For instance, one process's thread may apply +Documentation/userspace-api/seccomp_filter.rst) or any other LSM dealing with +task's :manpage:`credentials(7)`. For instance, one process's thread may apply Landlock rules to itself, but they will not be automatically applied to other sibling threads (unlike POSIX thread credential changes, cf. :manpage:`nptl(7)`). @@ -278,7 +279,7 @@ Memory usage ------------ Kernel memory allocated to create rulesets is accounted and can be restricted -by the :doc:`/admin-guide/cgroup-v1/memory`. +by the Documentation/admin-guide/cgroup-v1/memory.rst. Questions and answers ===================== @@ -303,7 +304,7 @@ issues, especially when untrusted processes can manipulate them (cf. Additional documentation ======================== -* :doc:`/security/landlock` +* Documentation/security/landlock.rst * https://landlock.io .. Links -- cgit v1.3.1 From c6c032bf2c5483c668461d5f33d83034c791fd91 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:43 +0200 Subject: docs: virt: kvm: s390-pv-boot.rst: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/8c0fc6578ff6384580fd0d622f363bbbd4fe91da.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/virt/kvm/s390-pv-boot.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/s390-pv-boot.rst b/Documentation/virt/kvm/s390-pv-boot.rst index ad1f7866c001..73a6083cb5e7 100644 --- a/Documentation/virt/kvm/s390-pv-boot.rst +++ b/Documentation/virt/kvm/s390-pv-boot.rst @@ -10,7 +10,7 @@ The memory of Protected Virtual Machines (PVMs) is not accessible to I/O or the hypervisor. In those cases where the hypervisor needs to access the memory of a PVM, that memory must be made accessible. Memory made accessible to the hypervisor will be encrypted. See -:doc:`s390-pv` for details." +Documentation/virt/kvm/s390-pv.rst for details." On IPL (boot) a small plaintext bootloader is started, which provides information about the encrypted components and necessary metadata to -- cgit v1.3.1 From 0ffd643875d3f7dac3cd9fbc637a3645c48ba21f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Jun 2021 08:27:44 +0200 Subject: docs: x86: avoid using ReST :doc:`foo` markup The :doc:`foo` tag is auto-generated via automarkup.py. So, use the filename at the sources, instead of :doc:`foo`. Acked-by: Peter Zijlstra (Intel) Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/17c68b5f1d72488431c77c1de9f13683fe9f536c.1623824363.git.mchehab+huawei@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/x86/boot.rst | 4 ++-- Documentation/x86/mtrr.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/x86/boot.rst b/Documentation/x86/boot.rst index fc844913dece..894a19897005 100644 --- a/Documentation/x86/boot.rst +++ b/Documentation/x86/boot.rst @@ -1343,7 +1343,7 @@ follow:: In addition to read/modify/write the setup header of the struct boot_params as that of 16-bit boot protocol, the boot loader should also fill the additional fields of the struct boot_params as -described in chapter :doc:`zero-page`. +described in chapter Documentation/x86/zero-page.rst. After setting up the struct boot_params, the boot loader can load the 32/64-bit kernel in the same way as that of 16-bit boot protocol. @@ -1379,7 +1379,7 @@ can be calculated as follows:: In addition to read/modify/write the setup header of the struct boot_params as that of 16-bit boot protocol, the boot loader should also fill the additional fields of the struct boot_params as described -in chapter :doc:`zero-page`. +in chapter Documentation/x86/zero-page.rst. After setting up the struct boot_params, the boot loader can load 64-bit kernel in the same way as that of 16-bit boot protocol, but diff --git a/Documentation/x86/mtrr.rst b/Documentation/x86/mtrr.rst index c5b695d75349..9f0b1851771a 100644 --- a/Documentation/x86/mtrr.rst +++ b/Documentation/x86/mtrr.rst @@ -28,7 +28,7 @@ are aligned with platform MTRR setup. If MTRRs are only set up by the platform firmware code though and the OS does not make any specific MTRR mapping requests mtrr_type_lookup() should always return MTRR_TYPE_INVALID. -For details refer to :doc:`pat`. +For details refer to Documentation/x86/pat.rst. .. tip:: On Intel P6 family processors (Pentium Pro, Pentium II and later) -- cgit v1.3.1 From 102caec1075fe993fb1ef95368ec1c3b2e5d0d77 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Mon, 14 Jun 2021 16:07:24 -0600 Subject: docs: Take a little noise out of the build process Sphinx 3.0 works at this point (albeit slowly) so stop scaring people with a loud warning. We also don't need to babble about CJK support in the LaTeX build. Signed-off-by: Jonathan Corbet --- Documentation/conf.py | 9 --------- 1 file changed, 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/conf.py b/Documentation/conf.py index a05225056e08..7d92ec3e5b6e 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -41,15 +41,7 @@ extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'maintainers_include', 'sphinx.ext.autosectionlabel', 'kernel_abi', 'kernel_feat'] -# -# cdomain is badly broken in Sphinx 3+. Leaving it out generates *most* -# of the docs correctly, but not all. Scream bloody murder but allow -# the process to proceed; hopefully somebody will fix this properly soon. -# if major >= 3: - sys.stderr.write('''WARNING: The kernel documentation build process - support for Sphinx v3.0 and above is brand new. Be prepared for - possible issues in the generated output.\n''') if (major > 3) or (minor > 0 or patch >= 2): # Sphinx c function parser is more pedantic with regards to type # checking. Due to that, having macros at c:function cause problems. @@ -368,7 +360,6 @@ latex_elements = { cjk_cmd = check_output(['fc-list', '--format="%{family[0]}\n"']).decode('utf-8', 'ignore') if cjk_cmd.find("Noto Sans CJK SC") >= 0: - print ("enabling CJK for LaTeX builder") latex_elements['preamble'] += ''' % This is needed for translations \\usepackage{xeCJK} -- cgit v1.3.1 From 222a28edce38b62074a950fb243df621c602b4d3 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 17 Jun 2021 15:58:08 -0700 Subject: docs: Makefile: Use CONFIG_SHELL not SHELL Fix think-o about which variable to find the Kbuild-configured shell. This has accidentally worked due to most shells setting $SHELL by default. Fixes: 51e46c7a4007 ("docs, parallelism: Rearrange how jobserver reservations are made") Cc: stable@vger.kernel.org Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20210617225808.3907377-1-keescook@chromium.org Signed-off-by: Jonathan Corbet --- Documentation/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/Makefile b/Documentation/Makefile index 9c42dde97671..c3feb657b654 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -76,7 +76,7 @@ quiet_cmd_sphinx = SPHINX $@ --> file://$(abspath $(BUILDDIR)/$3/$4) PYTHONDONTWRITEBYTECODE=1 \ BUILDDIR=$(abspath $(BUILDDIR)) SPHINX_CONF=$(abspath $(srctree)/$(src)/$5/$(SPHINX_CONF)) \ $(PYTHON3) $(srctree)/scripts/jobserver-exec \ - $(SHELL) $(srctree)/Documentation/sphinx/parallel-wrapper.sh \ + $(CONFIG_SHELL) $(srctree)/Documentation/sphinx/parallel-wrapper.sh \ $(SPHINXBUILD) \ -b $2 \ -c $(abspath $(srctree)/$(src)) \ -- cgit v1.3.1 From 993b892610d159dc16f6556dd0bf111ddc3ce0b9 Mon Sep 17 00:00:00 2001 From: Fox Chen Date: Thu, 27 May 2021 17:16:06 +0800 Subject: docs: path-lookup: update follow_managed() part No follow_managed() anymore, handle_mounts(), traverse_mounts(), will do the job. see commit 9deed3ebca24 ("new helper: traverse_mounts()") Signed-off-by: Fox Chen Reviewed-by: NeilBrown Link: https://lore.kernel.org/r/20210527091618.287093-2-foxhlchen@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/filesystems/path-lookup.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/path-lookup.rst b/Documentation/filesystems/path-lookup.rst index c482e1619e77..751082d469e8 100644 --- a/Documentation/filesystems/path-lookup.rst +++ b/Documentation/filesystems/path-lookup.rst @@ -448,10 +448,11 @@ described. If it finds a ``LAST_NORM`` component it first calls filesystem to revalidate the result if it is that sort of filesystem. If that doesn't get a good result, it calls "``lookup_slow()``" which takes ``i_rwsem``, rechecks the cache, and then asks the filesystem -to find a definitive answer. Each of these will call -``follow_managed()`` (as described below) to handle any mount points. +to find a definitive answer. -In the absence of symbolic links, ``walk_component()`` creates a new +As the last step of ``walk_component()``, ``step_into()`` will be called either +directly from walk_component() or from handle_dots(). It calls +``handle_mounts()``, to check and handle mount points, in which a new ``struct path`` containing a counted reference to the new dentry and a reference to the new ``vfsmount`` which is only counted if it is different from the previous ``vfsmount``. It then calls @@ -535,8 +536,7 @@ covered in greater detail in autofs.txt in the Linux documentation tree, but a few notes specifically related to path lookup are in order here. -The Linux VFS has a concept of "managed" dentries which is reflected -in function names such as "``follow_managed()``". There are three +The Linux VFS has a concept of "managed" dentries. There are three potentially interesting things about these dentries corresponding to three different flags that might be set in ``dentry->d_flags``: -- cgit v1.3.1 From 084c86837a3583c7cf56d74f91fb8e6191f99a8a Mon Sep 17 00:00:00 2001 From: Fox Chen Date: Thu, 27 May 2021 17:16:07 +0800 Subject: docs: path-lookup: update path_to_nameidata() part No path_to_namei() anymore, step_into() will be called. Related commit: commit c99687a03a78 ("fold path_to_nameidata() into its only remaining caller") Signed-off-by: Fox Chen Reviewed-by: NeilBrown Link: https://lore.kernel.org/r/20210527091618.287093-3-foxhlchen@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/filesystems/path-lookup.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/path-lookup.rst b/Documentation/filesystems/path-lookup.rst index 751082d469e8..6ea0880fb982 100644 --- a/Documentation/filesystems/path-lookup.rst +++ b/Documentation/filesystems/path-lookup.rst @@ -453,11 +453,12 @@ to find a definitive answer. As the last step of ``walk_component()``, ``step_into()`` will be called either directly from walk_component() or from handle_dots(). It calls ``handle_mounts()``, to check and handle mount points, in which a new -``struct path`` containing a counted reference to the new dentry and a -reference to the new ``vfsmount`` which is only counted if it is -different from the previous ``vfsmount``. It then calls -``path_to_nameidata()`` to install the new ``struct path`` in the -``struct nameidata`` and drop the unneeded references. +``struct path`` is created containing a counted reference to the new dentry and +a reference to the new ``vfsmount`` which is only counted if it is +different from the previous ``vfsmount``. Then if there is +a symbolic link, ``step_into()`` calls ``pick_link()`` to deal with it, +otherwise it installs the new ``struct path`` in the ``struct nameidata``, and +drops the unneeded references. This "hand-over-hand" sequencing of getting a reference to the new dentry before dropping the reference to the previous dentry may -- cgit v1.3.1 From 8593d2cc8c2f09164d674b2318661ede00dd4d0e Mon Sep 17 00:00:00 2001 From: Fox Chen Date: Thu, 27 May 2021 17:16:08 +0800 Subject: docs: path-lookup: update path_mountpoint() part path_mountpoint() doesn't exist anymore. Have been folded into path_lookup_at when flag is set with LOOKUP_MOUNTPOINT. Check commit: commit 161aff1d93abf0e ("LOOKUP_MOUNTPOINT: fold path_mountpointat() into path_lookupat()") Signed-off-by: Fox Chen Reviewed-by: NeilBrown Link: https://lore.kernel.org/r/20210527091618.287093-4-foxhlchen@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/filesystems/path-lookup.rst | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/path-lookup.rst b/Documentation/filesystems/path-lookup.rst index 6ea0880fb982..652d3284f178 100644 --- a/Documentation/filesystems/path-lookup.rst +++ b/Documentation/filesystems/path-lookup.rst @@ -472,7 +472,7 @@ Handling the final component ``nd->last_type`` to refer to the final component of the path. It does not call ``walk_component()`` that last time. Handling that final component remains for the caller to sort out. Those callers are -``path_lookupat()``, ``path_parentat()``, ``path_mountpoint()`` and +``path_lookupat()``, ``path_parentat()`` and ``path_openat()`` each of which handles the differing requirements of different system calls. @@ -488,12 +488,10 @@ perform their operation. object is wanted such as by ``stat()`` or ``chmod()``. It essentially just calls ``walk_component()`` on the final component through a call to ``lookup_last()``. ``path_lookupat()`` returns just the final dentry. - -``path_mountpoint()`` handles the special case of unmounting which must -not try to revalidate the mounted filesystem. It effectively -contains, through a call to ``mountpoint_last()``, an alternate -implementation of ``lookup_slow()`` which skips that step. This is -important when unmounting a filesystem that is inaccessible, such as +It is worth noting that when flag ``LOOKUP_MOUNTPOINT`` is set, +``path_lookupat()`` will unset LOOKUP_JUMPED in nameidata so that in the +subsequent path traversal ``d_weak_revalidate()`` won't be called. +This is important when unmounting a filesystem that is inaccessible, such as one provided by a dead NFS server. Finally ``path_openat()`` is used for the ``open()`` system call; it -- cgit v1.3.1 From 71e0a67dc6c26018e27fe0c670e2db023aa72d22 Mon Sep 17 00:00:00 2001 From: Fox Chen Date: Thu, 27 May 2021 17:16:09 +0800 Subject: docs: path-lookup: update do_last() part traling_symlink() was merged into lookup_last, do_last(). do_last() has later been split into open_last_lookups() and do_open(). see related commit: commit c5971b8c6354 ("take post-lookup part of do_last() out of loop") Signed-off-by: Fox Chen Reviewed-by: NeilBrown Link: https://lore.kernel.org/r/20210527091618.287093-5-foxhlchen@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/filesystems/path-lookup.rst | 47 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 25 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/path-lookup.rst b/Documentation/filesystems/path-lookup.rst index 652d3284f178..2b0b33168067 100644 --- a/Documentation/filesystems/path-lookup.rst +++ b/Documentation/filesystems/path-lookup.rst @@ -495,11 +495,11 @@ This is important when unmounting a filesystem that is inaccessible, such as one provided by a dead NFS server. Finally ``path_openat()`` is used for the ``open()`` system call; it -contains, in support functions starting with "``do_last()``", all the +contains, in support functions starting with "``open_last_lookups()``", all the complexity needed to handle the different subtleties of O_CREAT (with or without O_EXCL), final "``/``" characters, and trailing symbolic links. We will revisit this in the final part of this series, which -focuses on those symbolic links. "``do_last()``" will sometimes, but +focuses on those symbolic links. "``open_last_lookups()``" will sometimes, but not always, take ``i_rwsem``, depending on what it finds. Each of these, or the functions which call them, need to be alert to @@ -1196,29 +1196,26 @@ potentially need to call ``link_path_walk()`` again and again on successive symlinks until one is found that doesn't point to another symlink. -This case is handled by the relevant caller of ``link_path_walk()``, such as -``path_lookupat()`` using a loop that calls ``link_path_walk()``, and then -handles the final component. If the final component is a symlink -that needs to be followed, then ``trailing_symlink()`` is called to set -things up properly and the loop repeats, calling ``link_path_walk()`` -again. This could loop as many as 40 times if the last component of -each symlink is another symlink. - -The various functions that examine the final component and possibly -report that it is a symlink are ``lookup_last()``, ``mountpoint_last()`` -and ``do_last()``, each of which use the same convention as -``walk_component()`` of returning ``1`` if a symlink was found that needs -to be followed. - -Of these, ``do_last()`` is the most interesting as it is used for -opening a file. Part of ``do_last()`` runs with ``i_rwsem`` held and this -part is in a separate function: ``lookup_open()``. - -Explaining ``do_last()`` completely is beyond the scope of this article, -but a few highlights should help those interested in exploring the -code. - -1. Rather than just finding the target file, ``do_last()`` needs to open +This case is handled by relevant callers of ``link_path_walk()``, such as +``path_lookupat()``, ``path_openat()`` using a loop that calls ``link_path_walk()``, +and then handles the final component by calling ``open_last_lookups()`` or +``lookup_last()``. If it is a symlink that needs to be followed, +``open_last_lookups()`` or ``lookup_last()`` will set things up properly and +return the path so that the loop repeats, calling +``link_path_walk()`` again. This could loop as many as 40 times if the last +component of each symlink is another symlink. + +Of the various functions that examine the final component, +``open_last_lookups()`` is the most interesting as it works in tandem +with ``do_open()`` for opening a file. Part of ``open_last_lookups()`` runs +with ``i_rwsem`` held and this part is in a separate function: ``lookup_open()``. + +Explaining ``open_last_lookups()`` and ``do_open()`` completely is beyond the scope +of this article, but a few highlights should help those interested in exploring +the code. + +1. Rather than just finding the target file, ``do_open()`` is used after + ``open_last_lookup()`` to open it. If the file was found in the dcache, then ``vfs_open()`` is used for this. If not, then ``lookup_open()`` will either call ``atomic_open()`` (if the filesystem provides it) to combine the final lookup with the open, or -- cgit v1.3.1 From 34ef75ef25c6fdea899acdb0a466f8ed0c365644 Mon Sep 17 00:00:00 2001 From: Fox Chen Date: Thu, 27 May 2021 17:16:10 +0800 Subject: docs: path-lookup: remove filename_mountpoint No filename_mountpoint any more see commit: commit 161aff1d93ab ("LOOKUP_MOUNTPOINT: fold path_mountpointat() into path_lookupat()") Without filename_mountpoint and path_mountpoint(), the numbers should be four & three: "These four correspond roughly to the three path_*() functions" Signed-off-by: Fox Chen Reviewed-by: NeilBrown Link: https://lore.kernel.org/r/20210527091618.287093-6-foxhlchen@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/filesystems/path-lookup.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/path-lookup.rst b/Documentation/filesystems/path-lookup.rst index 2b0b33168067..3cbaf30b0f83 100644 --- a/Documentation/filesystems/path-lookup.rst +++ b/Documentation/filesystems/path-lookup.rst @@ -652,9 +652,9 @@ restarts from the top with REF-walk. This pattern of "try RCU-walk, if that fails try REF-walk" can be clearly seen in functions like ``filename_lookup()``, -``filename_parentat()``, ``filename_mountpoint()``, -``do_filp_open()``, and ``do_file_open_root()``. These five -correspond roughly to the four ``path_*()`` functions we met earlier, +``filename_parentat()``, +``do_filp_open()``, and ``do_file_open_root()``. These four +correspond roughly to the three ``path_*()`` functions we met earlier, each of which calls ``link_path_walk()``. The ``path_*()`` functions are called using different mode flags until a mode is found which works. They are first called with ``LOOKUP_RCU`` set to request "RCU-walk". If -- cgit v1.3.1 From d2d3dd5ecce11ba560ff024e63ddb1640b7b27b0 Mon Sep 17 00:00:00 2001 From: Fox Chen Date: Thu, 27 May 2021 17:16:11 +0800 Subject: docs: path-lookup: Add macro name to symlink limit description Add macro name MAXSYMLINKS to the symlink limit description, so that it is consistent with path name length description above. Signed-off-by: Fox Chen Reviewed-by: NeilBrown Link: https://lore.kernel.org/r/20210527091618.287093-7-foxhlchen@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/filesystems/path-lookup.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/path-lookup.rst b/Documentation/filesystems/path-lookup.rst index 3cbaf30b0f83..40b9afec4d60 100644 --- a/Documentation/filesystems/path-lookup.rst +++ b/Documentation/filesystems/path-lookup.rst @@ -992,8 +992,8 @@ is 4096. There are a number of reasons for this limit; not letting the kernel spend too much time on just one path is one of them. With symbolic links you can effectively generate much longer paths so some sort of limit is needed for the same reason. Linux imposes a limit of -at most 40 symlinks in any one path lookup. It previously imposed a -further limit of eight on the maximum depth of recursion, but that was +at most 40 (MAXSYMLINKS) symlinks in any one path lookup. It previously imposed +a further limit of eight on the maximum depth of recursion, but that was raised to 40 when a separate stack was implemented, so there is now just the one limit. -- cgit v1.3.1 From 4a00e4bd59bbd5eac26f1792eb8d7d60f6cafe9a Mon Sep 17 00:00:00 2001 From: Fox Chen Date: Thu, 27 May 2021 17:16:12 +0800 Subject: docs: path-lookup: i_op->follow_link replaced with i_op->get_link follow_link has been replaced by get_link() which can be called in RCU mode. see commit: commit 6b2553918d8b ("replace ->follow_link() with new method that could stay in RCU mode") Signed-off-by: Fox Chen Reviewed-by: NeilBrown Link: https://lore.kernel.org/r/20210527091618.287093-8-foxhlchen@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/filesystems/path-lookup.rst | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/path-lookup.rst b/Documentation/filesystems/path-lookup.rst index 40b9afec4d60..4650c6427963 100644 --- a/Documentation/filesystems/path-lookup.rst +++ b/Documentation/filesystems/path-lookup.rst @@ -1060,13 +1060,11 @@ filesystem cannot successfully get a reference in RCU-walk mode, it must return ``-ECHILD`` and ``unlazy_walk()`` will be called to return to REF-walk mode in which the filesystem is allowed to sleep. -The place for all this to happen is the ``i_op->follow_link()`` inode -method. In the present mainline code this is never actually called in -RCU-walk mode as the rewrite is not quite complete. It is likely that -in a future release this method will be passed an ``inode`` pointer when -called in RCU-walk mode so it both (1) knows to be careful, and (2) has the -validated pointer. Much like the ``i_op->permission()`` method we -looked at previously, ``->follow_link()`` would need to be careful that +The place for all this to happen is the ``i_op->get_link()`` inode +method. This is called both in RCU-walk and REF-walk. In RCU-walk the +``dentry*`` argument is NULL, ``->get_link()`` can return -ECHILD to drop out of +RCU-walk. Much like the ``i_op->permission()`` method we +looked at previously, ``->get_link()`` would need to be careful that all the data structures it references are safe to be accessed while holding no counted reference, only the RCU lock. Though getting a reference with ``->follow_link()`` is not yet done in RCU-walk mode, the -- cgit v1.3.1 From 671f73356f6a2aa2fb1bb71f8fdeeba858b6fec6 Mon Sep 17 00:00:00 2001 From: Fox Chen Date: Thu, 27 May 2021 17:16:13 +0800 Subject: docs: path-lookup: update i_op->put_link and cookie description No inode->put_link operation anymore. We use delayed_call to deal with link destruction. Cookie has been replaced with struct delayed_call. Related commit: commit fceef393a538 ("switch ->get_link() to delayed_call, kill ->put_link()") Signed-off-by: Fox Chen Reviewed-by: NeilBrown Link: https://lore.kernel.org/r/20210527091618.287093-9-foxhlchen@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/filesystems/path-lookup.rst | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/path-lookup.rst b/Documentation/filesystems/path-lookup.rst index 4650c6427963..3855809784cf 100644 --- a/Documentation/filesystems/path-lookup.rst +++ b/Documentation/filesystems/path-lookup.rst @@ -1066,34 +1066,20 @@ method. This is called both in RCU-walk and REF-walk. In RCU-walk the RCU-walk. Much like the ``i_op->permission()`` method we looked at previously, ``->get_link()`` would need to be careful that all the data structures it references are safe to be accessed while -holding no counted reference, only the RCU lock. Though getting a -reference with ``->follow_link()`` is not yet done in RCU-walk mode, the -code is ready to release the reference when that does happen. - -This need to drop the reference to a symlink adds significant -complexity. It requires a reference to the inode so that the -``i_op->put_link()`` inode operation can be called. In REF-walk, that -reference is kept implicitly through a reference to the dentry, so -keeping the ``struct path`` of the symlink is easiest. For RCU-walk, -the pointer to the inode is kept separately. To allow switching from -RCU-walk back to REF-walk in the middle of processing nested symlinks -we also need the seq number for the dentry so we can confirm that -switching back was safe. - -Finally, when providing a reference to a symlink, the filesystem also -provides an opaque "cookie" that must be passed to ``->put_link()`` so that it -knows what to free. This might be the allocated memory area, or a -pointer to the ``struct page`` in the page cache, or something else -completely. Only the filesystem knows what it is. +holding no counted reference, only the RCU lock. A callback +``struct delayed_called`` will be passed to ``->get_link()``: +file systems can set their own put_link function and argument through +``set_delayed_call()``. Later on, when VFS wants to put link, it will call +``do_delayed_call()`` to invoke that callback function with the argument. In order for the reference to each symlink to be dropped when the walk completes, whether in RCU-walk or REF-walk, the symlink stack needs to contain, along with the path remnants: -- the ``struct path`` to provide a reference to the inode in REF-walk -- the ``struct inode *`` to provide a reference to the inode in RCU-walk +- the ``struct path`` to provide a reference to the previous path +- the ``const char *`` to provide a reference to the to previous name - the ``seq`` to allow the path to be safely switched from RCU-walk to REF-walk -- the ``cookie`` that tells ``->put_path()`` what to put. +- the ``struct delayed_call`` for later invocation. This means that each entry in the symlink stack needs to hold five pointers and an integer instead of just one pointer (the path -- cgit v1.3.1 From 18edb95a88a947b10536be4dc86b4a190715f816 Mon Sep 17 00:00:00 2001 From: Fox Chen Date: Thu, 27 May 2021 17:16:14 +0800 Subject: docs: path-lookup: no get_link() no get_link() anymore. we have step_into() and pick_link(). walk_component() will call step_into(), in turn call pick_link, and return symlink name. Signed-off-by: Fox Chen Reviewed-by: NeilBrown Link: https://lore.kernel.org/r/20210527091618.287093-10-foxhlchen@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/filesystems/path-lookup.rst | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/path-lookup.rst b/Documentation/filesystems/path-lookup.rst index 3855809784cf..0a125673a8fe 100644 --- a/Documentation/filesystems/path-lookup.rst +++ b/Documentation/filesystems/path-lookup.rst @@ -1103,12 +1103,10 @@ doesn't need to notice. Getting this ``name`` variable on and off the stack is very straightforward; pushing and popping the references is a little more complex. -When a symlink is found, ``walk_component()`` returns the value ``1`` -(``0`` is returned for any other sort of success, and a negative number -is, as usual, an error indicator). This causes ``get_link()`` to be -called; it then gets the link from the filesystem. Providing that -operation is successful, the old path ``name`` is placed on the stack, -and the new value is used as the ``name`` for a while. When the end of +When a symlink is found, ``walk_component()`` calls ``pick_link()`` via ``step_into()`` +which returns the link from the filesystem. +Providing that operation is successful, the old path ``name`` is placed on the +stack, and the new value is used as the ``name`` for a while. When the end of the path is found (i.e. ``*name`` is ``'\0'``) the old ``name`` is restored off the stack and path walking continues. -- cgit v1.3.1 From de9414adafe4da174212909e054222948aa620fc Mon Sep 17 00:00:00 2001 From: Fox Chen Date: Thu, 27 May 2021 17:16:15 +0800 Subject: docs: path-lookup: update WALK_GET, WALK_PUT desc WALK_GET is changed to WALK_TRAILING with a different meaning. Here it should be WALK_NOFOLLOW. WALK_PUT dosn't exist, we have WALK_MORE. WALK_PUT == !WALK_MORE And there is not should_follow_link(). Related commits: commit 8c4efe22e7c4 ("namei: invert the meaning of WALK_FOLLOW") commit 1c4ff1a87e46 ("namei: invert WALK_PUT logics") Signed-off-by: Fox Chen Reviewed-by: NeilBrown [jc: applied language tweaks suggested by Neil] Link: https://lore.kernel.org/r/20210527091618.287093-11-foxhlchen@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/filesystems/path-lookup.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/path-lookup.rst b/Documentation/filesystems/path-lookup.rst index 0a125673a8fe..1102252cbc7a 100644 --- a/Documentation/filesystems/path-lookup.rst +++ b/Documentation/filesystems/path-lookup.rst @@ -1123,13 +1123,13 @@ stack in ``walk_component()`` immediately when the symlink is found; old symlink as it walks that last component. So it is quite convenient for ``walk_component()`` to release the old symlink and pop the references just before pushing the reference information for the -new symlink. It is guided in this by two flags; ``WALK_GET``, which -gives it permission to follow a symlink if it finds one, and -``WALK_PUT``, which tells it to release the current symlink after it has been -followed. ``WALK_PUT`` is tested first, leading to a call to -``put_link()``. ``WALK_GET`` is tested subsequently (by -``should_follow_link()``) leading to a call to ``pick_link()`` which sets -up the stack frame. +new symlink. It is guided in this by three flags: ``WALK_NOFOLLOW`` which +forbids it from following a symlink if it finds one, ``WALK_MORE`` +which indicates that it is yet too early to release the +current symlink, and ``WALK_TRAILING`` which indicates that it is on the final +component of the lookup, so we will check userspace flag ``LOOKUP_FOLLOW`` to +decide whether follow it when it is a symlink and call ``may_follow_link()`` to +check if we have privilege to follow it. Symlinks with no final component ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- cgit v1.3.1 From 3c1be84b8d82959a6b7fedb598b8781fa1d09421 Mon Sep 17 00:00:00 2001 From: Fox Chen Date: Thu, 27 May 2021 17:16:16 +0800 Subject: docs: path-lookup: update get_link() ->follow_link description get_link() is merged into pick_link(). i_op->follow_link is replaced with i_op->get_link(). get_link() can return ERR_PTR(0) which equals NULL. Signed-off-by: Fox Chen Reviewed-by: NeilBrown Link: https://lore.kernel.org/r/20210527091618.287093-12-foxhlchen@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/filesystems/path-lookup.rst | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/path-lookup.rst b/Documentation/filesystems/path-lookup.rst index 1102252cbc7a..c150f076abbf 100644 --- a/Documentation/filesystems/path-lookup.rst +++ b/Documentation/filesystems/path-lookup.rst @@ -1136,10 +1136,10 @@ Symlinks with no final component A pair of special-case symlinks deserve a little further explanation. Both result in a new ``struct path`` (with mount and dentry) being set -up in the ``nameidata``, and result in ``get_link()`` returning ``NULL``. +up in the ``nameidata``, and result in ``pick_link()`` returning ``NULL``. The more obvious case is a symlink to "``/``". All symlinks starting -with "``/``" are detected in ``get_link()`` which resets the ``nameidata`` +with "``/``" are detected in ``pick_link()`` which resets the ``nameidata`` to point to the effective filesystem root. If the symlink only contains "``/``" then there is nothing more to do, no components at all, so ``NULL`` is returned to indicate that the symlink can be released and @@ -1156,12 +1156,11 @@ something that looks like a symlink. It is really a reference to the target file, not just the name of it. When you ``readlink`` these objects you get a name that might refer to the same file - unless it has been unlinked or mounted over. When ``walk_component()`` follows -one of these, the ``->follow_link()`` method in "procfs" doesn't return +one of these, the ``->get_link()`` method in "procfs" doesn't return a string name, but instead calls ``nd_jump_link()`` which updates the -``nameidata`` in place to point to that target. ``->follow_link()`` then -returns ``NULL``. Again there is no final component and ``get_link()`` -reports this by leaving the ``last_type`` field of ``nameidata`` as -``LAST_BIND``. +``nameidata`` in place to point to that target. ``->get_link()`` then +returns ``NULL``. Again there is no final component and ``pick_link()`` +returns ``NULL``. Following the symlink in the final component -------------------------------------------- -- cgit v1.3.1 From ef4aa53f36a932e656a3b91cdc8a9a9dcb9cef81 Mon Sep 17 00:00:00 2001 From: Fox Chen Date: Thu, 27 May 2021 17:16:17 +0800 Subject: docs: path-lookup: update symlink description instead of lookup_real()/vfs_create(), i_op->lookup() and i_op->create() will be called directly. update vfs_open() logic should_follow_link is merged into lookup_last() or open_last_lookup() which returns symlink name instead of an integer. Signed-off-by: Fox Chen Reviewed-by: NeilBrown Link: https://lore.kernel.org/r/20210527091618.287093-13-foxhlchen@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/filesystems/path-lookup.rst | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/path-lookup.rst b/Documentation/filesystems/path-lookup.rst index c150f076abbf..b746e974393a 100644 --- a/Documentation/filesystems/path-lookup.rst +++ b/Documentation/filesystems/path-lookup.rst @@ -1200,16 +1200,15 @@ the code. it. If the file was found in the dcache, then ``vfs_open()`` is used for this. If not, then ``lookup_open()`` will either call ``atomic_open()`` (if the filesystem provides it) to combine the final lookup with the open, or - will perform the separate ``lookup_real()`` and ``vfs_create()`` steps + will perform the separate ``i_op->lookup()`` and ``i_op->create()`` steps directly. In the later case the actual "open" of this newly found or created file will be performed by ``vfs_open()``, just as if the name were found in the dcache. 2. ``vfs_open()`` can fail with ``-EOPENSTALE`` if the cached information - wasn't quite current enough. Rather than restarting the lookup from - the top with ``LOOKUP_REVAL`` set, ``lookup_open()`` is called instead, - giving the filesystem a chance to resolve small inconsistencies. - If that doesn't work, only then is the lookup restarted from the top. + wasn't quite current enough. If it's in RCU-walk ``-ECHILD`` will be returned + otherwise ``-ESTALE`` is returned. When ``-ESTALE`` is returned, the caller may + retry with ``LOOKUP_REVAL`` flag set. 3. An open with O_CREAT **does** follow a symlink in the final component, unlike other creation system calls (like ``mkdir``). So the sequence:: @@ -1219,8 +1218,8 @@ the code. will create a file called ``/tmp/bar``. This is not permitted if ``O_EXCL`` is set but otherwise is handled for an O_CREAT open much - like for a non-creating open: ``should_follow_link()`` returns ``1``, and - so does ``do_last()`` so that ``trailing_symlink()`` gets called and the + like for a non-creating open: ``lookup_last()`` or ``open_last_lookup()`` + returns a non ``NULL`` value, and ``link_path_walk()`` gets called and the open process continues on the symlink that was found. Updating the access time -- cgit v1.3.1 From 8943474a416c0d2eac2366c22be1458ad0ceb812 Mon Sep 17 00:00:00 2001 From: Fox Chen Date: Thu, 27 May 2021 17:16:18 +0800 Subject: docs: path-lookup: use bare function() rather than literals As suggested by Matthew Wilcox and Jonathan Corbet, drop ``...`` literals around function names of this patchset. Signed-off-by: Fox Chen Reviewed-by: NeilBrown Link: https://lore.kernel.org/r/20210527091618.287093-14-foxhlchen@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/filesystems/path-lookup.rst | 70 +++++++++++++++---------------- 1 file changed, 35 insertions(+), 35 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/path-lookup.rst b/Documentation/filesystems/path-lookup.rst index b746e974393a..a6fa7619b69e 100644 --- a/Documentation/filesystems/path-lookup.rst +++ b/Documentation/filesystems/path-lookup.rst @@ -450,13 +450,13 @@ If that doesn't get a good result, it calls "``lookup_slow()``" which takes ``i_rwsem``, rechecks the cache, and then asks the filesystem to find a definitive answer. -As the last step of ``walk_component()``, ``step_into()`` will be called either +As the last step of walk_component(), step_into() will be called either directly from walk_component() or from handle_dots(). It calls -``handle_mounts()``, to check and handle mount points, in which a new +handle_mounts(), to check and handle mount points, in which a new ``struct path`` is created containing a counted reference to the new dentry and a reference to the new ``vfsmount`` which is only counted if it is different from the previous ``vfsmount``. Then if there is -a symbolic link, ``step_into()`` calls ``pick_link()`` to deal with it, +a symbolic link, step_into() calls pick_link() to deal with it, otherwise it installs the new ``struct path`` in the ``struct nameidata``, and drops the unneeded references. @@ -472,8 +472,8 @@ Handling the final component ``nd->last_type`` to refer to the final component of the path. It does not call ``walk_component()`` that last time. Handling that final component remains for the caller to sort out. Those callers are -``path_lookupat()``, ``path_parentat()`` and -``path_openat()`` each of which handles the differing requirements of +path_lookupat(), path_parentat() and +path_openat() each of which handles the differing requirements of different system calls. ``path_parentat()`` is clearly the simplest - it just wraps a little bit @@ -489,17 +489,17 @@ object is wanted such as by ``stat()`` or ``chmod()``. It essentially just calls ``walk_component()`` on the final component through a call to ``lookup_last()``. ``path_lookupat()`` returns just the final dentry. It is worth noting that when flag ``LOOKUP_MOUNTPOINT`` is set, -``path_lookupat()`` will unset LOOKUP_JUMPED in nameidata so that in the -subsequent path traversal ``d_weak_revalidate()`` won't be called. +path_lookupat() will unset LOOKUP_JUMPED in nameidata so that in the +subsequent path traversal d_weak_revalidate() won't be called. This is important when unmounting a filesystem that is inaccessible, such as one provided by a dead NFS server. Finally ``path_openat()`` is used for the ``open()`` system call; it -contains, in support functions starting with "``open_last_lookups()``", all the +contains, in support functions starting with "open_last_lookups()", all the complexity needed to handle the different subtleties of O_CREAT (with or without O_EXCL), final "``/``" characters, and trailing symbolic links. We will revisit this in the final part of this series, which -focuses on those symbolic links. "``open_last_lookups()``" will sometimes, but +focuses on those symbolic links. "open_last_lookups()" will sometimes, but not always, take ``i_rwsem``, depending on what it finds. Each of these, or the functions which call them, need to be alert to @@ -651,9 +651,9 @@ RCU-walk finds it cannot stop gracefully, it simply gives up and restarts from the top with REF-walk. This pattern of "try RCU-walk, if that fails try REF-walk" can be -clearly seen in functions like ``filename_lookup()``, -``filename_parentat()``, -``do_filp_open()``, and ``do_file_open_root()``. These four +clearly seen in functions like filename_lookup(), +filename_parentat(), +do_filp_open(), and do_file_open_root(). These four correspond roughly to the three ``path_*()`` functions we met earlier, each of which calls ``link_path_walk()``. The ``path_*()`` functions are called using different mode flags until a mode is found which works. @@ -1069,8 +1069,8 @@ all the data structures it references are safe to be accessed while holding no counted reference, only the RCU lock. A callback ``struct delayed_called`` will be passed to ``->get_link()``: file systems can set their own put_link function and argument through -``set_delayed_call()``. Later on, when VFS wants to put link, it will call -``do_delayed_call()`` to invoke that callback function with the argument. +set_delayed_call(). Later on, when VFS wants to put link, it will call +do_delayed_call() to invoke that callback function with the argument. In order for the reference to each symlink to be dropped when the walk completes, whether in RCU-walk or REF-walk, the symlink stack needs to contain, @@ -1103,7 +1103,7 @@ doesn't need to notice. Getting this ``name`` variable on and off the stack is very straightforward; pushing and popping the references is a little more complex. -When a symlink is found, ``walk_component()`` calls ``pick_link()`` via ``step_into()`` +When a symlink is found, walk_component() calls pick_link() via step_into() which returns the link from the filesystem. Providing that operation is successful, the old path ``name`` is placed on the stack, and the new value is used as the ``name`` for a while. When the end of @@ -1136,10 +1136,10 @@ Symlinks with no final component A pair of special-case symlinks deserve a little further explanation. Both result in a new ``struct path`` (with mount and dentry) being set -up in the ``nameidata``, and result in ``pick_link()`` returning ``NULL``. +up in the ``nameidata``, and result in pick_link() returning ``NULL``. The more obvious case is a symlink to "``/``". All symlinks starting -with "``/``" are detected in ``pick_link()`` which resets the ``nameidata`` +with "``/``" are detected in pick_link() which resets the ``nameidata`` to point to the effective filesystem root. If the symlink only contains "``/``" then there is nothing more to do, no components at all, so ``NULL`` is returned to indicate that the symlink can be released and @@ -1157,9 +1157,9 @@ target file, not just the name of it. When you ``readlink`` these objects you get a name that might refer to the same file - unless it has been unlinked or mounted over. When ``walk_component()`` follows one of these, the ``->get_link()`` method in "procfs" doesn't return -a string name, but instead calls ``nd_jump_link()`` which updates the +a string name, but instead calls nd_jump_link() which updates the ``nameidata`` in place to point to that target. ``->get_link()`` then -returns ``NULL``. Again there is no final component and ``pick_link()`` +returns ``NULL``. Again there is no final component and pick_link() returns ``NULL``. Following the symlink in the final component @@ -1177,35 +1177,35 @@ potentially need to call ``link_path_walk()`` again and again on successive symlinks until one is found that doesn't point to another symlink. -This case is handled by relevant callers of ``link_path_walk()``, such as -``path_lookupat()``, ``path_openat()`` using a loop that calls ``link_path_walk()``, -and then handles the final component by calling ``open_last_lookups()`` or -``lookup_last()``. If it is a symlink that needs to be followed, -``open_last_lookups()`` or ``lookup_last()`` will set things up properly and +This case is handled by relevant callers of link_path_walk(), such as +path_lookupat(), path_openat() using a loop that calls link_path_walk(), +and then handles the final component by calling open_last_lookups() or +lookup_last(). If it is a symlink that needs to be followed, +open_last_lookups() or lookup_last() will set things up properly and return the path so that the loop repeats, calling -``link_path_walk()`` again. This could loop as many as 40 times if the last +link_path_walk() again. This could loop as many as 40 times if the last component of each symlink is another symlink. Of the various functions that examine the final component, -``open_last_lookups()`` is the most interesting as it works in tandem -with ``do_open()`` for opening a file. Part of ``open_last_lookups()`` runs -with ``i_rwsem`` held and this part is in a separate function: ``lookup_open()``. +open_last_lookups() is the most interesting as it works in tandem +with do_open() for opening a file. Part of open_last_lookups() runs +with ``i_rwsem`` held and this part is in a separate function: lookup_open(). -Explaining ``open_last_lookups()`` and ``do_open()`` completely is beyond the scope +Explaining open_last_lookups() and do_open() completely is beyond the scope of this article, but a few highlights should help those interested in exploring the code. -1. Rather than just finding the target file, ``do_open()`` is used after - ``open_last_lookup()`` to open +1. Rather than just finding the target file, do_open() is used after + open_last_lookup() to open it. If the file was found in the dcache, then ``vfs_open()`` is used for this. If not, then ``lookup_open()`` will either call ``atomic_open()`` (if the filesystem provides it) to combine the final lookup with the open, or will perform the separate ``i_op->lookup()`` and ``i_op->create()`` steps directly. In the later case the actual "open" of this newly found or - created file will be performed by ``vfs_open()``, just as if the name + created file will be performed by vfs_open(), just as if the name were found in the dcache. -2. ``vfs_open()`` can fail with ``-EOPENSTALE`` if the cached information +2. vfs_open() can fail with ``-EOPENSTALE`` if the cached information wasn't quite current enough. If it's in RCU-walk ``-ECHILD`` will be returned otherwise ``-ESTALE`` is returned. When ``-ESTALE`` is returned, the caller may retry with ``LOOKUP_REVAL`` flag set. @@ -1218,8 +1218,8 @@ the code. will create a file called ``/tmp/bar``. This is not permitted if ``O_EXCL`` is set but otherwise is handled for an O_CREAT open much - like for a non-creating open: ``lookup_last()`` or ``open_last_lookup()`` - returns a non ``NULL`` value, and ``link_path_walk()`` gets called and the + like for a non-creating open: lookup_last() or open_last_lookup() + returns a non ``NULL`` value, and link_path_walk() gets called and the open process continues on the symlink that was found. Updating the access time -- cgit v1.3.1 From 3a02764c372c50ff7917fde5c6961f6cdb81d9d5 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 18 Jun 2021 22:09:13 +0800 Subject: riscv: Ensure BPF_JIT_REGION_START aligned with PMD size Andreas reported commit fc8504765ec5 ("riscv: bpf: Avoid breaking W^X") breaks booting with one kind of defconfig, I reproduced a kernel panic with the defconfig: [ 0.138553] Unable to handle kernel paging request at virtual address ffffffff81201220 [ 0.139159] Oops [#1] [ 0.139303] Modules linked in: [ 0.139601] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.13.0-rc5-default+ #1 [ 0.139934] Hardware name: riscv-virtio,qemu (DT) [ 0.140193] epc : __memset+0xc4/0xfc [ 0.140416] ra : skb_flow_dissector_init+0x1e/0x82 [ 0.140609] epc : ffffffff8029806c ra : ffffffff8033be78 sp : ffffffe001647da0 [ 0.140878] gp : ffffffff81134b08 tp : ffffffe001654380 t0 : ffffffff81201158 [ 0.141156] t1 : 0000000000000002 t2 : 0000000000000154 s0 : ffffffe001647dd0 [ 0.141424] s1 : ffffffff80a43250 a0 : ffffffff81201220 a1 : 0000000000000000 [ 0.141654] a2 : 000000000000003c a3 : ffffffff81201258 a4 : 0000000000000064 [ 0.141893] a5 : ffffffff8029806c a6 : 0000000000000040 a7 : ffffffffffffffff [ 0.142126] s2 : ffffffff81201220 s3 : 0000000000000009 s4 : ffffffff81135088 [ 0.142353] s5 : ffffffff81135038 s6 : ffffffff8080ce80 s7 : ffffffff80800438 [ 0.142584] s8 : ffffffff80bc6578 s9 : 0000000000000008 s10: ffffffff806000ac [ 0.142810] s11: 0000000000000000 t3 : fffffffffffffffc t4 : 0000000000000000 [ 0.143042] t5 : 0000000000000155 t6 : 00000000000003ff [ 0.143220] status: 0000000000000120 badaddr: ffffffff81201220 cause: 000000000000000f [ 0.143560] [] __memset+0xc4/0xfc [ 0.143859] [] init_default_flow_dissectors+0x22/0x60 [ 0.144092] [] do_one_initcall+0x3e/0x168 [ 0.144278] [] kernel_init_freeable+0x1c8/0x224 [ 0.144479] [] kernel_init+0x12/0x110 [ 0.144658] [] ret_from_exception+0x0/0xc [ 0.145124] ---[ end trace f1e9643daa46d591 ]--- After some investigation, I think I found the root cause: commit 2bfc6cd81bd ("move kernel mapping outside of linear mapping") moves BPF JIT region after the kernel: | #define BPF_JIT_REGION_START PFN_ALIGN((unsigned long)&_end) The &_end is unlikely aligned with PMD size, so the front bpf jit region sits with part of kernel .data section in one PMD size mapping. But kernel is mapped in PMD SIZE, when bpf_jit_binary_lock_ro() is called to make the first bpf jit prog ROX, we will make part of kernel .data section RO too, so when we write to, for example memset the .data section, MMU will trigger a store page fault. To fix the issue, we need to ensure the BPF JIT region is PMD size aligned. This patch acchieve this goal by restoring the BPF JIT region to original position, I.E the 128MB before kernel .text section. The modification to kasan_init.c is inspired by Alexandre. Fixes: fc8504765ec5 ("riscv: bpf: Avoid breaking W^X") Reported-by: Andreas Schwab Signed-off-by: Jisheng Zhang Signed-off-by: Palmer Dabbelt --- Documentation/riscv/vm-layout.rst | 4 ++-- arch/riscv/include/asm/pgtable.h | 5 ++--- arch/riscv/mm/kasan_init.c | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/riscv/vm-layout.rst b/Documentation/riscv/vm-layout.rst index 329d32098af4..b7f98930d38d 100644 --- a/Documentation/riscv/vm-layout.rst +++ b/Documentation/riscv/vm-layout.rst @@ -58,6 +58,6 @@ RISC-V Linux Kernel SV39 | ____________________________________________________________|____________________________________________________________ | | | | - ffffffff00000000 | -4 GB | ffffffff7fffffff | 2 GB | modules - ffffffff80000000 | -2 GB | ffffffffffffffff | 2 GB | kernel, BPF + ffffffff00000000 | -4 GB | ffffffff7fffffff | 2 GB | modules, BPF + ffffffff80000000 | -2 GB | ffffffffffffffff | 2 GB | kernel __________________|____________|__________________|_________|____________________________________________________________ diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index 9469f464e71a..380cd3a7e548 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -30,9 +30,8 @@ #define BPF_JIT_REGION_SIZE (SZ_128M) #ifdef CONFIG_64BIT -/* KASLR should leave at least 128MB for BPF after the kernel */ -#define BPF_JIT_REGION_START PFN_ALIGN((unsigned long)&_end) -#define BPF_JIT_REGION_END (BPF_JIT_REGION_START + BPF_JIT_REGION_SIZE) +#define BPF_JIT_REGION_START (BPF_JIT_REGION_END - BPF_JIT_REGION_SIZE) +#define BPF_JIT_REGION_END (MODULES_END) #else #define BPF_JIT_REGION_START (PAGE_OFFSET - BPF_JIT_REGION_SIZE) #define BPF_JIT_REGION_END (VMALLOC_END) diff --git a/arch/riscv/mm/kasan_init.c b/arch/riscv/mm/kasan_init.c index a0d9e4ace331..d7189c8714a9 100644 --- a/arch/riscv/mm/kasan_init.c +++ b/arch/riscv/mm/kasan_init.c @@ -201,7 +201,7 @@ void __init kasan_init(void) /* Populate kernel, BPF, modules mapping */ kasan_populate(kasan_mem_to_shadow((const void *)MODULES_VADDR), - kasan_mem_to_shadow((const void *)BPF_JIT_REGION_END)); + kasan_mem_to_shadow((const void *)MODULES_VADDR + SZ_2G)); for (i = 0; i < PTRS_PER_PTE; i++) set_pte(&kasan_early_shadow_pte[i], -- cgit v1.3.1 From 85adaac269c36d8e2e0a5de87a1dc4ec06e984f1 Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Thu, 17 Jun 2021 10:47:08 +0530 Subject: regulator: qcom,rpmh-regulator: Arrange compatibles alphabetically Arrange the compatibles inside qcom-rpmh regulator device tree bindings alphabetically. Cc: Mark Brown Cc: Bjorn Andersson Signed-off-by: Bhupesh Sharma Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210617051712.345372-2-bhupesh.sharma@linaro.org Signed-off-by: Mark Brown --- .../bindings/regulator/qcom,rpmh-regulator.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml index e561a5b941e4..3546c6a966a3 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml @@ -33,6 +33,9 @@ description: | The names used for regulator nodes must match those supported by a given PMIC. Supported regulator node names are + For PM6150, smps1 - smps5, ldo1 - ldo19 + For PM6150L, smps1 - smps8, ldo1 - ldo11, bob + For PM7325, smps1 - smps8, ldo1 - ldo19 For PM8005, smps1 - smps4 For PM8009, smps1 - smps2, ldo1 - ldo7 For PM8150, smps1 - smps10, ldo1 - ldo18 @@ -41,15 +44,15 @@ description: | For PM8350C, smps1 - smps10, ldo1 - ldo13, bob For PM8998, smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2 For PMI8998, bob - For PM6150, smps1 - smps5, ldo1 - ldo19 - For PM6150L, smps1 - smps8, ldo1 - ldo11, bob - For PMX55, smps1 - smps7, ldo1 - ldo16 - For PM7325, smps1 - smps8, ldo1 - ldo19 For PMR735A, smps1 - smps3, ldo1 - ldo7 + For PMX55, smps1 - smps7, ldo1 - ldo16 properties: compatible: enum: + - qcom,pm6150-rpmh-regulators + - qcom,pm6150l-rpmh-regulators + - qcom,pm7325-rpmh-regulators - qcom,pm8005-rpmh-regulators - qcom,pm8009-rpmh-regulators - qcom,pm8009-1-rpmh-regulators @@ -59,11 +62,8 @@ properties: - qcom,pm8350c-rpmh-regulators - qcom,pm8998-rpmh-regulators - qcom,pmi8998-rpmh-regulators - - qcom,pm6150-rpmh-regulators - - qcom,pm6150l-rpmh-regulators - - qcom,pmx55-rpmh-regulators - - qcom,pm7325-rpmh-regulators - qcom,pmr735a-rpmh-regulators + - qcom,pmx55-rpmh-regulators qcom,pmic-id: description: | -- cgit v1.3.1 From 66376e152303bb60d6a75328b7bc998de86f8c08 Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Thu, 17 Jun 2021 10:47:09 +0530 Subject: regulator: qcom,rpmh-regulator: Add compatible for SA8155p-adp board pmic Add compatible string for pmm8155au pmic found on the SA8155p-adp board. Cc: Mark Brown Cc: Bjorn Andersson Signed-off-by: Bhupesh Sharma Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210617051712.345372-3-bhupesh.sharma@linaro.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml index 3546c6a966a3..34de38377aa6 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml @@ -62,6 +62,7 @@ properties: - qcom,pm8350c-rpmh-regulators - qcom,pm8998-rpmh-regulators - qcom,pmi8998-rpmh-regulators + - qcom,pmm8155au-rpmh-regulators - qcom,pmr735a-rpmh-regulators - qcom,pmx55-rpmh-regulators -- cgit v1.3.1 From 01c5741b82969d096ac0870d997b7d2f5a5fe970 Mon Sep 17 00:00:00 2001 From: Sergey Larin Date: Fri, 18 Jun 2021 17:16:07 +0300 Subject: regulator: Add MAX8893 bindings Add Maxim MAX8893 PMIC device tree bindings. The example is also provided. Signed-off-by: Sergey Larin Link: https://lore.kernel.org/r/20210618141607.884-2-cerg2010cerg2010@mail.ru Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/max8893.yaml | 88 ++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/max8893.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/max8893.yaml b/Documentation/devicetree/bindings/regulator/max8893.yaml new file mode 100644 index 000000000000..2b5e977bf409 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/max8893.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/max8893.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Regulator driver for MAX8893 PMIC from Maxim Integrated. + +maintainers: + - Sergey Larin + +description: | + The device has 5 LDO regulators and a single BUCK regulator. + Programming is done through I2C bus. + +properties: + compatible: + const: maxim,max8893 + + reg: + maxItems: 1 + + regulators: + type: object + + patternProperties: + "^(ldo[1-5]|buck)$": + $ref: "regulator.yaml#" + + additionalProperties: false + +additionalProperties: false + +required: + - compatible + - reg + - regulators + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@3e { + compatible = "maxim,max8893"; + reg = <0x3e>; + + regulators { + /* Front camera - s5k6aafx, back - m5mo */ + /* Numbers used to indicate the sequence */ + front_1_back_1: buck { + regulator-name = "cam_isp_core_1v2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + front_4_back_5: ldo1 { + regulator-name = "vt_io_1v8,cam_isp_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + front_3_back_4: ldo2 { + regulator-name = "vt_core_1v5"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + }; + + front_5_back_6: ldo3 { + regulator-name = "vt_cam_1v8,vt_sensor_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo4 { + /* not used */ + }; + + back_7: ldo5 { + regulator-name = "cam_sensor_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + }; + }; + }; +... -- cgit v1.3.1 From 673e851b7da81256e73fb738c550ec39bac1c9ff Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Thu, 3 Jun 2021 08:40:28 +0300 Subject: regulator: Add protection limit properties Support specifying protection/error/warning limits for regulator over current, over temperature and over/under voltage. Most of the PMICs support only "protection" feature but few setups do also support error/warning level indications. On many ICs most of the protection limits can't actually be set. But for example the ampere limit for over-current protection on ROHM BD9576 can be configured - or feature can be completely disabled. Provide limit setting for all protections/errors for the sake of the completeness and do that using own properties for all so that not all users would need to set all levels when only one or few are supported. Signed-off-by: Matti Vaittinen Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/ae2c6056d5ed1334912d27e736d23c9151065433.1622628333.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/regulator.yaml | 82 ++++++++++++++++++++++ 1 file changed, 82 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml b/Documentation/devicetree/bindings/regulator/regulator.yaml index 6d0bc9cd4040..a6ae9ecae5cc 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/regulator.yaml @@ -117,6 +117,88 @@ properties: description: Enable over current protection. type: boolean + regulator-oc-protection-microamp: + description: Set over current protection limit. This is a limit where + hardware performs emergency shutdown. Zero can be passed to disable + protection and value '1' indicates that protection should be enabled but + limit setting can be omitted. + + regulator-oc-error-microamp: + description: Set over current error limit. This is a limit where part of + the hardware propably is malfunctional and damage prevention is requested. + Zero can be passed to disable error detection and value '1' indicates + that detection should be enabled but limit setting can be omitted. + + regulator-oc-warn-microamp: + description: Set over current warning limit. This is a limit where hardware + is assumed still to be functional but approaching limit where it gets + damaged. Recovery actions should be initiated. Zero can be passed to + disable detection and value '1' indicates that detection should + be enabled but limit setting can be omitted. + + regulator-ov-protection-microvolt: + description: Set over voltage protection limit. This is a limit where + hardware performs emergency shutdown. Zero can be passed to disable + protection and value '1' indicates that protection should be enabled but + limit setting can be omitted. Limit is given as microvolt offset from + voltage set to regulator. + + regulator-ov-error-microvolt: + description: Set over voltage error limit. This is a limit where part of + the hardware propably is malfunctional and damage prevention is requested + Zero can be passed to disable error detection and value '1' indicates + that detection should be enabled but limit setting can be omitted. Limit + is given as microvolt offset from voltage set to regulator. + + regulator-ov-warn-microvolt: + description: Set over voltage warning limit. This is a limit where hardware + is assumed still to be functional but approaching limit where it gets + damaged. Recovery actions should be initiated. Zero can be passed to + disable detection and value '1' indicates that detection should + be enabled but limit setting can be omitted. Limit is given as microvolt + offset from voltage set to regulator. + + regulator-uv-protection-microvolt: + description: Set over under voltage protection limit. This is a limit where + hardware performs emergency shutdown. Zero can be passed to disable + protection and value '1' indicates that protection should be enabled but + limit setting can be omitted. Limit is given as microvolt offset from + voltage set to regulator. + + regulator-uv-error-microvolt: + description: Set under voltage error limit. This is a limit where part of + the hardware propably is malfunctional and damage prevention is requested + Zero can be passed to disable error detection and value '1' indicates + that detection should be enabled but limit setting can be omitted. Limit + is given as microvolt offset from voltage set to regulator. + + regulator-uv-warn-microvolt: + description: Set over under voltage warning limit. This is a limit where + hardware is assumed still to be functional but approaching limit where + it gets damaged. Recovery actions should be initiated. Zero can be passed + to disable detection and value '1' indicates that detection should + be enabled but limit setting can be omitted. Limit is given as microvolt + offset from voltage set to regulator. + + regulator-temp-protection-kelvin: + description: Set over temperature protection limit. This is a limit where + hardware performs emergency shutdown. Zero can be passed to disable + protection and value '1' indicates that protection should be enabled but + limit setting can be omitted. + + regulator-temp-error-kelvin: + description: Set over temperature error limit. This is a limit where part of + the hardware propably is malfunctional and damage prevention is requested + Zero can be passed to disable error detection and value '1' indicates + that detection should be enabled but limit setting can be omitted. + + regulator-temp-warn-kelvin: + description: Set over temperature warning limit. This is a limit where + hardware is assumed still to be functional but approaching limit where it + gets damaged. Recovery actions should be initiated. Zero can be passed to + disable detection and value '1' indicates that detection should + be enabled but limit setting can be omitted. + regulator-active-discharge: description: | tristate, enable/disable active discharge of regulators. The values are: -- cgit v1.3.1 From db0aeb4f074f7023da26fb65078197c39590346b Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Thu, 3 Jun 2021 08:41:03 +0300 Subject: thermal: Use generic HW-protection shutdown API The hardware shutdown function was exported from kernel/reboot for other subsystems to use. Logic is copied from the thermal_core. The protection mutex is replaced by an atomic_t to allow calls also from an IRQ context. Also the WARN() was replaced by pr_emerg() based on discussions here: https://lore.kernel.org/lkml/YJuPwAZroVZ%2Fw633@alley/ and here: https://lore.kernel.org/linux-iommu/20210331093104.383705-4-geert+renesas@glider.be/ Use the exported API instead of implementing own just for the thermal_core. Signed-off-by: Matti Vaittinen Acked-by: Daniel Lezcano Link: https://lore.kernel.org/r/5531e89d9e710f5d10e7cdce3ee58957335b9e03.1622628333.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- Documentation/driver-api/thermal/sysfs-api.rst | 24 ++++------ drivers/thermal/thermal_core.c | 63 ++------------------------ 2 files changed, 13 insertions(+), 74 deletions(-) (limited to 'Documentation') diff --git a/Documentation/driver-api/thermal/sysfs-api.rst b/Documentation/driver-api/thermal/sysfs-api.rst index 4b638c14bc16..c93fa5e961a0 100644 --- a/Documentation/driver-api/thermal/sysfs-api.rst +++ b/Documentation/driver-api/thermal/sysfs-api.rst @@ -740,21 +740,15 @@ possible. 5. thermal_emergency_poweroff ============================= -On an event of critical trip temperature crossing. Thermal framework -allows the system to shutdown gracefully by calling orderly_poweroff(). -In the event of a failure of orderly_poweroff() to shut down the system -we are in danger of keeping the system alive at undesirably high -temperatures. To mitigate this high risk scenario we program a work -queue to fire after a pre-determined number of seconds to start -an emergency shutdown of the device using the kernel_power_off() -function. In case kernel_power_off() fails then finally -emergency_restart() is called in the worst case. +On an event of critical trip temperature crossing the thermal framework +shuts down the system by calling hw_protection_shutdown(). The +hw_protection_shutdown() first attempts to perform an orderly shutdown +but accepts a delay after which it proceeds doing a forced power-off +or as last resort an emergency_restart. The delay should be carefully profiled so as to give adequate time for -orderly_poweroff(). In case of failure of an orderly_poweroff() the -emergency poweroff kicks in after the delay has elapsed and shuts down -the system. +orderly poweroff. -If set to 0 emergency poweroff will not be supported. So a carefully -profiled non-zero positive value is a must for emergency poweroff to be -triggered. +If the delay is set to 0 emergency poweroff will not be supported. So a +carefully profiled non-zero positive value is a must for emergency +poweroff to be triggered. diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index d20b25f40d19..10a2d8e1cacf 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -36,10 +36,8 @@ static LIST_HEAD(thermal_governor_list); static DEFINE_MUTEX(thermal_list_lock); static DEFINE_MUTEX(thermal_governor_lock); -static DEFINE_MUTEX(poweroff_lock); static atomic_t in_suspend; -static bool power_off_triggered; static struct thermal_governor *def_governor; @@ -327,70 +325,18 @@ static void handle_non_critical_trips(struct thermal_zone_device *tz, int trip) def_governor->throttle(tz, trip); } -/** - * thermal_emergency_poweroff_func - emergency poweroff work after a known delay - * @work: work_struct associated with the emergency poweroff function - * - * This function is called in very critical situations to force - * a kernel poweroff after a configurable timeout value. - */ -static void thermal_emergency_poweroff_func(struct work_struct *work) -{ - /* - * We have reached here after the emergency thermal shutdown - * Waiting period has expired. This means orderly_poweroff has - * not been able to shut off the system for some reason. - * Try to shut down the system immediately using kernel_power_off - * if populated - */ - WARN(1, "Attempting kernel_power_off: Temperature too high\n"); - kernel_power_off(); - - /* - * Worst of the worst case trigger emergency restart - */ - WARN(1, "Attempting emergency_restart: Temperature too high\n"); - emergency_restart(); -} - -static DECLARE_DELAYED_WORK(thermal_emergency_poweroff_work, - thermal_emergency_poweroff_func); - -/** - * thermal_emergency_poweroff - Trigger an emergency system poweroff - * - * This may be called from any critical situation to trigger a system shutdown - * after a known period of time. By default this is not scheduled. - */ -static void thermal_emergency_poweroff(void) +void thermal_zone_device_critical(struct thermal_zone_device *tz) { - int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS; /* * poweroff_delay_ms must be a carefully profiled positive value. - * Its a must for thermal_emergency_poweroff_work to be scheduled + * Its a must for forced_emergency_poweroff_work to be scheduled. */ - if (poweroff_delay_ms <= 0) - return; - schedule_delayed_work(&thermal_emergency_poweroff_work, - msecs_to_jiffies(poweroff_delay_ms)); -} + int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS; -void thermal_zone_device_critical(struct thermal_zone_device *tz) -{ dev_emerg(&tz->device, "%s: critical temperature reached, " "shutting down\n", tz->type); - mutex_lock(&poweroff_lock); - if (!power_off_triggered) { - /* - * Queue a backup emergency shutdown in the event of - * orderly_poweroff failure - */ - thermal_emergency_poweroff(); - orderly_poweroff(true); - power_off_triggered = true; - } - mutex_unlock(&poweroff_lock); + hw_protection_shutdown("Temperature too high", poweroff_delay_ms); } EXPORT_SYMBOL(thermal_zone_device_critical); @@ -1538,7 +1484,6 @@ error: ida_destroy(&thermal_cdev_ida); mutex_destroy(&thermal_list_lock); mutex_destroy(&thermal_governor_lock); - mutex_destroy(&poweroff_lock); return result; } postcore_initcall(thermal_init); -- cgit v1.3.1 From 627793e4ca4f511837de893545baf0e1b8174dc2 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Thu, 3 Jun 2021 08:42:30 +0300 Subject: regulator: bd9576 add FET ON-resistance for OCW BD9576MUF provides over-current protection and detection. Current is measured as voltage loss over external FET. Allow specifying FET's on resistance so current monitoring limits can be converted to voltages. Signed-off-by: Matti Vaittinen Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/e5feb160d7e09f33fff5b88f1928c66a15c6680f.1622628334.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/rohm,bd9576-regulator.yaml | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml b/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml index b6515a0cee62..7cb74cc8c5d9 100644 --- a/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml @@ -27,6 +27,12 @@ patternProperties: Properties for single regulator. $ref: "regulator.yaml#" + properties: + rohm,ocw-fet-ron-micro-ohms: + description: | + External FET's ON-resistance. Required if VoutS1 OCP/OCW is + to be set. + required: - regulator-name -- cgit v1.3.1 From d90609a4b72dbfe42da2a55f3078c35e669948e0 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 21 Jun 2021 19:53:56 +0200 Subject: spi: dt-bindings: support devices with multiple chipselects Add binding support for devices, that have more than one chip select. A typical example are SPI connected microcontroller, that can also be programmed over SPI like NXP Kinetis or chips with a configuration and a data chip select, such as Microchip's MRF89XA transceiver. Reviewed-by: Rob Herring Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20210621175359.126729-3-sebastian.reichel@collabora.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-controller.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-controller.yaml b/Documentation/devicetree/bindings/spi/spi-controller.yaml index 0477396e4945..faef4f6f55b8 100644 --- a/Documentation/devicetree/bindings/spi/spi-controller.yaml +++ b/Documentation/devicetree/bindings/spi/spi-controller.yaml @@ -114,8 +114,11 @@ patternProperties: Compatible of the SPI device. reg: - minimum: 0 - maximum: 256 + minItems: 1 + maxItems: 256 + items: + minimum: 0 + maximum: 256 description: Chip select used by the device. -- cgit v1.3.1 From 04c02c201d7e8149ae336ead69fb64e4e6f94bc9 Mon Sep 17 00:00:00 2001 From: Steven Price Date: Mon, 21 Jun 2021 12:17:16 +0100 Subject: KVM: arm64: Document MTE capability and ioctl A new capability (KVM_CAP_ARM_MTE) identifies that the kernel supports granting a guest access to the tags, and provides a mechanism for the VMM to enable it. A new ioctl (KVM_ARM_MTE_COPY_TAGS) provides a simple way for a VMM to access the tags of a guest without having to maintain a PROT_MTE mapping in userspace. The above capability gates access to the ioctl. Reviewed-by: Catalin Marinas Signed-off-by: Steven Price Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20210621111716.37157-7-steven.price@arm.com --- Documentation/virt/kvm/api.rst | 61 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 7fcb2fd38f42..97661a97943f 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -5034,6 +5034,43 @@ see KVM_XEN_VCPU_SET_ATTR above. The KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST type may not be used with the KVM_XEN_VCPU_GET_ATTR ioctl. +4.130 KVM_ARM_MTE_COPY_TAGS +--------------------------- + +:Capability: KVM_CAP_ARM_MTE +:Architectures: arm64 +:Type: vm ioctl +:Parameters: struct kvm_arm_copy_mte_tags +:Returns: number of bytes copied, < 0 on error (-EINVAL for incorrect + arguments, -EFAULT if memory cannot be accessed). + +:: + + struct kvm_arm_copy_mte_tags { + __u64 guest_ipa; + __u64 length; + void __user *addr; + __u64 flags; + __u64 reserved[2]; + }; + +Copies Memory Tagging Extension (MTE) tags to/from guest tag memory. The +``guest_ipa`` and ``length`` fields must be ``PAGE_SIZE`` aligned. The ``addr`` +field must point to a buffer which the tags will be copied to or from. + +``flags`` specifies the direction of copy, either ``KVM_ARM_TAGS_TO_GUEST`` or +``KVM_ARM_TAGS_FROM_GUEST``. + +The size of the buffer to store the tags is ``(length / 16)`` bytes +(granules in MTE are 16 bytes long). Each byte contains a single tag +value. This matches the format of ``PTRACE_PEEKMTETAGS`` and +``PTRACE_POKEMTETAGS``. + +If an error occurs before any data is copied then a negative error code is +returned. If some tags have been copied before an error occurs then the number +of bytes successfully copied is returned. If the call completes successfully +then ``length`` is returned. + 5. The kvm_run structure ======================== @@ -6362,6 +6399,30 @@ default. See Documentation/x86/sgx/2.Kernel-internals.rst for more details. +7.26 KVM_CAP_ARM_MTE +-------------------- + +:Architectures: arm64 +:Parameters: none + +This capability indicates that KVM (and the hardware) supports exposing the +Memory Tagging Extensions (MTE) to the guest. It must also be enabled by the +VMM before creating any VCPUs to allow the guest access. Note that MTE is only +available to a guest running in AArch64 mode and enabling this capability will +cause attempts to create AArch32 VCPUs to fail. + +When enabled the guest is able to access tags associated with any memory given +to the guest. KVM will ensure that the tags are maintained during swap or +hibernation of the host; however the VMM needs to manually save/restore the +tags as appropriate if the VM is migrated. + +When this capability is enabled all memory in memslots must be mapped as +not-shareable (no MAP_SHARED), attempts to create a memslot with a +MAP_SHARED mmap will result in an -EINVAL return. + +When enabled the VMM may make use of the ``KVM_ARM_MTE_COPY_TAGS`` ioctl to +perform a bulk copy of tags to/from the guest. + 8. Other capabilities. ====================== -- cgit v1.3.1 From b87cc116c7e1bc62a84d8c46acd401db179edb11 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Mon, 21 Jun 2021 14:20:02 +0530 Subject: KVM: PPC: Book3S HV: Add KVM_CAP_PPC_RPT_INVALIDATE capability Now that we have H_RPT_INVALIDATE fully implemented, enable support for the same via KVM_CAP_PPC_RPT_INVALIDATE KVM capability Signed-off-by: Bharata B Rao Reviewed-by: David Gibson Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20210621085003.904767-6-bharata@linux.ibm.com --- Documentation/virt/kvm/api.rst | 18 ++++++++++++++++++ arch/powerpc/kvm/powerpc.c | 3 +++ include/uapi/linux/kvm.h | 1 + 3 files changed, 22 insertions(+) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 7fcb2fd38f42..9977e845633f 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6362,6 +6362,24 @@ default. See Documentation/x86/sgx/2.Kernel-internals.rst for more details. +7.26 KVM_CAP_PPC_RPT_INVALIDATE +------------------------------- + +:Capability: KVM_CAP_PPC_RPT_INVALIDATE +:Architectures: ppc +:Type: vm + +This capability indicates that the kernel is capable of handling +H_RPT_INVALIDATE hcall. + +In order to enable the use of H_RPT_INVALIDATE in the guest, +user space might have to advertise it for the guest. For example, +IBM pSeries (sPAPR) guest starts using it if "hcall-rpt-invalidate" is +present in the "ibm,hypertas-functions" device-tree property. + +This capability is enabled for hypervisors on platforms like POWER9 +that support radix MMU. + 8. Other capabilities. ====================== diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index a2a68a958fa0..be33b5321a76 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -682,6 +682,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = !!(hv_enabled && kvmppc_hv_ops->enable_dawr1 && !kvmppc_hv_ops->enable_dawr1(NULL)); break; + case KVM_CAP_PPC_RPT_INVALIDATE: + r = 1; + break; #endif default: r = 0; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 3fd9a7e9d90c..613198a94c43 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1082,6 +1082,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_SGX_ATTRIBUTE 196 #define KVM_CAP_VM_COPY_ENC_CONTEXT_FROM 197 #define KVM_CAP_PTP_KVM 198 +#define KVM_CAP_PPC_RPT_INVALIDATE 199 #ifdef KVM_CAP_IRQ_ROUTING -- cgit v1.3.1 From db3a34e17433de2390eb80d436970edcebd0ca3e Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 27 May 2021 12:01:19 -0700 Subject: clocksource: Retry clock read if long delays detected When the clocksource watchdog marks a clock as unstable, this might be due to that clock being unstable or it might be due to delays that happen to occur between the reads of the two clocks. Yes, interrupts are disabled across those two reads, but there are no shortage of things that can delay interrupts-disabled regions of code ranging from SMI handlers to vCPU preemption. It would be good to have some indication as to why the clock was marked unstable. Therefore, re-read the watchdog clock on either side of the read from the clock under test. If the watchdog clock shows an excessive time delta between its pair of reads, the reads are retried. The maximum number of retries is specified by a new kernel boot parameter clocksource.max_cswd_read_retries, which defaults to three, that is, up to four reads, one initial and up to three retries. If more than one retry was required, a message is printed on the console (the occasional single retry is expected behavior, especially in guest OSes). If the maximum number of retries is exceeded, the clock under test will be marked unstable. However, the probability of this happening due to various sorts of delays is quite small. In addition, the reason (clock-read delays) for the unstable marking will be apparent. Reported-by: Chris Mason Signed-off-by: Paul E. McKenney Signed-off-by: Thomas Gleixner Acked-by: Feng Tang Link: https://lore.kernel.org/r/20210527190124.440372-1-paulmck@kernel.org --- Documentation/admin-guide/kernel-parameters.txt | 6 +++ kernel/time/clocksource.c | 53 ++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index cb89dbdedc46..995deccc28bc 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -581,6 +581,12 @@ loops can be debugged more effectively on production systems. + clocksource.max_cswd_read_retries= [KNL] + Number of clocksource_watchdog() retries due to + external delays before the clock will be marked + unstable. Defaults to three retries, that is, + four attempts to read the clock under test. + clearcpuid=BITNUM[,BITNUM...] [X86] Disable CPUID feature X for the kernel. See arch/x86/include/asm/cpufeatures.h for the valid bit diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 2cd902592fc1..43243f2be98e 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -124,6 +124,13 @@ static void __clocksource_change_rating(struct clocksource *cs, int rating); #define WATCHDOG_INTERVAL (HZ >> 1) #define WATCHDOG_THRESHOLD (NSEC_PER_SEC >> 4) +/* + * Maximum permissible delay between two readouts of the watchdog + * clocksource surrounding a read of the clocksource being validated. + * This delay could be due to SMIs, NMIs, or to VCPU preemptions. + */ +#define WATCHDOG_MAX_SKEW (100 * NSEC_PER_USEC) + static void clocksource_watchdog_work(struct work_struct *work) { /* @@ -184,12 +191,45 @@ void clocksource_mark_unstable(struct clocksource *cs) spin_unlock_irqrestore(&watchdog_lock, flags); } +static ulong max_cswd_read_retries = 3; +module_param(max_cswd_read_retries, ulong, 0644); + +static bool cs_watchdog_read(struct clocksource *cs, u64 *csnow, u64 *wdnow) +{ + unsigned int nretries; + u64 wd_end, wd_delta; + int64_t wd_delay; + + for (nretries = 0; nretries <= max_cswd_read_retries; nretries++) { + local_irq_disable(); + *wdnow = watchdog->read(watchdog); + *csnow = cs->read(cs); + wd_end = watchdog->read(watchdog); + local_irq_enable(); + + wd_delta = clocksource_delta(wd_end, *wdnow, watchdog->mask); + wd_delay = clocksource_cyc2ns(wd_delta, watchdog->mult, + watchdog->shift); + if (wd_delay <= WATCHDOG_MAX_SKEW) { + if (nretries > 1 || nretries >= max_cswd_read_retries) { + pr_warn("timekeeping watchdog on CPU%d: %s retried %d times before success\n", + smp_processor_id(), watchdog->name, nretries); + } + return true; + } + } + + pr_warn("timekeeping watchdog on CPU%d: %s read-back delay of %lldns, attempt %d, marking unstable\n", + smp_processor_id(), watchdog->name, wd_delay, nretries); + return false; +} + static void clocksource_watchdog(struct timer_list *unused) { - struct clocksource *cs; u64 csnow, wdnow, cslast, wdlast, delta; - int64_t wd_nsec, cs_nsec; int next_cpu, reset_pending; + int64_t wd_nsec, cs_nsec; + struct clocksource *cs; spin_lock(&watchdog_lock); if (!watchdog_running) @@ -206,10 +246,11 @@ static void clocksource_watchdog(struct timer_list *unused) continue; } - local_irq_disable(); - csnow = cs->read(cs); - wdnow = watchdog->read(watchdog); - local_irq_enable(); + if (!cs_watchdog_read(cs, &csnow, &wdnow)) { + /* Clock readout unreliable, so give it up. */ + __clocksource_unstable(cs); + continue; + } /* Clocksource initialized ? */ if (!(cs->flags & CLOCK_SOURCE_WATCHDOG) || -- cgit v1.3.1 From fa218f1cce6ba40069c8daab8821de7e6be1cdd0 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 27 May 2021 12:01:21 -0700 Subject: clocksource: Limit number of CPUs checked for clock synchronization Currently, if skew is detected on a clock marked CLOCK_SOURCE_VERIFY_PERCPU, that clock is checked on all CPUs. This is thorough, but might not be what you want on a system with a few tens of CPUs, let alone a few hundred of them. Therefore, by default check only up to eight randomly chosen CPUs. Also provide a new clocksource.verify_n_cpus kernel boot parameter. A value of -1 says to check all of the CPUs, and a non-negative value says to randomly select that number of CPUs, without concern about selecting the same CPU multiple times. However, make use of a cpumask so that a given CPU will be checked at most once. Suggested-by: Thomas Gleixner # For verify_n_cpus=1. Signed-off-by: Paul E. McKenney Signed-off-by: Thomas Gleixner Acked-by: Feng Tang Link: https://lore.kernel.org/r/20210527190124.440372-3-paulmck@kernel.org --- Documentation/admin-guide/kernel-parameters.txt | 10 ++++ kernel/time/clocksource.c | 74 ++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 995deccc28bc..9ec9ea1a51f2 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -587,6 +587,16 @@ unstable. Defaults to three retries, that is, four attempts to read the clock under test. + clocksource.verify_n_cpus= [KNL] + Limit the number of CPUs checked for clocksources + marked with CLOCK_SOURCE_VERIFY_PERCPU that + are marked unstable due to excessive skew. + A negative value says to check all CPUs, while + zero says not to check any. Values larger than + nr_cpu_ids are silently truncated to nr_cpu_ids. + The actual CPUs are chosen randomly, with + no replacement if the same CPU is chosen twice. + clearcpuid=BITNUM[,BITNUM...] [X86] Disable CPUID feature X for the kernel. See arch/x86/include/asm/cpufeatures.h for the valid bit diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index cb12225bf050..e4beab21a1fa 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -14,6 +14,8 @@ #include /* for spin_unlock_irq() using preempt_count() m68k */ #include #include +#include +#include #include "tick-internal.h" #include "timekeeping_internal.h" @@ -193,6 +195,8 @@ void clocksource_mark_unstable(struct clocksource *cs) static ulong max_cswd_read_retries = 3; module_param(max_cswd_read_retries, ulong, 0644); +static int verify_n_cpus = 8; +module_param(verify_n_cpus, int, 0644); static bool cs_watchdog_read(struct clocksource *cs, u64 *csnow, u64 *wdnow) { @@ -227,6 +231,55 @@ static bool cs_watchdog_read(struct clocksource *cs, u64 *csnow, u64 *wdnow) static u64 csnow_mid; static cpumask_t cpus_ahead; static cpumask_t cpus_behind; +static cpumask_t cpus_chosen; + +static void clocksource_verify_choose_cpus(void) +{ + int cpu, i, n = verify_n_cpus; + + if (n < 0) { + /* Check all of the CPUs. */ + cpumask_copy(&cpus_chosen, cpu_online_mask); + cpumask_clear_cpu(smp_processor_id(), &cpus_chosen); + return; + } + + /* If no checking desired, or no other CPU to check, leave. */ + cpumask_clear(&cpus_chosen); + if (n == 0 || num_online_cpus() <= 1) + return; + + /* Make sure to select at least one CPU other than the current CPU. */ + cpu = cpumask_next(-1, cpu_online_mask); + if (cpu == smp_processor_id()) + cpu = cpumask_next(cpu, cpu_online_mask); + if (WARN_ON_ONCE(cpu >= nr_cpu_ids)) + return; + cpumask_set_cpu(cpu, &cpus_chosen); + + /* Force a sane value for the boot parameter. */ + if (n > nr_cpu_ids) + n = nr_cpu_ids; + + /* + * Randomly select the specified number of CPUs. If the same + * CPU is selected multiple times, that CPU is checked only once, + * and no replacement CPU is selected. This gracefully handles + * situations where verify_n_cpus is greater than the number of + * CPUs that are currently online. + */ + for (i = 1; i < n; i++) { + cpu = prandom_u32() % nr_cpu_ids; + cpu = cpumask_next(cpu - 1, cpu_online_mask); + if (cpu >= nr_cpu_ids) + cpu = cpumask_next(-1, cpu_online_mask); + if (!WARN_ON_ONCE(cpu >= nr_cpu_ids)) + cpumask_set_cpu(cpu, &cpus_chosen); + } + + /* Don't verify ourselves. */ + cpumask_clear_cpu(smp_processor_id(), &cpus_chosen); +} static void clocksource_verify_one_cpu(void *csin) { @@ -242,12 +295,22 @@ static void clocksource_verify_percpu(struct clocksource *cs) int cpu, testcpu; s64 delta; + if (verify_n_cpus == 0) + return; cpumask_clear(&cpus_ahead); cpumask_clear(&cpus_behind); + get_online_cpus(); preempt_disable(); + clocksource_verify_choose_cpus(); + if (cpumask_weight(&cpus_chosen) == 0) { + preempt_enable(); + put_online_cpus(); + pr_warn("Not enough CPUs to check clocksource '%s'.\n", cs->name); + return; + } testcpu = smp_processor_id(); - pr_warn("Checking clocksource %s synchronization from CPU %d.\n", cs->name, testcpu); - for_each_online_cpu(cpu) { + pr_warn("Checking clocksource %s synchronization from CPU %d to CPUs %*pbl.\n", cs->name, testcpu, cpumask_pr_args(&cpus_chosen)); + for_each_cpu(cpu, &cpus_chosen) { if (cpu == testcpu) continue; csnow_begin = cs->read(cs); @@ -267,6 +330,7 @@ static void clocksource_verify_percpu(struct clocksource *cs) cs_nsec_min = cs_nsec; } preempt_enable(); + put_online_cpus(); if (!cpumask_empty(&cpus_ahead)) pr_warn(" CPUs %*pbl ahead of CPU %d for clocksource %s.\n", cpumask_pr_args(&cpus_ahead), testcpu, cs->name); @@ -337,6 +401,12 @@ static void clocksource_watchdog(struct timer_list *unused) watchdog->name, wdnow, wdlast, watchdog->mask); pr_warn(" '%s' cs_now: %llx cs_last: %llx mask: %llx\n", cs->name, csnow, cslast, cs->mask); + if (curr_clocksource == cs) + pr_warn(" '%s' is current clocksource.\n", cs->name); + else if (curr_clocksource) + pr_warn(" '%s' (not '%s') is current clocksource.\n", curr_clocksource->name, cs->name); + else + pr_warn(" No current clocksource.\n"); __clocksource_unstable(cs); continue; } -- cgit v1.3.1 From 1253b9b87e42ab6a3d5c2cb27af2bdd67d7e50ff Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 27 May 2021 12:01:23 -0700 Subject: clocksource: Provide kernel module to test clocksource watchdog When the clocksource watchdog marks a clock as unstable, this might be due to that clock being unstable or it might be due to delays that happen to occur between the reads of the two clocks. It would be good to have a way of testing the clocksource watchdog's ability to distinguish between these two causes of clock skew and instability. Therefore, provide a new clocksource-wdtest module selected by a new TEST_CLOCKSOURCE_WATCHDOG Kconfig option. This module has a single module parameter named "holdoff" that provides the number of seconds of delay before testing should start, which defaults to zero when built as a module and to 10 seconds when built directly into the kernel. Very large systems that boot slowly may need to increase the value of this module parameter. This module uses hand-crafted clocksource structures to do its testing, thus avoiding messing up timing for the rest of the kernel and for user applications. This module first verifies that the ->uncertainty_margin field of the clocksource structures are set sanely. It then tests the delay-detection capability of the clocksource watchdog, increasing the number of consecutive delays injected, first provoking console messages complaining about the delays and finally forcing a clock-skew event. Unexpected test results cause at least one WARN_ON_ONCE() console splat. If there are no splats, the test has passed. Finally, it fuzzes the value returned from a clocksource to test the clocksource watchdog's ability to detect time skew. This module checks the state of its clocksource after each test, and uses WARN_ON_ONCE() to emit a console splat if there are any failures. This should enable all types of test frameworks to detect any such failures. This facility is intended for diagnostic use only, and should be avoided on production systems. Reported-by: Chris Mason Suggested-by: Thomas Gleixner Signed-off-by: Paul E. McKenney Signed-off-by: Thomas Gleixner Tested-by: Feng Tang Link: https://lore.kernel.org/r/20210527190124.440372-5-paulmck@kernel.org --- Documentation/admin-guide/kernel-parameters.txt | 6 + include/linux/clocksource.h | 3 + kernel/time/Makefile | 1 + kernel/time/clocksource-wdtest.c | 202 ++++++++++++++++++++++++ kernel/time/clocksource.c | 6 +- lib/Kconfig.debug | 12 ++ 6 files changed, 228 insertions(+), 2 deletions(-) create mode 100644 kernel/time/clocksource-wdtest.c (limited to 'Documentation') diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 9ec9ea1a51f2..591048ed1365 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -597,6 +597,12 @@ The actual CPUs are chosen randomly, with no replacement if the same CPU is chosen twice. + clocksource-wdtest.holdoff= [KNL] + Set the time in seconds that the clocksource + watchdog test waits before commencing its tests. + Defaults to zero when built as a module and to + 10 seconds when built into the kernel. + clearcpuid=BITNUM[,BITNUM...] [X86] Disable CPUID feature X for the kernel. See arch/x86/include/asm/cpufeatures.h for the valid bit diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 895203727cb5..1d42d4b17327 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -291,4 +291,7 @@ static inline void timer_probe(void) {} #define TIMER_ACPI_DECLARE(name, table_id, fn) \ ACPI_DECLARE_PROBE_ENTRY(timer, name, table_id, 0, NULL, 0, fn) +extern ulong max_cswd_read_retries; +void clocksource_verify_percpu(struct clocksource *cs); + #endif /* _LINUX_CLOCKSOURCE_H */ diff --git a/kernel/time/Makefile b/kernel/time/Makefile index 1fb1c1ef6a19..1ed85b25b096 100644 --- a/kernel/time/Makefile +++ b/kernel/time/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_HAVE_GENERIC_VDSO) += vsyscall.o obj-$(CONFIG_DEBUG_FS) += timekeeping_debug.o obj-$(CONFIG_TEST_UDELAY) += test_udelay.o obj-$(CONFIG_TIME_NS) += namespace.o +obj-$(CONFIG_TEST_CLOCKSOURCE_WATCHDOG) += clocksource-wdtest.o diff --git a/kernel/time/clocksource-wdtest.c b/kernel/time/clocksource-wdtest.c new file mode 100644 index 000000000000..01df12395c0e --- /dev/null +++ b/kernel/time/clocksource-wdtest.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Unit test for the clocksource watchdog. + * + * Copyright (C) 2021 Facebook, Inc. + * + * Author: Paul E. McKenney + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include /* for spin_unlock_irq() using preempt_count() m68k */ +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Paul E. McKenney "); + +static int holdoff = IS_BUILTIN(CONFIG_TEST_CLOCKSOURCE_WATCHDOG) ? 10 : 0; +module_param(holdoff, int, 0444); +MODULE_PARM_DESC(holdoff, "Time to wait to start test (s)."); + +/* Watchdog kthread's task_struct pointer for debug purposes. */ +static struct task_struct *wdtest_task; + +static u64 wdtest_jiffies_read(struct clocksource *cs) +{ + return (u64)jiffies; +} + +/* Assume HZ > 100. */ +#define JIFFIES_SHIFT 8 + +static struct clocksource clocksource_wdtest_jiffies = { + .name = "wdtest-jiffies", + .rating = 1, /* lowest valid rating*/ + .uncertainty_margin = TICK_NSEC, + .read = wdtest_jiffies_read, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_MUST_VERIFY, + .mult = TICK_NSEC << JIFFIES_SHIFT, /* details above */ + .shift = JIFFIES_SHIFT, + .max_cycles = 10, +}; + +static int wdtest_ktime_read_ndelays; +static bool wdtest_ktime_read_fuzz; + +static u64 wdtest_ktime_read(struct clocksource *cs) +{ + int wkrn = READ_ONCE(wdtest_ktime_read_ndelays); + static int sign = 1; + u64 ret; + + if (wkrn) { + udelay(cs->uncertainty_margin / 250); + WRITE_ONCE(wdtest_ktime_read_ndelays, wkrn - 1); + } + ret = ktime_get_real_fast_ns(); + if (READ_ONCE(wdtest_ktime_read_fuzz)) { + sign = -sign; + ret = ret + sign * 100 * NSEC_PER_MSEC; + } + return ret; +} + +static void wdtest_ktime_cs_mark_unstable(struct clocksource *cs) +{ + pr_info("--- Marking %s unstable due to clocksource watchdog.\n", cs->name); +} + +#define KTIME_FLAGS (CLOCK_SOURCE_IS_CONTINUOUS | \ + CLOCK_SOURCE_VALID_FOR_HRES | \ + CLOCK_SOURCE_MUST_VERIFY | \ + CLOCK_SOURCE_VERIFY_PERCPU) + +static struct clocksource clocksource_wdtest_ktime = { + .name = "wdtest-ktime", + .rating = 300, + .read = wdtest_ktime_read, + .mask = CLOCKSOURCE_MASK(64), + .flags = KTIME_FLAGS, + .mark_unstable = wdtest_ktime_cs_mark_unstable, + .list = LIST_HEAD_INIT(clocksource_wdtest_ktime.list), +}; + +/* Reset the clocksource if needed. */ +static void wdtest_ktime_clocksource_reset(void) +{ + if (clocksource_wdtest_ktime.flags & CLOCK_SOURCE_UNSTABLE) { + clocksource_unregister(&clocksource_wdtest_ktime); + clocksource_wdtest_ktime.flags = KTIME_FLAGS; + schedule_timeout_uninterruptible(HZ / 10); + clocksource_register_khz(&clocksource_wdtest_ktime, 1000 * 1000); + } +} + +/* Run the specified series of watchdog tests. */ +static int wdtest_func(void *arg) +{ + unsigned long j1, j2; + char *s; + int i; + + schedule_timeout_uninterruptible(holdoff * HZ); + + /* + * Verify that jiffies-like clocksources get the manually + * specified uncertainty margin. + */ + pr_info("--- Verify jiffies-like uncertainty margin.\n"); + __clocksource_register(&clocksource_wdtest_jiffies); + WARN_ON_ONCE(clocksource_wdtest_jiffies.uncertainty_margin != TICK_NSEC); + + j1 = clocksource_wdtest_jiffies.read(&clocksource_wdtest_jiffies); + schedule_timeout_uninterruptible(HZ); + j2 = clocksource_wdtest_jiffies.read(&clocksource_wdtest_jiffies); + WARN_ON_ONCE(j1 == j2); + + clocksource_unregister(&clocksource_wdtest_jiffies); + + /* + * Verify that tsc-like clocksources are assigned a reasonable + * uncertainty margin. + */ + pr_info("--- Verify tsc-like uncertainty margin.\n"); + clocksource_register_khz(&clocksource_wdtest_ktime, 1000 * 1000); + WARN_ON_ONCE(clocksource_wdtest_ktime.uncertainty_margin < NSEC_PER_USEC); + + j1 = clocksource_wdtest_ktime.read(&clocksource_wdtest_ktime); + udelay(1); + j2 = clocksource_wdtest_ktime.read(&clocksource_wdtest_ktime); + pr_info("--- tsc-like times: %lu - %lu = %lu.\n", j2, j1, j2 - j1); + WARN_ON_ONCE(time_before(j2, j1 + NSEC_PER_USEC)); + + /* Verify tsc-like stability with various numbers of errors injected. */ + for (i = 0; i <= max_cswd_read_retries + 1; i++) { + if (i <= 1 && i < max_cswd_read_retries) + s = ""; + else if (i <= max_cswd_read_retries) + s = ", expect message"; + else + s = ", expect clock skew"; + pr_info("--- Watchdog with %dx error injection, %lu retries%s.\n", i, max_cswd_read_retries, s); + WRITE_ONCE(wdtest_ktime_read_ndelays, i); + schedule_timeout_uninterruptible(2 * HZ); + WARN_ON_ONCE(READ_ONCE(wdtest_ktime_read_ndelays)); + WARN_ON_ONCE((i <= max_cswd_read_retries) != + !(clocksource_wdtest_ktime.flags & CLOCK_SOURCE_UNSTABLE)); + wdtest_ktime_clocksource_reset(); + } + + /* Verify tsc-like stability with clock-value-fuzz error injection. */ + pr_info("--- Watchdog clock-value-fuzz error injection, expect clock skew and per-CPU mismatches.\n"); + WRITE_ONCE(wdtest_ktime_read_fuzz, true); + schedule_timeout_uninterruptible(2 * HZ); + WARN_ON_ONCE(!(clocksource_wdtest_ktime.flags & CLOCK_SOURCE_UNSTABLE)); + clocksource_verify_percpu(&clocksource_wdtest_ktime); + WRITE_ONCE(wdtest_ktime_read_fuzz, false); + + clocksource_unregister(&clocksource_wdtest_ktime); + + pr_info("--- Done with test.\n"); + return 0; +} + +static void wdtest_print_module_parms(void) +{ + pr_alert("--- holdoff=%d\n", holdoff); +} + +/* Cleanup function. */ +static void clocksource_wdtest_cleanup(void) +{ +} + +static int __init clocksource_wdtest_init(void) +{ + int ret = 0; + + wdtest_print_module_parms(); + + /* Create watchdog-test task. */ + wdtest_task = kthread_run(wdtest_func, NULL, "wdtest"); + if (IS_ERR(wdtest_task)) { + ret = PTR_ERR(wdtest_task); + pr_warn("%s: Failed to create wdtest kthread.\n", __func__); + wdtest_task = NULL; + return ret; + } + + return 0; +} + +module_init(clocksource_wdtest_init); +module_exit(clocksource_wdtest_cleanup); diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 9b27888a6e75..74d6a234fd14 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -199,8 +199,9 @@ void clocksource_mark_unstable(struct clocksource *cs) spin_unlock_irqrestore(&watchdog_lock, flags); } -static ulong max_cswd_read_retries = 3; +ulong max_cswd_read_retries = 3; module_param(max_cswd_read_retries, ulong, 0644); +EXPORT_SYMBOL_GPL(max_cswd_read_retries); static int verify_n_cpus = 8; module_param(verify_n_cpus, int, 0644); @@ -294,7 +295,7 @@ static void clocksource_verify_one_cpu(void *csin) csnow_mid = cs->read(cs); } -static void clocksource_verify_percpu(struct clocksource *cs) +void clocksource_verify_percpu(struct clocksource *cs) { int64_t cs_nsec, cs_nsec_max = 0, cs_nsec_min = LLONG_MAX; u64 csnow_begin, csnow_end; @@ -347,6 +348,7 @@ static void clocksource_verify_percpu(struct clocksource *cs) pr_warn(" CPU %d check durations %lldns - %lldns for clocksource %s.\n", testcpu, cs_nsec_min, cs_nsec_max, cs->name); } +EXPORT_SYMBOL_GPL(clocksource_verify_percpu); static void clocksource_watchdog(struct timer_list *unused) { diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 678c13967580..0a5a70c742e6 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2571,6 +2571,18 @@ config TEST_FPU If unsure, say N. +config TEST_CLOCKSOURCE_WATCHDOG + tristate "Test clocksource watchdog in kernel space" + depends on CLOCKSOURCE_WATCHDOG + help + Enable this option to create a kernel module that will trigger + a test of the clocksource watchdog. This module may be loaded + via modprobe or insmod in which case it will run upon being + loaded, or it may be built in, in which case it will run + shortly after boot. + + If unsure, say N. + endif # RUNTIME_TESTING_MENU config ARCH_USE_MEMTEST -- cgit v1.3.1 From c58c7e9bf55ced301fdd9c8c1841361cc5fc8458 Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Mon, 21 Jun 2021 18:47:55 +0800 Subject: spi: spi-rockchip: add description for rv1126 The description below will be used for rv1126.dtsi or compatible one in the future Signed-off-by: Jon Lin Link: https://lore.kernel.org/r/20210621104800.19088-2-jon.lin@rock-chips.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-rockchip.yaml | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.yaml b/Documentation/devicetree/bindings/spi/spi-rockchip.yaml index 1e6cf29e6388..7f987e79337c 100644 --- a/Documentation/devicetree/bindings/spi/spi-rockchip.yaml +++ b/Documentation/devicetree/bindings/spi/spi-rockchip.yaml @@ -33,6 +33,7 @@ properties: - rockchip,rk3328-spi - rockchip,rk3368-spi - rockchip,rk3399-spi + - rockchip,rv1126-spi - const: rockchip,rk3066-spi reg: -- cgit v1.3.1 From adf3c31e18b765ea24eba7b0c1efc076b8ee3d55 Mon Sep 17 00:00:00 2001 From: Beata Michalska Date: Thu, 3 Jun 2021 15:06:27 +0100 Subject: sched/doc: Update the CPU capacity asymmetry bits Update the documentation bits referring to capacity aware scheduling with regards to newly introduced SD_ASYM_CPUCAPACITY_FULL sched_domain flag. Signed-off-by: Beata Michalska Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Valentin Schneider Reviewed-by: Dietmar Eggemann Link: https://lore.kernel.org/r/20210603140627.8409-4-beata.michalska@arm.com --- Documentation/scheduler/sched-capacity.rst | 6 ++++-- Documentation/scheduler/sched-energy.rst | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/scheduler/sched-capacity.rst b/Documentation/scheduler/sched-capacity.rst index 9b7cbe43b2d1..805f85f330b5 100644 --- a/Documentation/scheduler/sched-capacity.rst +++ b/Documentation/scheduler/sched-capacity.rst @@ -284,8 +284,10 @@ whether the system exhibits asymmetric CPU capacities. Should that be the case: - The sched_asym_cpucapacity static key will be enabled. -- The SD_ASYM_CPUCAPACITY flag will be set at the lowest sched_domain level that - spans all unique CPU capacity values. +- The SD_ASYM_CPUCAPACITY_FULL flag will be set at the lowest sched_domain + level that spans all unique CPU capacity values. +- The SD_ASYM_CPUCAPACITY flag will be set for any sched_domain that spans + CPUs with any range of asymmetry. The sched_asym_cpucapacity static key is intended to guard sections of code that cater to asymmetric CPU capacity systems. Do note however that said key is diff --git a/Documentation/scheduler/sched-energy.rst b/Documentation/scheduler/sched-energy.rst index afe02d394402..8fbce5e767d9 100644 --- a/Documentation/scheduler/sched-energy.rst +++ b/Documentation/scheduler/sched-energy.rst @@ -328,7 +328,7 @@ section lists these dependencies and provides hints as to how they can be met. As mentioned in the introduction, EAS is only supported on platforms with asymmetric CPU topologies for now. This requirement is checked at run-time by -looking for the presence of the SD_ASYM_CPUCAPACITY flag when the scheduling +looking for the presence of the SD_ASYM_CPUCAPACITY_FULL flag when the scheduling domains are built. See Documentation/scheduler/sched-capacity.rst for requirements to be met for this -- cgit v1.3.1 From fdc09ddd40645b0e3f245e4512fd4b4c34cde5e5 Mon Sep 17 00:00:00 2001 From: Jing Zhang Date: Fri, 18 Jun 2021 22:27:07 +0000 Subject: KVM: stats: Add documentation for binary statistics interface This new API provides a file descriptor for every VM and VCPU to read KVM statistics data in binary format. It is meant to provide a lightweight, flexible, scalable and efficient lock-free solution for user space telemetry applications to pull the statistics data periodically for large scale systems. The pulling frequency could be as high as a few times per second. The statistics descriptors are defined by KVM in kernel and can be by userspace to discover VM/VCPU statistics during the one-time setup stage. The statistics data itself could be read out by userspace telemetry periodically without any extra parsing or setup effort. There are a few existed interface protocols and definitions, but no one can fulfil all the requirements this interface implemented as below: 1. During high frequency periodic stats reading, there should be no extra efforts except the stats data read itself. 2. Support stats annotation, like type (cumulative, instantaneous, peak, histogram, etc) and unit (counter, time, size, cycles, etc). 3. The stats data reading should be free of lock/synchronization. We don't care about the consistency between all the stats data. All stats data can not be read out at exactly the same time. We really care about the change or trend of the stats data. The lock-free solution is not just for efficiency and scalability, also for the stats data accuracy and usability. For example, in the situation that all the stats data readings are protected by a global lock, if one VCPU died somehow with that lock held, then all stats data reading would be blocked, then we have no way from stats data that which VCPU has died. 4. The stats data reading workload can be handed over to other unprivileged process. Reviewed-by: David Matlack Reviewed-by: Ricardo Koller Reviewed-by: Krish Sadhukhan Reviewed-by: Fuad Tabba Signed-off-by: Jing Zhang Message-Id: <20210618222709.1858088-6-jingzhangos@google.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 170 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index dd3fe231e435..b87fa32835f2 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -5081,6 +5081,176 @@ Writes special registers into the vcpu. See KVM_GET_SREGS2 for the data structures. This ioctl (when supported) replaces the KVM_SET_SREGS. +4.133 KVM_GET_STATS_FD +---------------------- + +:Capability: KVM_CAP_STATS_BINARY_FD +:Architectures: all +:Type: vm ioctl, vcpu ioctl +:Parameters: none +:Returns: statistics file descriptor on success, < 0 on error + +Errors: + + ====== ====================================================== + ENOMEM if the fd could not be created due to lack of memory + EMFILE if the number of opened files exceeds the limit + ====== ====================================================== + +The returned file descriptor can be used to read VM/vCPU statistics data in +binary format. The data in the file descriptor consists of four blocks +organized as follows: + ++-------------+ +| Header | ++-------------+ +| id string | ++-------------+ +| Descriptors | ++-------------+ +| Stats Data | ++-------------+ + +Apart from the header starting at offset 0, please be aware that it is +not guaranteed that the four blocks are adjacent or in the above order; +the offsets of the id, descriptors and data blocks are found in the +header. However, all four blocks are aligned to 64 bit offsets in the +file and they do not overlap. + +All blocks except the data block are immutable. Userspace can read them +only one time after retrieving the file descriptor, and then use ``pread`` or +``lseek`` to read the statistics repeatedly. + +All data is in system endianness. + +The format of the header is as follows:: + + struct kvm_stats_header { + __u32 flags; + __u32 name_size; + __u32 num_desc; + __u32 id_offset; + __u32 desc_offset; + __u32 data_offset; + }; + +The ``flags`` field is not used at the moment. It is always read as 0. + +The ``name_size`` field is the size (in byte) of the statistics name string +(including trailing '\0') which is contained in the "id string" block and +appended at the end of every descriptor. + +The ``num_desc`` field is the number of descriptors that are included in the +descriptor block. (The actual number of values in the data block may be +larger, since each descriptor may comprise more than one value). + +The ``id_offset`` field is the offset of the id string from the start of the +file indicated by the file descriptor. It is a multiple of 8. + +The ``desc_offset`` field is the offset of the Descriptors block from the start +of the file indicated by the file descriptor. It is a multiple of 8. + +The ``data_offset`` field is the offset of the Stats Data block from the start +of the file indicated by the file descriptor. It is a multiple of 8. + +The id string block contains a string which identifies the file descriptor on +which KVM_GET_STATS_FD was invoked. The size of the block, including the +trailing ``'\0'``, is indicated by the ``name_size`` field in the header. + +The descriptors block is only needed to be read once for the lifetime of the +file descriptor contains a sequence of ``struct kvm_stats_desc``, each followed +by a string of size ``name_size``. + + #define KVM_STATS_TYPE_SHIFT 0 + #define KVM_STATS_TYPE_MASK (0xF << KVM_STATS_TYPE_SHIFT) + #define KVM_STATS_TYPE_CUMULATIVE (0x0 << KVM_STATS_TYPE_SHIFT) + #define KVM_STATS_TYPE_INSTANT (0x1 << KVM_STATS_TYPE_SHIFT) + #define KVM_STATS_TYPE_PEAK (0x2 << KVM_STATS_TYPE_SHIFT) + + #define KVM_STATS_UNIT_SHIFT 4 + #define KVM_STATS_UNIT_MASK (0xF << KVM_STATS_UNIT_SHIFT) + #define KVM_STATS_UNIT_NONE (0x0 << KVM_STATS_UNIT_SHIFT) + #define KVM_STATS_UNIT_BYTES (0x1 << KVM_STATS_UNIT_SHIFT) + #define KVM_STATS_UNIT_SECONDS (0x2 << KVM_STATS_UNIT_SHIFT) + #define KVM_STATS_UNIT_CYCLES (0x3 << KVM_STATS_UNIT_SHIFT) + + #define KVM_STATS_BASE_SHIFT 8 + #define KVM_STATS_BASE_MASK (0xF << KVM_STATS_BASE_SHIFT) + #define KVM_STATS_BASE_POW10 (0x0 << KVM_STATS_BASE_SHIFT) + #define KVM_STATS_BASE_POW2 (0x1 << KVM_STATS_BASE_SHIFT) + + struct kvm_stats_desc { + __u32 flags; + __s16 exponent; + __u16 size; + __u32 offset; + __u32 unused; + char name[]; + }; + +The ``flags`` field contains the type and unit of the statistics data described +by this descriptor. Its endianness is CPU native. +The following flags are supported: + +Bits 0-3 of ``flags`` encode the type: + * ``KVM_STATS_TYPE_CUMULATIVE`` + The statistics data is cumulative. The value of data can only be increased. + Most of the counters used in KVM are of this type. + The corresponding ``size`` field for this type is always 1. + All cumulative statistics data are read/write. + * ``KVM_STATS_TYPE_INSTANT`` + The statistics data is instantaneous. Its value can be increased or + decreased. This type is usually used as a measurement of some resources, + like the number of dirty pages, the number of large pages, etc. + All instant statistics are read only. + The corresponding ``size`` field for this type is always 1. + * ``KVM_STATS_TYPE_PEAK`` + The statistics data is peak. The value of data can only be increased, and + represents a peak value for a measurement, for example the maximum number + of items in a hash table bucket, the longest time waited and so on. + The corresponding ``size`` field for this type is always 1. + +Bits 4-7 of ``flags`` encode the unit: + * ``KVM_STATS_UNIT_NONE`` + There is no unit for the value of statistics data. This usually means that + the value is a simple counter of an event. + * ``KVM_STATS_UNIT_BYTES`` + It indicates that the statistics data is used to measure memory size, in the + unit of Byte, KiByte, MiByte, GiByte, etc. The unit of the data is + determined by the ``exponent`` field in the descriptor. + * ``KVM_STATS_UNIT_SECONDS`` + It indicates that the statistics data is used to measure time or latency. + * ``KVM_STATS_UNIT_CYCLES`` + It indicates that the statistics data is used to measure CPU clock cycles. + +Bits 8-11 of ``flags``, together with ``exponent``, encode the scale of the +unit: + * ``KVM_STATS_BASE_POW10`` + The scale is based on power of 10. It is used for measurement of time and + CPU clock cycles. For example, an exponent of -9 can be used with + ``KVM_STATS_UNIT_SECONDS`` to express that the unit is nanoseconds. + * ``KVM_STATS_BASE_POW2`` + The scale is based on power of 2. It is used for measurement of memory size. + For example, an exponent of 20 can be used with ``KVM_STATS_UNIT_BYTES`` to + express that the unit is MiB. + +The ``size`` field is the number of values of this statistics data. Its +value is usually 1 for most of simple statistics. 1 means it contains an +unsigned 64bit data. + +The ``offset`` field is the offset from the start of Data Block to the start of +the corresponding statistics data. + +The ``unused`` field is reserved for future support for other types of +statistics data, like log/linear histogram. Its value is always 0 for the types +defined above. + +The ``name`` field is the name string of the statistics data. The name string +starts at the end of ``struct kvm_stats_desc``. The maximum length including +the trailing ``'\0'``, is indicated by ``name_size`` in the header. + +The Stats Data block contains an array of 64-bit values in the same order +as the descriptors in Descriptors block. 5. The kvm_run structure ======================== -- cgit v1.3.1 From 63f5a1909f9e465eb446274969f65471794deafb Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 22 Jun 2021 10:56:52 -0700 Subject: KVM: x86: Alert userspace that KVM_SET_CPUID{,2} after KVM_RUN is broken Warn userspace that KVM_SET_CPUID{,2} after KVM_RUN "may" cause guest instability. Initialize last_vmentry_cpu to -1 and use it to detect if the vCPU has been run at least once when its CPUID model is changed. KVM does not correctly handle changes to paging related settings in the guest's vCPU model after KVM_RUN, e.g. MAXPHYADDR, GBPAGES, etc... KVM could theoretically zap all shadow pages, but actually making that happen is a mess due to lock inversion (vcpu->mutex is held). And even then, updating paging settings on the fly would only work if all vCPUs are stopped, updated in concert with identical settings, then restarted. To support running vCPUs with different vCPU models (that affect paging), KVM would need to track all relevant information in kvm_mmu_page_role. Note, that's the _page_ role, not the full mmu_role. Updating mmu_role isn't sufficient as a vCPU can reuse a shadow page translation that was created by a vCPU with different settings and thus completely skip the reserved bit checks (that are tied to CPUID). Tracking CPUID state in kvm_mmu_page_role is _extremely_ undesirable as it would require doubling gfn_track from a u16 to a u32, i.e. would increase KVM's memory footprint by 2 bytes for every 4kb of guest memory. E.g. MAXPHYADDR (6 bits), GBPAGES, AMD vs. INTEL = 1 bit, and SEV C-BIT would all need to be tracked. In practice, there is no remotely sane use case for changing any paging related CPUID entries on the fly, so just sweep it under the rug (after yelling at userspace). Signed-off-by: Sean Christopherson Message-Id: <20210622175739.3610207-8-seanjc@google.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 11 ++++++++--- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/mmu/mmu.c | 20 ++++++++++++++++++++ arch/x86/kvm/x86.c | 2 ++ 4 files changed, 31 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index b87fa32835f2..5d8db4922df6 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -688,9 +688,14 @@ MSRs that have been set successfully. Defines the vcpu responses to the cpuid instruction. Applications should use the KVM_SET_CPUID2 ioctl if available. -Note, when this IOCTL fails, KVM gives no guarantees that previous valid CPUID -configuration (if there is) is not corrupted. Userspace can get a copy of the -resulting CPUID configuration through KVM_GET_CPUID2 in case. +Caveat emptor: + - If this IOCTL fails, KVM gives no guarantees that previous valid CPUID + configuration (if there is) is not corrupted. Userspace can get a copy + of the resulting CPUID configuration through KVM_GET_CPUID2 in case. + - Using KVM_SET_CPUID{,2} after KVM_RUN, i.e. changing the guest vCPU model + after running the guest, may cause guest instability. + - Using heterogeneous CPUID configurations, modulo APIC IDs, topology, etc... + may cause guest instability. :: diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index f1e4d5f2bf8d..f8faf3efc08d 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -840,7 +840,7 @@ struct kvm_vcpu_arch { bool l1tf_flush_l1d; /* Host CPU on which VM-entry was most recently attempted */ - unsigned int last_vmentry_cpu; + int last_vmentry_cpu; /* AMD MSRC001_0015 Hardware Configuration */ u64 msr_hwcr; diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 1ab3fdb1f2e4..36201c02a472 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -4913,6 +4913,26 @@ void kvm_mmu_after_set_cpuid(struct kvm_vcpu *vcpu) vcpu->arch.guest_mmu.mmu_role.ext.valid = 0; vcpu->arch.nested_mmu.mmu_role.ext.valid = 0; kvm_mmu_reset_context(vcpu); + + /* + * KVM does not correctly handle changing guest CPUID after KVM_RUN, as + * MAXPHYADDR, GBPAGES support, AMD reserved bit behavior, etc.. aren't + * tracked in kvm_mmu_page_role. As a result, KVM may miss guest page + * faults due to reusing SPs/SPTEs. Alert userspace, but otherwise + * sweep the problem under the rug. + * + * KVM's horrific CPUID ABI makes the problem all but impossible to + * solve, as correctly handling multiple vCPU models (with respect to + * paging and physical address properties) in a single VM would require + * tracking all relevant CPUID information in kvm_mmu_page_role. That + * is very undesirable as it would double the memory requirements for + * gfn_track (see struct kvm_mmu_page_role comments), and in practice + * no sane VMM mucks with the core vCPU model on the fly. + */ + if (vcpu->arch.last_vmentry_cpu != -1) { + pr_warn_ratelimited("KVM: KVM_SET_CPUID{,2} after KVM_RUN may cause guest instability\n"); + pr_warn_ratelimited("KVM: KVM_SET_CPUID{,2} will fail after KVM_RUN starting with Linux 5.16\n"); + } } void kvm_mmu_reset_context(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 4bd10fb1dfd6..c862783035b8 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -10602,6 +10602,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) struct page *page; int r; + vcpu->arch.last_vmentry_cpu = -1; + if (!irqchip_in_kernel(vcpu->kvm) || kvm_vcpu_is_reset_bsp(vcpu)) vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; else -- cgit v1.3.1 From 00a669780ffa8c4b5f3e37346b5bf45508dd15bb Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 22 Jun 2021 10:56:55 -0700 Subject: KVM: x86/mmu: Use MMU role to check for matching guest page sizes Originally, __kvm_sync_page used to check the cr4_pae bit in the role to avoid zapping 4-byte kvm_mmu_pages when guest page size are 8-byte or the other way round. However, in commit 47c42e6b4192 ("KVM: x86: fix handling of role.cr4_pae and rename it to 'gpte_size'", 2019-03-28) it was observed that this did not work for nested EPT, where the page table size would be 8 bytes even if CR4.PAE=0. (Note that the check still has to be done for nested *NPT*, so it is not possible to use tdp_enabled or similar). Therefore, a hack was introduced to identify nested EPT shadow pages and unconditionally call __kvm_sync_page() on them. However, it is possible to do without the hack to identify nested EPT shadow pages: if EPT is active, there will be no shadow pages in non-EPT format, and all of them will have gpte_is_8_bytes set to true; we can just check the MMU role directly, and the test will always be true. Even for non-EPT shadow MMUs, this test should really always be true now that __kvm_sync_page() is called if and only if the role is an exact match (kvm_mmu_get_page()) or is part of the current MMU context (kvm_mmu_sync_roots()). A future commit will convert the likely-pointless check into a meaningful WARN to enforce that the mmu_roles of the current context and the shadow page are compatible. Cc: Vitaly Kuznetsov Signed-off-by: Sean Christopherson Message-Id: <20210622175739.3610207-11-seanjc@google.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/mmu.rst | 3 --- arch/x86/kvm/mmu/mmu.c | 16 +++------------- 2 files changed, 3 insertions(+), 16 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/mmu.rst b/Documentation/virt/kvm/mmu.rst index 20d85daed395..ddbb23998742 100644 --- a/Documentation/virt/kvm/mmu.rst +++ b/Documentation/virt/kvm/mmu.rst @@ -192,9 +192,6 @@ Shadow pages contain the following information: Contains the value of cr4.smap && !cr0.wp for which the page is valid (pages for which this is true are different from other pages; see the treatment of cr0.wp=0 below). - role.ept_sp: - This is a virtual flag to denote a shadowed nested EPT page. ept_sp - is true if "cr0_wp && smap_andnot_wp", an otherwise invalid combination. role.smm: Is 1 if the page is valid in system management mode. This field determines which of the kvm_memslots array was used to build this diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 4af466f0ec6d..71a2ee755224 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -1780,16 +1780,13 @@ static void kvm_mmu_commit_zap_page(struct kvm *kvm, &(_kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(_gfn)]) \ if ((_sp)->gfn != (_gfn) || (_sp)->role.direct) {} else -static inline bool is_ept_sp(struct kvm_mmu_page *sp) -{ - return sp->role.cr0_wp && sp->role.smap_andnot_wp; -} - /* @sp->gfn should be write-protected at the call site */ static bool __kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, struct list_head *invalid_list) { - if ((!is_ept_sp(sp) && sp->role.gpte_is_8_bytes != !!is_pae(vcpu)) || + union kvm_mmu_page_role mmu_role = vcpu->arch.mmu->mmu_role.base; + + if (sp->role.gpte_is_8_bytes != mmu_role.gpte_is_8_bytes || vcpu->arch.mmu->sync_page(vcpu, sp) == 0) { kvm_mmu_prepare_zap_page(vcpu->kvm, sp, invalid_list); return false; @@ -4721,13 +4718,6 @@ kvm_calc_shadow_ept_root_page_role(struct kvm_vcpu *vcpu, bool accessed_dirty, role.base.guest_mode = true; role.base.access = ACC_ALL; - /* - * WP=1 and NOT_WP=1 is an impossible combination, use WP and the - * SMAP variation to denote shadow EPT entries. - */ - role.base.cr0_wp = true; - role.base.smap_andnot_wp = true; - role.ext = kvm_calc_mmu_role_ext(vcpu); role.ext.execonly = execonly; -- cgit v1.3.1 From 167f8a5cae99fb2050d3d674ca84457a526e23dd Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 22 Jun 2021 10:57:09 -0700 Subject: KVM: x86/mmu: Rename "nxe" role bit to "efer_nx" for macro shenanigans Rename "nxe" to "efer_nx" so that future macro magic can use the pattern _ for all CR0, CR4, and EFER bits that included in the role. Using "efer_nx" also makes it clear that the role bit reflects EFER.NX, not the NX bit in the corresponding PTE. Signed-off-by: Sean Christopherson Message-Id: <20210622175739.3610207-25-seanjc@google.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/mmu.rst | 4 ++-- arch/x86/include/asm/kvm_host.h | 4 ++-- arch/x86/kvm/mmu/mmu.c | 2 +- arch/x86/kvm/mmu/mmutrace.h | 2 +- tools/lib/traceevent/plugins/plugin_kvm.c | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/mmu.rst b/Documentation/virt/kvm/mmu.rst index ddbb23998742..f60f5488e121 100644 --- a/Documentation/virt/kvm/mmu.rst +++ b/Documentation/virt/kvm/mmu.rst @@ -180,8 +180,8 @@ Shadow pages contain the following information: role.gpte_is_8_bytes: Reflects the size of the guest PTE for which the page is valid, i.e. '1' if 64-bit gptes are in use, '0' if 32-bit gptes are in use. - role.nxe: - Contains the value of efer.nxe for which the page is valid. + role.efer_nx: + Contains the value of efer.nx for which the page is valid. role.cr0_wp: Contains the value of cr0.wp for which the page is valid. role.smep_andnot_wp: diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 250915da1681..520140eed423 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -274,7 +274,7 @@ struct kvm_kernel_irq_routing_entry; * by indirect shadow page can not be more than 15 bits. * * Currently, we used 14 bits that are @level, @gpte_is_8_bytes, @quadrant, @access, - * @nxe, @cr0_wp, @smep_andnot_wp and @smap_andnot_wp. + * @efer_nx, @cr0_wp, @smep_andnot_wp and @smap_andnot_wp. */ union kvm_mmu_page_role { u32 word; @@ -285,7 +285,7 @@ union kvm_mmu_page_role { unsigned direct:1; unsigned access:3; unsigned invalid:1; - unsigned nxe:1; + unsigned efer_nx:1; unsigned cr0_wp:1; unsigned smep_andnot_wp:1; unsigned smap_andnot_wp:1; diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 81992ba2899f..25f23de89cdf 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -4567,7 +4567,7 @@ static union kvm_mmu_role kvm_calc_mmu_role_common(struct kvm_vcpu *vcpu, union kvm_mmu_role role = {0}; role.base.access = ACC_ALL; - role.base.nxe = ____is_efer_nx(regs); + role.base.efer_nx = ____is_efer_nx(regs); role.base.cr0_wp = ____is_cr0_wp(regs); role.base.smm = is_smm(vcpu); role.base.guest_mode = is_guest_mode(vcpu); diff --git a/arch/x86/kvm/mmu/mmutrace.h b/arch/x86/kvm/mmu/mmutrace.h index e798489b56b5..efbad33a0645 100644 --- a/arch/x86/kvm/mmu/mmutrace.h +++ b/arch/x86/kvm/mmu/mmutrace.h @@ -40,7 +40,7 @@ role.direct ? " direct" : "", \ access_str[role.access], \ role.invalid ? " invalid" : "", \ - role.nxe ? "" : "!", \ + role.efer_nx ? "" : "!", \ role.ad_disabled ? "!" : "", \ __entry->root_count, \ __entry->unsync ? "unsync" : "sync", 0); \ diff --git a/tools/lib/traceevent/plugins/plugin_kvm.c b/tools/lib/traceevent/plugins/plugin_kvm.c index 51ceeb9147eb..9ce7b4b68e3f 100644 --- a/tools/lib/traceevent/plugins/plugin_kvm.c +++ b/tools/lib/traceevent/plugins/plugin_kvm.c @@ -366,7 +366,7 @@ union kvm_mmu_page_role { unsigned direct:1; unsigned access:3; unsigned invalid:1; - unsigned nxe:1; + unsigned efer_nx:1; unsigned cr0_wp:1; unsigned smep_and_not_wp:1; unsigned smap_and_not_wp:1; @@ -403,7 +403,7 @@ static int kvm_mmu_print_role(struct trace_seq *s, struct tep_record *record, access_str[role.access], role.invalid ? " invalid" : "", role.cr4_pae ? "" : "!", - role.nxe ? "" : "!", + role.efer_nx ? "" : "!", role.cr0_wp ? "" : "!", role.smep_and_not_wp ? " smep" : "", role.smap_and_not_wp ? " smap" : "", -- cgit v1.3.1 From 19238e75bd8ed8ffe784bf5b37586e77b2093742 Mon Sep 17 00:00:00 2001 From: Aaron Lewis Date: Mon, 10 May 2021 07:48:33 -0700 Subject: kvm: x86: Allow userspace to handle emulation errors Add a fallback mechanism to the in-kernel instruction emulator that allows userspace the opportunity to process an instruction the emulator was unable to. When the in-kernel instruction emulator fails to process an instruction it will either inject a #UD into the guest or exit to userspace with exit reason KVM_INTERNAL_ERROR. This is because it does not know how to proceed in an appropriate manner. This feature lets userspace get involved to see if it can figure out a better path forward. Signed-off-by: Aaron Lewis Reviewed-by: David Edmondson Message-Id: <20210510144834.658457-2-aaronlewis@google.com> Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 20 ++++++++++++++++++++ arch/x86/include/asm/kvm_host.h | 6 ++++++ arch/x86/kvm/x86.c | 40 ++++++++++++++++++++++++++++++++++++---- include/uapi/linux/kvm.h | 23 +++++++++++++++++++++++ 4 files changed, 85 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 5d8db4922df6..3b6e3b1628b4 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6546,6 +6546,7 @@ KVM_RUN_BUS_LOCK flag is used to distinguish between them. This capability can be used to check / enable 2nd DAWR feature provided by POWER10 processor. + 7.24 KVM_CAP_VM_COPY_ENC_CONTEXT_FROM ------------------------------------- @@ -6603,6 +6604,25 @@ present in the "ibm,hypertas-functions" device-tree property. This capability is enabled for hypervisors on platforms like POWER9 that support radix MMU. +7.27 KVM_CAP_EXIT_ON_EMULATION_FAILURE +-------------------------------------- + +:Architectures: x86 +:Parameters: args[0] whether the feature should be enabled or not + +When this capability is enabled, an emulation failure will result in an exit +to userspace with KVM_INTERNAL_ERROR (except when the emulator was invoked +to handle a VMware backdoor instruction). Furthermore, KVM will now provide up +to 15 instruction bytes for any exit to userspace resulting from an emulation +failure. When these exits to userspace occur use the emulation_failure struct +instead of the internal struct. They both have the same layout, but the +emulation_failure struct matches the content better. It also explicitly +defines the 'flags' field which is used to describe the fields in the struct +that are valid (ie: if KVM_INTERNAL_ERROR_EMULATION_FLAG_INSTRUCTION_BYTES is +set in the 'flags' field then both 'insn_size' and 'insn_bytes' have valid data +in them.) + + 8. Other capabilities. ====================== diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 3cd496c8acb8..c9ec5c76c438 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1114,6 +1114,12 @@ struct kvm_arch { bool exception_payload_enabled; bool bus_lock_detection_enabled; + /* + * If exit_on_emulation_error is set, and the in-kernel instruction + * emulator fails to emulate an instruction, allow userspace + * the opportunity to look at it. + */ + bool exit_on_emulation_error; /* Deflect RDMSR and WRMSR to user space when they trigger a #GP */ u32 user_space_msr_mask; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a7c7b2b28de7..17468d983fbd 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4010,6 +4010,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) #endif case KVM_CAP_VM_COPY_ENC_CONTEXT_FROM: case KVM_CAP_SREGS2: + case KVM_CAP_EXIT_ON_EMULATION_FAILURE: r = 1; break; case KVM_CAP_EXIT_HYPERCALL: @@ -5649,6 +5650,13 @@ split_irqchip_unlock: kvm->arch.hypercall_exit_enabled = cap->args[0]; r = 0; break; + case KVM_CAP_EXIT_ON_EMULATION_FAILURE: + r = -EINVAL; + if (cap->args[0] & ~1) + break; + kvm->arch.exit_on_emulation_error = cap->args[0]; + r = 0; + break; default: r = -EINVAL; break; @@ -7444,8 +7452,33 @@ void kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip) } EXPORT_SYMBOL_GPL(kvm_inject_realmode_interrupt); +static void prepare_emulation_failure_exit(struct kvm_vcpu *vcpu) +{ + struct x86_emulate_ctxt *ctxt = vcpu->arch.emulate_ctxt; + u32 insn_size = ctxt->fetch.end - ctxt->fetch.data; + struct kvm_run *run = vcpu->run; + + run->exit_reason = KVM_EXIT_INTERNAL_ERROR; + run->emulation_failure.suberror = KVM_INTERNAL_ERROR_EMULATION; + run->emulation_failure.ndata = 0; + run->emulation_failure.flags = 0; + + if (insn_size) { + run->emulation_failure.ndata = 3; + run->emulation_failure.flags |= + KVM_INTERNAL_ERROR_EMULATION_FLAG_INSTRUCTION_BYTES; + run->emulation_failure.insn_size = insn_size; + memset(run->emulation_failure.insn_bytes, 0x90, + sizeof(run->emulation_failure.insn_bytes)); + memcpy(run->emulation_failure.insn_bytes, + ctxt->fetch.data, insn_size); + } +} + static int handle_emulation_failure(struct kvm_vcpu *vcpu, int emulation_type) { + struct kvm *kvm = vcpu->kvm; + ++vcpu->stat.insn_emulation_fail; trace_kvm_emulate_insn_failed(vcpu); @@ -7454,10 +7487,9 @@ static int handle_emulation_failure(struct kvm_vcpu *vcpu, int emulation_type) return 1; } - if (emulation_type & EMULTYPE_SKIP) { - vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; - vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; - vcpu->run->internal.ndata = 0; + if (kvm->arch.exit_on_emulation_error || + (emulation_type & EMULTYPE_SKIP)) { + prepare_emulation_failure_exit(vcpu); return 0; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index f1ba602260f6..68c9e6d8bbda 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -280,6 +280,9 @@ struct kvm_xen_exit { /* Encounter unexpected vm-exit reason */ #define KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON 4 +/* Flags that describe what fields in emulation_failure hold valid data. */ +#define KVM_INTERNAL_ERROR_EMULATION_FLAG_INSTRUCTION_BYTES (1ULL << 0) + /* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */ struct kvm_run { /* in */ @@ -383,6 +386,25 @@ struct kvm_run { __u32 ndata; __u64 data[16]; } internal; + /* + * KVM_INTERNAL_ERROR_EMULATION + * + * "struct emulation_failure" is an overlay of "struct internal" + * that is used for the KVM_INTERNAL_ERROR_EMULATION sub-type of + * KVM_EXIT_INTERNAL_ERROR. Note, unlike other internal error + * sub-types, this struct is ABI! It also needs to be backwards + * compatible with "struct internal". Take special care that + * "ndata" is correct, that new fields are enumerated in "flags", + * and that each flag enumerates fields that are 64-bit aligned + * and sized (so that ndata+internal.data[] is valid/accurate). + */ + struct { + __u32 suberror; + __u32 ndata; + __u64 flags; + __u8 insn_size; + __u8 insn_bytes[15]; + } emulation_failure; /* KVM_EXIT_OSI */ struct { __u64 gprs[32]; @@ -1088,6 +1110,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_EXIT_HYPERCALL 201 #define KVM_CAP_PPC_RPT_INVALIDATE 202 #define KVM_CAP_BINARY_STATS_FD 203 +#define KVM_CAP_EXIT_ON_EMULATION_FAILURE 204 #ifdef KVM_CAP_IRQ_ROUTING -- cgit v1.3.1 From c58db2abb19fd2bf23fb25bb3630a9f540df6042 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Mon, 14 Jun 2021 06:43:17 +0900 Subject: spi: convert Xilinx Zynq UltraScale+ MPSoC GQSPI bindings to YAML Convert spi for Xilinx Zynq UltraScale+ MPSoC GQSPI bindings documentation to YAML. Signed-off-by: Nobuhiro Iwamatsu Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210613214317.296667-1-iwamatsu@nigauri.org Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-zynqmp-qspi.txt | 25 ----------- .../devicetree/bindings/spi/spi-zynqmp-qspi.yaml | 51 ++++++++++++++++++++++ 2 files changed, 51 insertions(+), 25 deletions(-) delete mode 100644 Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.txt create mode 100644 Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.txt b/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.txt deleted file mode 100644 index 0f6d37ff541c..000000000000 --- a/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.txt +++ /dev/null @@ -1,25 +0,0 @@ -Xilinx Zynq UltraScale+ MPSoC GQSPI controller Device Tree Bindings -------------------------------------------------------------------- - -Required properties: -- compatible : Should be "xlnx,zynqmp-qspi-1.0". -- reg : Physical base address and size of GQSPI registers map. -- interrupts : Property with a value describing the interrupt - number. -- clock-names : List of input clock names - "ref_clk", "pclk" - (See clock bindings for details). -- clocks : Clock phandles (see clock bindings for details). - -Optional properties: -- num-cs : Number of chip selects used. - -Example: - qspi: spi@ff0f0000 { - compatible = "xlnx,zynqmp-qspi-1.0"; - clock-names = "ref_clk", "pclk"; - clocks = <&misc_clk &misc_clk>; - interrupts = <0 15 4>; - interrupt-parent = <&gic>; - num-cs = <1>; - reg = <0x0 0xff0f0000 0x1000>,<0x0 0xc0000000 0x8000000>; - }; diff --git a/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml b/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml new file mode 100644 index 000000000000..ea72c8001256 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/spi-zynqmp-qspi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Xilinx Zynq UltraScale+ MPSoC GQSPI controller Device Tree Bindings + +maintainers: + - Michal Simek + +allOf: + - $ref: "spi-controller.yaml#" + +properties: + compatible: + const: xlnx,zynqmp-qspi-1.0 + + reg: + maxItems: 2 + + interrupts: + maxItems: 1 + + clock-names: + items: + - const: ref_clk + - const: pclk + + clocks: + maxItems: 2 + +unevaluatedProperties: false + +examples: + - | + #include + soc { + #address-cells = <2>; + #size-cells = <2>; + + qspi: spi@ff0f0000 { + compatible = "xlnx,zynqmp-qspi-1.0"; + clocks = <&zynqmp_clk QSPI_REF>, <&zynqmp_clk LPD_LSBUS>; + clock-names = "ref_clk", "pclk"; + interrupts = <0 15 4>; + interrupt-parent = <&gic>; + reg = <0x0 0xff0f0000 0x0 0x1000>, + <0x0 0xc0000000 0x0 0x8000000>; + }; + }; -- cgit v1.3.1 From 0ae71c7720e3ae3aabd2e8a072d27f7bd173d25c Mon Sep 17 00:00:00 2001 From: Rodrigo Campos Date: Mon, 17 May 2021 12:39:07 -0700 Subject: seccomp: Support atomic "addfd + send reply" Alban Crequy reported a race condition userspace faces when we want to add some fds and make the syscall return them[1] using seccomp notify. The problem is that currently two different ioctl() calls are needed by the process handling the syscalls (agent) for another userspace process (target): SECCOMP_IOCTL_NOTIF_ADDFD to allocate the fd and SECCOMP_IOCTL_NOTIF_SEND to return that value. Therefore, it is possible for the agent to do the first ioctl to add a file descriptor but the target is interrupted (EINTR) before the agent does the second ioctl() call. This patch adds a flag to the ADDFD ioctl() so it adds the fd and returns that value atomically to the target program, as suggested by Kees Cook[2]. This is done by simply allowing seccomp_do_user_notification() to add the fd and return it in this case. Therefore, in this case the target wakes up from the wait in seccomp_do_user_notification() either to interrupt the syscall or to add the fd and return it. This "allocate an fd and return" functionality is useful for syscalls that return a file descriptor only, like connect(2). Other syscalls that return a file descriptor but not as return value (or return more than one fd), like socketpair(), pipe(), recvmsg with SCM_RIGHTs, will not work with this flag. This effectively combines SECCOMP_IOCTL_NOTIF_ADDFD and SECCOMP_IOCTL_NOTIF_SEND into an atomic opteration. The notification's return value, nor error can be set by the user. Upon successful invocation of the SECCOMP_IOCTL_NOTIF_ADDFD ioctl with the SECCOMP_ADDFD_FLAG_SEND flag, the notifying process's errno will be 0, and the return value will be the file descriptor number that was installed. [1]: https://lore.kernel.org/lkml/CADZs7q4sw71iNHmV8EOOXhUKJMORPzF7thraxZYddTZsxta-KQ@mail.gmail.com/ [2]: https://lore.kernel.org/lkml/202012011322.26DCBC64F2@keescook/ Signed-off-by: Rodrigo Campos Signed-off-by: Sargun Dhillon Acked-by: Tycho Andersen Acked-by: Christian Brauner Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20210517193908.3113-4-sargun@sargun.me --- Documentation/userspace-api/seccomp_filter.rst | 12 ++++++ include/uapi/linux/seccomp.h | 1 + kernel/seccomp.c | 51 +++++++++++++++++++++++--- 3 files changed, 58 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/seccomp_filter.rst b/Documentation/userspace-api/seccomp_filter.rst index 6efb41cc8072..d61219889e49 100644 --- a/Documentation/userspace-api/seccomp_filter.rst +++ b/Documentation/userspace-api/seccomp_filter.rst @@ -259,6 +259,18 @@ and ``ioctl(SECCOMP_IOCTL_NOTIF_SEND)`` a response, indicating what should be returned to userspace. The ``id`` member of ``struct seccomp_notif_resp`` should be the same ``id`` as in ``struct seccomp_notif``. +Userspace can also add file descriptors to the notifying process via +``ioctl(SECCOMP_IOCTL_NOTIF_ADDFD)``. The ``id`` member of +``struct seccomp_notif_addfd`` should be the same ``id`` as in +``struct seccomp_notif``. The ``newfd_flags`` flag may be used to set flags +like O_EXEC on the file descriptor in the notifying process. If the supervisor +wants to inject the file descriptor with a specific number, the +``SECCOMP_ADDFD_FLAG_SETFD`` flag can be used, and set the ``newfd`` member to +the specific number to use. If that file descriptor is already open in the +notifying process it will be replaced. The supervisor can also add an FD, and +respond atomically by using the ``SECCOMP_ADDFD_FLAG_SEND`` flag and the return +value will be the injected file descriptor number. + It is worth noting that ``struct seccomp_data`` contains the values of register arguments to the syscall, but does not contain pointers to memory. The task's memory is accessible to suitably privileged traces via ``ptrace()`` or diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h index 6ba18b82a02e..78074254ab98 100644 --- a/include/uapi/linux/seccomp.h +++ b/include/uapi/linux/seccomp.h @@ -115,6 +115,7 @@ struct seccomp_notif_resp { /* valid flags for seccomp_notif_addfd */ #define SECCOMP_ADDFD_FLAG_SETFD (1UL << 0) /* Specify remote fd */ +#define SECCOMP_ADDFD_FLAG_SEND (1UL << 1) /* Addfd and return it, atomically */ /** * struct seccomp_notif_addfd diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 9f58049ac16d..057e17f3215d 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -107,6 +107,7 @@ struct seccomp_knotif { * installing process should allocate the fd as normal. * @flags: The flags for the new file descriptor. At the moment, only O_CLOEXEC * is allowed. + * @ioctl_flags: The flags used for the seccomp_addfd ioctl. * @ret: The return value of the installing process. It is set to the fd num * upon success (>= 0). * @completion: Indicates that the installing process has completed fd @@ -118,6 +119,7 @@ struct seccomp_kaddfd { struct file *file; int fd; unsigned int flags; + __u32 ioctl_flags; union { bool setfd; @@ -1065,18 +1067,37 @@ static u64 seccomp_next_notify_id(struct seccomp_filter *filter) return filter->notif->next_id++; } -static void seccomp_handle_addfd(struct seccomp_kaddfd *addfd) +static void seccomp_handle_addfd(struct seccomp_kaddfd *addfd, struct seccomp_knotif *n) { + int fd; + /* * Remove the notification, and reset the list pointers, indicating * that it has been handled. */ list_del_init(&addfd->list); if (!addfd->setfd) - addfd->ret = receive_fd(addfd->file, addfd->flags); + fd = receive_fd(addfd->file, addfd->flags); else - addfd->ret = receive_fd_replace(addfd->fd, addfd->file, - addfd->flags); + fd = receive_fd_replace(addfd->fd, addfd->file, addfd->flags); + addfd->ret = fd; + + if (addfd->ioctl_flags & SECCOMP_ADDFD_FLAG_SEND) { + /* If we fail reset and return an error to the notifier */ + if (fd < 0) { + n->state = SECCOMP_NOTIFY_SENT; + } else { + /* Return the FD we just added */ + n->flags = 0; + n->error = 0; + n->val = fd; + } + } + + /* + * Mark the notification as completed. From this point, addfd mem + * might be invalidated and we can't safely read it anymore. + */ complete(&addfd->completion); } @@ -1120,7 +1141,7 @@ static int seccomp_do_user_notification(int this_syscall, struct seccomp_kaddfd, list); /* Check if we were woken up by a addfd message */ if (addfd) - seccomp_handle_addfd(addfd); + seccomp_handle_addfd(addfd, &n); } while (n.state != SECCOMP_NOTIFY_REPLIED); @@ -1581,7 +1602,7 @@ static long seccomp_notify_addfd(struct seccomp_filter *filter, if (addfd.newfd_flags & ~O_CLOEXEC) return -EINVAL; - if (addfd.flags & ~SECCOMP_ADDFD_FLAG_SETFD) + if (addfd.flags & ~(SECCOMP_ADDFD_FLAG_SETFD | SECCOMP_ADDFD_FLAG_SEND)) return -EINVAL; if (addfd.newfd && !(addfd.flags & SECCOMP_ADDFD_FLAG_SETFD)) @@ -1591,6 +1612,7 @@ static long seccomp_notify_addfd(struct seccomp_filter *filter, if (!kaddfd.file) return -EBADF; + kaddfd.ioctl_flags = addfd.flags; kaddfd.flags = addfd.newfd_flags; kaddfd.setfd = addfd.flags & SECCOMP_ADDFD_FLAG_SETFD; kaddfd.fd = addfd.newfd; @@ -1616,6 +1638,23 @@ static long seccomp_notify_addfd(struct seccomp_filter *filter, goto out_unlock; } + if (addfd.flags & SECCOMP_ADDFD_FLAG_SEND) { + /* + * Disallow queuing an atomic addfd + send reply while there are + * some addfd requests still to process. + * + * There is no clear reason to support it and allows us to keep + * the loop on the other side straight-forward. + */ + if (!list_empty(&knotif->addfd)) { + ret = -EBUSY; + goto out_unlock; + } + + /* Allow exactly only one reply */ + knotif->state = SECCOMP_NOTIFY_REPLIED; + } + list_add(&kaddfd.list, &knotif->addfd); complete(&knotif->ready); mutex_unlock(&filter->notify_lock); -- cgit v1.3.1