diff --git a/Documentation/devicetree/bindings/leds/common.yaml b/Documentation/devicetree/bindings/leds/common.yaml index 3c14a98430e190..f5c57a580078ea 100644 --- a/Documentation/devicetree/bindings/leds/common.yaml +++ b/Documentation/devicetree/bindings/leds/common.yaml @@ -100,6 +100,7 @@ properties: - pattern # LED is triggered by SD/MMC activity - pattern: "^mmc[0-9]+$" + - pattern: "^cpu[0-9]*$" led-pattern: description: | diff --git a/Documentation/devicetree/bindings/leds/leds-pm8058.txt b/Documentation/devicetree/bindings/leds/leds-pm8058.txt deleted file mode 100644 index 89584c49aab2b3..00000000000000 --- a/Documentation/devicetree/bindings/leds/leds-pm8058.txt +++ /dev/null @@ -1,67 +0,0 @@ -Qualcomm PM8058 LED driver - -The Qualcomm PM8058 is a multi-functional device which contains -an LED driver block for up to six LEDs: three normal LEDs, two -"flash" LEDs and one "keypad backlight" LED. The names are -quoted because sometimes these LED drivers are used for wildly -different things than flash or keypad backlight: their names -are more of a suggestion than a hard-wired usecase. - -Hardware-wise the different LEDs support slightly different -output currents. The "flash" LEDs do not need to charge nor -do they support external triggers. They are just powerful LED -drivers. - -The LEDs appear as children to the PM8058 device, with the -proper compatible string. For the PM8058 bindings see: -mfd/qcom-pm8xxx.txt. - -Each LED is represented as a sub-node of the syscon device. Each -node's name represents the name of the corresponding LED. - -LED sub-node properties: - -Required properties: -- compatible: one of - "qcom,pm8058-led" (for the normal LEDs at 0x131, 0x132 and 0x133) - "qcom,pm8058-keypad-led" (for the "keypad" LED at 0x48) - "qcom,pm8058-flash-led" (for the "flash" LEDs at 0x49 and 0xFB) - -Optional properties: -- label: see Documentation/devicetree/bindings/leds/common.txt -- default-state: see Documentation/devicetree/bindings/leds/common.txt -- linux,default-trigger: see Documentation/devicetree/bindings/leds/common.txt - -Example: - -qcom,ssbi@500000 { - pmicintc: pmic@0 { - compatible = "qcom,pm8058"; - led@48 { - compatible = "qcom,pm8058-keypad-led"; - reg = <0x48>; - label = "pm8050:white:keypad"; - default-state = "off"; - }; - led@131 { - compatible = "qcom,pm8058-led"; - reg = <0x131>; - label = "pm8058:red"; - default-state = "off"; - }; - led@132 { - compatible = "qcom,pm8058-led"; - reg = <0x132>; - label = "pm8058:yellow"; - default-state = "off"; - linux,default-trigger = "mmc0"; - }; - led@133 { - compatible = "qcom,pm8058-led"; - reg = <0x133>; - label = "pm8058:green"; - default-state = "on"; - linux,default-trigger = "heartbeat"; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/leds/qcom,pm8058-led.yaml b/Documentation/devicetree/bindings/leds/qcom,pm8058-led.yaml new file mode 100644 index 00000000000000..fa03e73622d487 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/qcom,pm8058-led.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/qcom,pm8058-led.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm PM8058 PMIC LED + +maintainers: + - Krzysztof Kozlowski + +description: | + The Qualcomm PM8058 contains an LED block for up to six LEDs:: three normal + LEDs, two "flash" LEDs and one "keypad backlight" LED. The names are quoted + because sometimes these LED drivers are used for wildly different things than + flash or keypad backlight:: their names are more of a suggestion than a + hard-wired usecase. + + Hardware-wise the different LEDs support slightly different output currents. + The "flash" LEDs do not need to charge nor do they support external triggers. + They are just powerful LED drivers. + +allOf: + - $ref: common.yaml# + +properties: + compatible: + enum: + - qcom,pm8058-led + - qcom,pm8058-keypad-led + - qcom,pm8058-flash-led + + reg: + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + + pmic { + #address-cells = <1>; + #size-cells = <0>; + + led@131 { + compatible = "qcom,pm8058-led"; + reg = <0x131>; + label = "pm8058:red"; + color = ; + default-state = "off"; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/ene-kb930.yaml b/Documentation/devicetree/bindings/mfd/ene-kb930.yaml index 06ed9ec8f4bbce..7c0a42390f1894 100644 --- a/Documentation/devicetree/bindings/mfd/ene-kb930.yaml +++ b/Documentation/devicetree/bindings/mfd/ene-kb930.yaml @@ -13,6 +13,8 @@ description: | maintainers: - Dmitry Osipenko +$ref: /schemas/power/supply/power-supply.yaml + properties: compatible: items: @@ -22,15 +24,13 @@ properties: reg: maxItems: 1 - monitored-battery: true - power-supplies: true system-power-controller: true required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.yaml b/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.yaml index 61bd0b3ce02f8a..bd6e4aecfe2b14 100644 --- a/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.yaml @@ -39,6 +39,10 @@ properties: interrupt-controller: true patternProperties: + "led@[0-9a-f]+$": + type: object + $ref: /schemas/leds/qcom,pm8058-led.yaml# + "rtc@[0-9a-f]+$": type: object $ref: "../rtc/qcom-pm8xxx-rtc.yaml" diff --git a/Documentation/devicetree/bindings/mfd/rockchip,rk817.yaml b/Documentation/devicetree/bindings/mfd/rockchip,rk817.yaml index 935e17099213fe..269fb85b20278c 100644 --- a/Documentation/devicetree/bindings/mfd/rockchip,rk817.yaml +++ b/Documentation/devicetree/bindings/mfd/rockchip,rk817.yaml @@ -124,6 +124,8 @@ properties: The child node for the charger to hold additional properties. If a battery is not in use, this node can be omitted. type: object + $ref: /schemas/power/supply/power-supply.yaml + properties: monitored-battery: description: | diff --git a/Documentation/devicetree/bindings/power/reset/gpio-restart.yaml b/Documentation/devicetree/bindings/power/reset/gpio-restart.yaml index a72d5c7215161a..d3d18e0f5db385 100644 --- a/Documentation/devicetree/bindings/power/reset/gpio-restart.yaml +++ b/Documentation/devicetree/bindings/power/reset/gpio-restart.yaml @@ -25,6 +25,9 @@ description: > inactive-delay, the GPIO is driven active again. After a delay specified by wait-delay, the restart handler completes allowing other restart handlers to be attempted. +allOf: + - $ref: restart-handler.yaml# + properties: compatible: const: gpio-restart @@ -41,16 +44,6 @@ properties: in its inactive state. priority: - $ref: /schemas/types.yaml#/definitions/uint32 - description: | - A priority ranging from 0 to 255 (default 129) according to the following guidelines: - - 0: Restart handler of last resort, with limited restart capabilities. - 128: Default restart handler; use if no other restart handler is expected to be available, - and/or if restart functionality is sufficient to restart the entire system. - 255: Highest priority restart handler, will preempt all other restart handlers. - minimum: 0 - maximum: 255 default: 129 active-delay: diff --git a/Documentation/devicetree/bindings/power/reset/restart-handler.yaml b/Documentation/devicetree/bindings/power/reset/restart-handler.yaml new file mode 100644 index 00000000000000..1f9a2aac53c081 --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/restart-handler.yaml @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/reset/restart-handler.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Restart and shutdown handler generic binding + +maintainers: + - Sebastian Reichel + +description: + Restart and shutdown handler device is responsible for powering off the + system, e.g. my cutting off the power. System might have several restart + handlers, which usually are tried from most precise to last resort. + +properties: + priority: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + A priority ranging from 0 to 255 according to the following guidelines:: + 0:: Restart handler of last resort, with limited restart capabilities. + 128:: Typical, default restart handler; use if no other restart handler + is expected to be available, and/or if restart functionality is + sufficient to restart the entire system. + 255:: Highest priority restart handler, will preempt all other restart handlers. + minimum: 0 + maximum: 255 + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/power/supply/bq25890.yaml b/Documentation/devicetree/bindings/power/supply/bq25890.yaml index 204c0147188f2b..ee51b6335e728e 100644 --- a/Documentation/devicetree/bindings/power/supply/bq25890.yaml +++ b/Documentation/devicetree/bindings/power/supply/bq25890.yaml @@ -15,11 +15,15 @@ allOf: properties: compatible: - enum: - - ti,bq25890 - - ti,bq25892 - - ti,bq25895 - - ti,bq25896 + oneOf: + - enum: + - ti,bq25890 + - items: + - enum: + - ti,bq25892 + - ti,bq25895 + - ti,bq25896 + - const: ti,bq25890 reg: maxItems: 1 @@ -93,7 +97,7 @@ required: - ti,boost-voltage - ti,boost-max-current -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/power/supply/bq27xxx.yaml b/Documentation/devicetree/bindings/power/supply/bq27xxx.yaml index 65fc6049efc140..347d4433adc5f5 100644 --- a/Documentation/devicetree/bindings/power/supply/bq27xxx.yaml +++ b/Documentation/devicetree/bindings/power/supply/bq27xxx.yaml @@ -60,13 +60,11 @@ properties: monitored-battery: description: | - phandle of battery characteristics node. The fuel gauge uses the following battery properties: - energy-full-design-microwatt-hours - charge-full-design-microamp-hours - voltage-min-design-microvolt Both or neither of the *-full-design-*-hours properties must be set. - See Documentation/devicetree/bindings/power/supply/battery.yaml power-supplies: true diff --git a/Documentation/devicetree/bindings/power/supply/ingenic,battery.yaml b/Documentation/devicetree/bindings/power/supply/ingenic,battery.yaml index 46527038bf2274..42fcfc0269726c 100644 --- a/Documentation/devicetree/bindings/power/supply/ingenic,battery.yaml +++ b/Documentation/devicetree/bindings/power/supply/ingenic,battery.yaml @@ -10,6 +10,8 @@ title: Ingenic JZ47xx battery bindings maintainers: - Artur Rojek +$ref: power-supply.yaml# + properties: compatible: oneOf: @@ -28,8 +30,6 @@ properties: monitored-battery: description: > - phandle to a "simple-battery" compatible node. - This property must be a phandle to a node using the format described in battery.yaml, with the following properties being required: - voltage-min-design-microvolt: drained battery voltage, diff --git a/Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml b/Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml index aff5d0792e0fef..64a0edb7bc473c 100644 --- a/Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml +++ b/Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml @@ -59,6 +59,8 @@ properties: Voltage threshold to report battery as over voltage (in mV). Default is not to report over-voltage events. + power-supplies: true + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/power/supply/power-supply.yaml b/Documentation/devicetree/bindings/power/supply/power-supply.yaml index 2f672e6e8d72c0..4e54c937973ee7 100644 --- a/Documentation/devicetree/bindings/power/supply/power-supply.yaml +++ b/Documentation/devicetree/bindings/power/supply/power-supply.yaml @@ -18,4 +18,10 @@ properties: This property is added to a supply in order to list the devices which supply it power, referenced by their phandles. + monitored-battery: + $ref: /schemas/types.yaml#/definitions/phandle + description: + The battery (with "simple-battery" compatible) being monitored by this + power supply. + additionalProperties: true diff --git a/Documentation/devicetree/bindings/power/supply/rohm,bd99954.yaml b/Documentation/devicetree/bindings/power/supply/rohm,bd99954.yaml index 24b06957b4ca52..14d9b42eda27da 100644 --- a/Documentation/devicetree/bindings/power/supply/rohm,bd99954.yaml +++ b/Documentation/devicetree/bindings/power/supply/rohm,bd99954.yaml @@ -18,6 +18,7 @@ description: | provides a Dual-source Battery Charger, two port BC1.2 detection and a Battery Monitor. +$ref: power-supply.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml b/Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml index eeb043f9bb4f2f..735f7d372ae172 100644 --- a/Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml +++ b/Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml @@ -28,7 +28,6 @@ properties: The charger uses the following battery properties - charge-term-current-microamp: current for charge termination phase. - constant-charge-voltage-max-microvolt: maximum constant input voltage. - See Documentation/devicetree/bindings/power/supply/battery.yaml additionalProperties: false diff --git a/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml b/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml new file mode 100644 index 00000000000000..b3605608410c63 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/mediatek,mtk-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek SoCs Watchdog timer + +maintainers: + - Matthias Brugger + +description: + The watchdog supports a pre-timeout interrupt that fires + timeout-sec/2 before the expiry. + +allOf: + - $ref: watchdog.yaml# + +properties: + compatible: + oneOf: + - enum: + - mediatek,mt2712-wdt + - mediatek,mt6589-wdt + - mediatek,mt6795-wdt + - mediatek,mt7986-wdt + - mediatek,mt8183-wdt + - mediatek,mt8186-wdt + - mediatek,mt8188-wdt + - mediatek,mt8192-wdt + - mediatek,mt8195-wdt + - items: + - enum: + - mediatek,mt2701-wdt + - mediatek,mt6582-wdt + - mediatek,mt6797-wdt + - mediatek,mt7622-wdt + - mediatek,mt7623-wdt + - mediatek,mt7629-wdt + - mediatek,mt8173-wdt + - mediatek,mt8516-wdt + - const: mediatek,mt6589-wdt + + reg: + maxItems: 1 + + interrupts: + items: + - description: Watchdog pre-timeout (bark) interrupt + + mediatek,disable-extrst: + description: Disable sending output reset signal + type: boolean + + '#reset-cells': + const: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + watchdog: watchdog@10007000 { + compatible = "mediatek,mt8183-wdt"; + reg = <0 0x10007000 0 0x100>; + interrupts = ; + mediatek,disable-extrst; + timeout-sec = <10>; + #reset-cells = <1>; + }; + }; diff --git a/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt b/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt deleted file mode 100644 index 762c62e428ef26..00000000000000 --- a/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt +++ /dev/null @@ -1,42 +0,0 @@ -Mediatek SoCs Watchdog timer - -The watchdog supports a pre-timeout interrupt that fires timeout-sec/2 -before the expiry. - -Required properties: - -- compatible should contain: - "mediatek,mt2701-wdt", "mediatek,mt6589-wdt": for MT2701 - "mediatek,mt2712-wdt": for MT2712 - "mediatek,mt6582-wdt", "mediatek,mt6589-wdt": for MT6582 - "mediatek,mt6589-wdt": for MT6589 - "mediatek,mt6797-wdt", "mediatek,mt6589-wdt": for MT6797 - "mediatek,mt7622-wdt", "mediatek,mt6589-wdt": for MT7622 - "mediatek,mt7623-wdt", "mediatek,mt6589-wdt": for MT7623 - "mediatek,mt7629-wdt", "mediatek,mt6589-wdt": for MT7629 - "mediatek,mt7986-wdt", "mediatek,mt6589-wdt": for MT7986 - "mediatek,mt8183-wdt": for MT8183 - "mediatek,mt8186-wdt", "mediatek,mt6589-wdt": for MT8186 - "mediatek,mt8516-wdt", "mediatek,mt6589-wdt": for MT8516 - "mediatek,mt8192-wdt": for MT8192 - "mediatek,mt8195-wdt", "mediatek,mt6589-wdt": for MT8195 - -- reg : Specifies base physical address and size of the registers. - -Optional properties: -- mediatek,disable-extrst: disable send output reset signal -- interrupts: Watchdog pre-timeout (bark) interrupt. -- timeout-sec: contains the watchdog timeout in seconds. -- #reset-cells: Should be 1. - -Example: - -watchdog: watchdog@10007000 { - compatible = "mediatek,mt8183-wdt", - "mediatek,mt6589-wdt"; - mediatek,disable-extrst; - reg = <0 0x10007000 0 0x100>; - interrupts = ; - timeout-sec = <10>; - #reset-cells = <1>; -}; diff --git a/MAINTAINERS b/MAINTAINERS index afe0d838b55203..28cc7862a18739 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11732,11 +11732,13 @@ F: scripts/leaking_addresses.pl LED SUBSYSTEM M: Pavel Machek +M: Lee Jones L: linux-leds@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds.git F: Documentation/devicetree/bindings/leds/ F: drivers/leds/ +F: include/dt-bindings/leds/ F: include/linux/leds.h LEGACY EEPROM DRIVER diff --git a/drivers/hsi/clients/ssi_protocol.c b/drivers/hsi/clients/ssi_protocol.c index 274ad8443f8c28..38e572faff4357 100644 --- a/drivers/hsi/clients/ssi_protocol.c +++ b/drivers/hsi/clients/ssi_protocol.c @@ -968,7 +968,7 @@ static void ssip_xmit_work(struct work_struct *work) ssip_xmit(cl); } -static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev) { struct hsi_client *cl = to_hsi_client(dev->dev.parent); struct ssi_protocol *ssi = hsi_client_drvdata(cl); @@ -1027,7 +1027,7 @@ static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; - return 0; + return NETDEV_TX_OK; drop2: hsi_free_msg(msg); drop: @@ -1035,7 +1035,7 @@ static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev) inc_dropped: dev->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } /* CMT reset event handler */ diff --git a/drivers/hsi/controllers/omap_ssi_core.c b/drivers/hsi/controllers/omap_ssi_core.c index eb982015831858..26f2c3c0129783 100644 --- a/drivers/hsi/controllers/omap_ssi_core.c +++ b/drivers/hsi/controllers/omap_ssi_core.c @@ -502,8 +502,10 @@ static int ssi_probe(struct platform_device *pd) platform_set_drvdata(pd, ssi); err = ssi_add_controller(ssi, pd); - if (err < 0) + if (err < 0) { + hsi_put_controller(ssi); goto out1; + } pm_runtime_enable(&pd->dev); @@ -536,9 +538,9 @@ static int ssi_probe(struct platform_device *pd) device_for_each_child(&pd->dev, NULL, ssi_remove_ports); out2: ssi_remove_controller(ssi); + pm_runtime_disable(&pd->dev); out1: platform_set_drvdata(pd, NULL); - pm_runtime_disable(&pd->dev); return err; } @@ -629,7 +631,13 @@ static int __init ssi_init(void) { if (ret) return ret; - return platform_driver_register(&ssi_port_pdriver); + ret = platform_driver_register(&ssi_port_pdriver); + if (ret) { + platform_driver_unregister(&ssi_pdriver); + return ret; + } + + return 0; } module_init(ssi_init); diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c index 7a60c7709da045..c74972244f08f5 100644 --- a/drivers/infiniband/sw/rxe/rxe_resp.c +++ b/drivers/infiniband/sw/rxe/rxe_resp.c @@ -785,53 +785,61 @@ static enum resp_states atomic_reply(struct rxe_qp *qp, return ret; } -static enum resp_states atomic_write_reply(struct rxe_qp *qp, - struct rxe_pkt_info *pkt) +#ifdef CONFIG_64BIT +static enum resp_states do_atomic_write(struct rxe_qp *qp, + struct rxe_pkt_info *pkt) { - u64 src, *dst; - struct resp_res *res = qp->resp.res; struct rxe_mr *mr = qp->resp.mr; int payload = payload_size(pkt); + u64 src, *dst; - if (!res) { - res = rxe_prepare_res(qp, pkt, RXE_ATOMIC_WRITE_MASK); - qp->resp.res = res; - } - - if (!res->replay) { -#ifdef CONFIG_64BIT - if (mr->state != RXE_MR_STATE_VALID) - return RESPST_ERR_RKEY_VIOLATION; - - memcpy(&src, payload_addr(pkt), payload); + if (mr->state != RXE_MR_STATE_VALID) + return RESPST_ERR_RKEY_VIOLATION; - dst = iova_to_vaddr(mr, qp->resp.va + qp->resp.offset, payload); - /* check vaddr is 8 bytes aligned. */ - if (!dst || (uintptr_t)dst & 7) - return RESPST_ERR_MISALIGNED_ATOMIC; + memcpy(&src, payload_addr(pkt), payload); - /* Do atomic write after all prior operations have completed */ - smp_store_release(dst, src); + dst = iova_to_vaddr(mr, qp->resp.va + qp->resp.offset, payload); + /* check vaddr is 8 bytes aligned. */ + if (!dst || (uintptr_t)dst & 7) + return RESPST_ERR_MISALIGNED_ATOMIC; - /* decrease resp.resid to zero */ - qp->resp.resid -= sizeof(payload); + /* Do atomic write after all prior operations have completed */ + smp_store_release(dst, src); - qp->resp.msn++; + /* decrease resp.resid to zero */ + qp->resp.resid -= sizeof(payload); - /* next expected psn, read handles this separately */ - qp->resp.psn = (pkt->psn + 1) & BTH_PSN_MASK; - qp->resp.ack_psn = qp->resp.psn; + qp->resp.msn++; - qp->resp.opcode = pkt->opcode; - qp->resp.status = IB_WC_SUCCESS; + /* next expected psn, read handles this separately */ + qp->resp.psn = (pkt->psn + 1) & BTH_PSN_MASK; + qp->resp.ack_psn = qp->resp.psn; - return RESPST_ACKNOWLEDGE; + qp->resp.opcode = pkt->opcode; + qp->resp.status = IB_WC_SUCCESS; + return RESPST_ACKNOWLEDGE; +} #else - return RESPST_ERR_UNSUPPORTED_OPCODE; +static enum resp_states do_atomic_write(struct rxe_qp *qp, + struct rxe_pkt_info *pkt) +{ + return RESPST_ERR_UNSUPPORTED_OPCODE; +} #endif /* CONFIG_64BIT */ + +static enum resp_states atomic_write_reply(struct rxe_qp *qp, + struct rxe_pkt_info *pkt) +{ + struct resp_res *res = qp->resp.res; + + if (!res) { + res = rxe_prepare_res(qp, pkt, RXE_ATOMIC_WRITE_MASK); + qp->resp.res = res; } - return RESPST_ACKNOWLEDGE; + if (res->replay) + return RESPST_ACKNOWLEDGE; + return do_atomic_write(qp, pkt); } static struct sk_buff *prepare_ack_packet(struct rxe_qp *qp, diff --git a/drivers/infiniband/sw/siw/siw_qp_tx.c b/drivers/infiniband/sw/siw/siw_qp_tx.c index 7d47b521070b1b..05052b49107f27 100644 --- a/drivers/infiniband/sw/siw/siw_qp_tx.c +++ b/drivers/infiniband/sw/siw/siw_qp_tx.c @@ -29,7 +29,7 @@ static struct page *siw_get_pblpage(struct siw_mem *mem, u64 addr, int *idx) dma_addr_t paddr = siw_pbl_get_buffer(pbl, offset, NULL, idx); if (paddr) - return virt_to_page((void *)paddr); + return virt_to_page((void *)(uintptr_t)paddr); return NULL; } diff --git a/drivers/leds/leds-blinkm.c b/drivers/leds/leds-blinkm.c index 3fb6a2fdaefa67..e19cc8a7b7cac2 100644 --- a/drivers/leds/leds-blinkm.c +++ b/drivers/leds/leds-blinkm.c @@ -139,11 +139,11 @@ static ssize_t show_color_common(struct device *dev, char *buf, int color) return ret; switch (color) { case RED: - return scnprintf(buf, PAGE_SIZE, "%02X\n", data->red); + return sysfs_emit(buf, "%02X\n", data->red); case GREEN: - return scnprintf(buf, PAGE_SIZE, "%02X\n", data->green); + return sysfs_emit(buf, "%02X\n", data->green); case BLUE: - return scnprintf(buf, PAGE_SIZE, "%02X\n", data->blue); + return sysfs_emit(buf, "%02X\n", data->blue); default: return -EINVAL; } @@ -253,7 +253,7 @@ static DEVICE_ATTR_RW(blue); static ssize_t test_show(struct device *dev, struct device_attribute *attr, char *buf) { - return scnprintf(buf, PAGE_SIZE, + return sysfs_emit(buf, "#Write into test to start test sequence!#\n"); } diff --git a/drivers/leds/leds-is31fl319x.c b/drivers/leds/leds-is31fl319x.c index 52b59b62f437cd..b2f4c4ec7c5671 100644 --- a/drivers/leds/leds-is31fl319x.c +++ b/drivers/leds/leds-is31fl319x.c @@ -38,6 +38,7 @@ #define IS31FL3190_CURRENT_uA_MIN 5000 #define IS31FL3190_CURRENT_uA_DEFAULT 42000 #define IS31FL3190_CURRENT_uA_MAX 42000 +#define IS31FL3190_CURRENT_SHIFT 2 #define IS31FL3190_CURRENT_MASK GENMASK(4, 2) #define IS31FL3190_CURRENT_5_mA 0x02 #define IS31FL3190_CURRENT_10_mA 0x01 @@ -553,7 +554,7 @@ static int is31fl319x_probe(struct i2c_client *client) is31fl3196_db_to_gain(is31->audio_gain_db)); else regmap_update_bits(is31->regmap, IS31FL3190_CURRENT, IS31FL3190_CURRENT_MASK, - is31fl3190_microamp_to_cs(dev, aggregated_led_microamp)); + is31fl3190_microamp_to_cs(dev, aggregated_led_microamp) << IS31FL3190_CURRENT_SHIFT); for (i = 0; i < is31->cdef->num_leds; i++) { struct is31fl319x_led *led = &is31->leds[i]; diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c index 43d5970d96aa22..bcd414eb47246e 100644 --- a/drivers/leds/leds-lm3533.c +++ b/drivers/leds/leds-lm3533.c @@ -314,7 +314,7 @@ static ssize_t show_id(struct device *dev, struct led_classdev *led_cdev = dev_get_drvdata(dev); struct lm3533_led *led = to_lm3533_led(led_cdev); - return scnprintf(buf, PAGE_SIZE, "%d\n", led->id); + return sysfs_emit(buf, "%d\n", led->id); } /* @@ -344,7 +344,7 @@ static ssize_t show_risefalltime(struct device *dev, if (ret) return ret; - return scnprintf(buf, PAGE_SIZE, "%x\n", val); + return sysfs_emit(buf, "%x\n", val); } static ssize_t show_risetime(struct device *dev, @@ -415,7 +415,7 @@ static ssize_t show_als_channel(struct device *dev, channel = (val & LM3533_REG_CTRLBANK_BCONF_ALS_CHANNEL_MASK) + 1; - return scnprintf(buf, PAGE_SIZE, "%u\n", channel); + return sysfs_emit(buf, "%u\n", channel); } static ssize_t store_als_channel(struct device *dev, @@ -465,7 +465,7 @@ static ssize_t show_als_en(struct device *dev, enable = val & LM3533_REG_CTRLBANK_BCONF_ALS_EN_MASK; - return scnprintf(buf, PAGE_SIZE, "%d\n", enable); + return sysfs_emit(buf, "%d\n", enable); } static ssize_t store_als_en(struct device *dev, @@ -518,7 +518,7 @@ static ssize_t show_linear(struct device *dev, else linear = 0; - return scnprintf(buf, PAGE_SIZE, "%x\n", linear); + return sysfs_emit(buf, "%x\n", linear); } static ssize_t store_linear(struct device *dev, @@ -564,7 +564,7 @@ static ssize_t show_pwm(struct device *dev, if (ret) return ret; - return scnprintf(buf, PAGE_SIZE, "%u\n", val); + return sysfs_emit(buf, "%u\n", val); } static ssize_t store_pwm(struct device *dev, diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 7ff20c2605041b..19478d9c19a70d 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -469,7 +469,7 @@ static ssize_t lp5521_selftest(struct device *dev, ret = lp5521_run_selftest(chip, buf); mutex_unlock(&chip->lock); - return scnprintf(buf, PAGE_SIZE, "%s\n", ret ? "FAIL" : "OK"); + return sysfs_emit(buf, "%s\n", ret ? "FAIL" : "OK"); } /* device attributes */ diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index 369d40b0b65b85..e08e3de1428df3 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -581,8 +581,8 @@ static ssize_t lp5523_selftest(struct device *dev, struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); struct lp55xx_chip *chip = led->chip; struct lp55xx_platform_data *pdata = chip->pdata; - int i, ret, pos = 0; - u8 status, adc, vdd; + int ret, pos = 0; + u8 status, adc, vdd, i; mutex_lock(&chip->lock); @@ -612,20 +612,21 @@ static ssize_t lp5523_selftest(struct device *dev, vdd--; /* There may be some fluctuation in measurement */ - for (i = 0; i < LP5523_MAX_LEDS; i++) { - /* Skip non-existing channels */ + for (i = 0; i < pdata->num_channels; i++) { + /* Skip disabled channels */ if (pdata->led_config[i].led_current == 0) continue; /* Set default current */ - lp55xx_write(chip, LP5523_REG_LED_CURRENT_BASE + i, + lp55xx_write(chip, LP5523_REG_LED_CURRENT_BASE + led->chan_nr, pdata->led_config[i].led_current); - lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + i, 0xff); + lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + led->chan_nr, + 0xff); /* let current stabilize 2 - 4ms before measurements start */ usleep_range(2000, 4000); lp55xx_write(chip, LP5523_REG_LED_TEST_CTRL, - LP5523_EN_LEDTEST | i); + LP5523_EN_LEDTEST | led->chan_nr); /* ADC conversion time is 2.7 ms typically */ usleep_range(3000, 6000); ret = lp55xx_read(chip, LP5523_REG_STATUS, &status); @@ -633,20 +634,22 @@ static ssize_t lp5523_selftest(struct device *dev, goto fail; if (!(status & LP5523_LEDTEST_DONE)) - usleep_range(3000, 6000);/* Was not ready. Wait. */ + usleep_range(3000, 6000); /* Was not ready. Wait. */ ret = lp55xx_read(chip, LP5523_REG_LED_TEST_ADC, &adc); if (ret < 0) goto fail; if (adc >= vdd || adc < LP5523_ADC_SHORTCIRC_LIM) - pos += sprintf(buf + pos, "LED %d FAIL\n", i); + pos += sprintf(buf + pos, "LED %d FAIL\n", + led->chan_nr); - lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + i, 0x00); + lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + led->chan_nr, + 0x00); /* Restore current */ - lp55xx_write(chip, LP5523_REG_LED_CURRENT_BASE + i, - led->led_current); + lp55xx_write(chip, LP5523_REG_LED_CURRENT_BASE + led->chan_nr, + led->led_current); led++; } if (pos == 0) diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c index 9fdfc1b9a1a0cb..c1940964067af8 100644 --- a/drivers/leds/leds-lp55xx-common.c +++ b/drivers/leds/leds-lp55xx-common.c @@ -88,7 +88,7 @@ static ssize_t led_current_show(struct device *dev, { struct lp55xx_led *led = dev_to_lp55xx_led(dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", led->led_current); + return sysfs_emit(buf, "%d\n", led->led_current); } static ssize_t led_current_store(struct device *dev, @@ -121,7 +121,7 @@ static ssize_t max_current_show(struct device *dev, { struct lp55xx_led *led = dev_to_lp55xx_led(dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", led->max_current); + return sysfs_emit(buf, "%d\n", led->max_current); } static DEVICE_ATTR_RW(led_current); @@ -166,7 +166,7 @@ static int lp55xx_init_led(struct lp55xx_led *led, struct mc_subled *mc_led_info; struct led_classdev *led_cdev; char name[32]; - int i, j = 0; + int i; int ret; if (chan >= max_channel) { @@ -201,7 +201,6 @@ static int lp55xx_init_led(struct lp55xx_led *led, pdata->led_config[chan].color_id[i]; mc_led_info[i].channel = pdata->led_config[chan].output_num[i]; - j++; } led->mc_cdev.subled_info = mc_led_info; diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c index c0bddb33888d7f..c8d7f55c9dec29 100644 --- a/drivers/leds/leds-max8997.c +++ b/drivers/leds/leds-max8997.c @@ -238,11 +238,6 @@ static int max8997_led_probe(struct platform_device *pdev) char name[20]; int ret = 0; - if (pdata == NULL) { - dev_err(&pdev->dev, "no platform data\n"); - return -ENODEV; - } - led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL); if (led == NULL) return -ENOMEM; @@ -258,7 +253,7 @@ static int max8997_led_probe(struct platform_device *pdev) led->iodev = iodev; /* initialize mode and brightness according to platform_data */ - if (pdata->led_pdata) { + if (pdata && pdata->led_pdata) { u8 mode = 0, brightness = 0; mode = pdata->led_pdata->mode[led->id]; diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index 81aaf21212d7d6..33ec4543fb4f82 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -145,12 +145,6 @@ static inline int pca95xx_num_input_regs(int bits) return (bits + 7) / 8; } -/* 4 bits per LED selector register */ -static inline int pca95xx_num_led_regs(int bits) -{ - return (bits + 3) / 4; -} - /* * Return an LED selector register value based on an existing one, with * the appropriate 2-bit state value set for the given LED number (0-3). diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c index 02f51cc618376a..c1a56259226fb7 100644 --- a/drivers/leds/rgb/leds-qcom-lpg.c +++ b/drivers/leds/rgb/leds-qcom-lpg.c @@ -602,8 +602,8 @@ static void lpg_brightness_set(struct lpg_led *led, struct led_classdev *cdev, lpg_lut_sync(lpg, lut_mask); } -static void lpg_brightness_single_set(struct led_classdev *cdev, - enum led_brightness value) +static int lpg_brightness_single_set(struct led_classdev *cdev, + enum led_brightness value) { struct lpg_led *led = container_of(cdev, struct lpg_led, cdev); struct mc_subled info; @@ -614,10 +614,12 @@ static void lpg_brightness_single_set(struct led_classdev *cdev, lpg_brightness_set(led, cdev, &info); mutex_unlock(&led->lpg->lock); + + return 0; } -static void lpg_brightness_mc_set(struct led_classdev *cdev, - enum led_brightness value) +static int lpg_brightness_mc_set(struct led_classdev *cdev, + enum led_brightness value) { struct led_classdev_mc *mc = lcdev_to_mccdev(cdev); struct lpg_led *led = container_of(mc, struct lpg_led, mcdev); @@ -628,6 +630,8 @@ static void lpg_brightness_mc_set(struct led_classdev *cdev, lpg_brightness_set(led, cdev, mc->subled_info); mutex_unlock(&led->lpg->lock); + + return 0; } static int lpg_blink_set(struct lpg_led *led, @@ -1118,7 +1122,7 @@ static int lpg_add_led(struct lpg *lpg, struct device_node *np) led->mcdev.num_colors = num_channels; cdev = &led->mcdev.led_cdev; - cdev->brightness_set = lpg_brightness_mc_set; + cdev->brightness_set_blocking = lpg_brightness_mc_set; cdev->blink_set = lpg_blink_mc_set; /* Register pattern accessors only if we have a LUT block */ @@ -1132,7 +1136,7 @@ static int lpg_add_led(struct lpg *lpg, struct device_node *np) return ret; cdev = &led->cdev; - cdev->brightness_set = lpg_brightness_single_set; + cdev->brightness_set_blocking = lpg_brightness_single_set; cdev->blink_set = lpg_blink_single_set; /* Register pattern accessors only if we have a LUT block */ @@ -1151,7 +1155,7 @@ static int lpg_add_led(struct lpg *lpg, struct device_node *np) else cdev->brightness = LED_OFF; - cdev->brightness_set(cdev, cdev->brightness); + cdev->brightness_set_blocking(cdev, cdev->brightness); init_data.fwnode = of_fwnode_handle(np); diff --git a/drivers/leds/trigger/ledtrig-pattern.c b/drivers/leds/trigger/ledtrig-pattern.c index 43a265dc4696e3..885ca63f383fb4 100644 --- a/drivers/leds/trigger/ledtrig-pattern.c +++ b/drivers/leds/trigger/ledtrig-pattern.c @@ -155,7 +155,7 @@ static ssize_t repeat_show(struct device *dev, struct device_attribute *attr, mutex_unlock(&data->lock); - return scnprintf(buf, PAGE_SIZE, "%d\n", repeat); + return sysfs_emit(buf, "%d\n", repeat); } static ssize_t repeat_store(struct device *dev, struct device_attribute *attr, diff --git a/drivers/power/supply/88pm860x_charger.c b/drivers/power/supply/88pm860x_charger.c index f21ce52fbc0405..2b9fcb7e71d79e 100644 --- a/drivers/power/supply/88pm860x_charger.c +++ b/drivers/power/supply/88pm860x_charger.c @@ -690,8 +690,7 @@ static int pm860x_charger_probe(struct platform_device *pdev) (chip->id == CHIP_PM8607) ? chip->companion : chip->client; if (!info->i2c_8606) { dev_err(&pdev->dev, "Missed I2C address of 88PM8606!\n"); - ret = -EINVAL; - goto out; + return -EINVAL; } info->dev = &pdev->dev; @@ -704,44 +703,26 @@ static int pm860x_charger_probe(struct platform_device *pdev) psy_cfg.drv_data = info; psy_cfg.supplied_to = pm860x_supplied_to; psy_cfg.num_supplicants = ARRAY_SIZE(pm860x_supplied_to); - info->usb = power_supply_register(&pdev->dev, &pm860x_charger_desc, - &psy_cfg); + info->usb = devm_power_supply_register(&pdev->dev, &pm860x_charger_desc, + &psy_cfg); if (IS_ERR(info->usb)) { - ret = PTR_ERR(info->usb); - goto out; + return PTR_ERR(info->usb); } pm860x_init_charger(info); for (i = 0; i < ARRAY_SIZE(info->irq); i++) { - ret = request_threaded_irq(info->irq[i], NULL, - pm860x_irq_descs[i].handler, - IRQF_ONESHOT, pm860x_irq_descs[i].name, info); + ret = devm_request_threaded_irq(&pdev->dev, info->irq[i], NULL, + pm860x_irq_descs[i].handler, + IRQF_ONESHOT, + pm860x_irq_descs[i].name, info); if (ret < 0) { dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", info->irq[i], ret); - goto out_irq; + return ret; } } return 0; - -out_irq: - power_supply_unregister(info->usb); - while (--i >= 0) - free_irq(info->irq[i], info); -out: - return ret; -} - -static int pm860x_charger_remove(struct platform_device *pdev) -{ - struct pm860x_charger_info *info = platform_get_drvdata(pdev); - int i; - - power_supply_unregister(info->usb); - for (i = 0; i < info->irq_nums; i++) - free_irq(info->irq[i], info); - return 0; } static struct platform_driver pm860x_charger_driver = { @@ -749,7 +730,6 @@ static struct platform_driver pm860x_charger_driver = { .name = "88pm860x-charger", }, .probe = pm860x_charger_probe, - .remove = pm860x_charger_remove, }; module_platform_driver(pm860x_charger_driver); diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index c19c50442761dc..308e68545d44d4 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -1940,7 +1940,7 @@ static int ab8500_charger_get_ext_psy_data(struct device *dev, void *data) * * Due to a asic bug it is necessary to lower the input current to the vbus * charger when charging with at some specific levels. This issue is only valid - * for below a certain battery voltage. This function makes sure that the + * for below a certain battery voltage. This function makes sure that * the allowed current limit isn't exceeded. */ static void ab8500_charger_check_vbat_work(struct work_struct *work) @@ -3719,7 +3719,14 @@ static int __init ab8500_charger_init(void) if (ret) return ret; - return platform_driver_register(&ab8500_charger_driver); + ret = platform_driver_register(&ab8500_charger_driver); + if (ret) { + platform_unregister_drivers(ab8500_charger_component_drivers, + ARRAY_SIZE(ab8500_charger_component_drivers)); + return ret; + } + + return 0; } static void __exit ab8500_charger_exit(void) diff --git a/drivers/power/supply/adp5061.c b/drivers/power/supply/adp5061.c index fcf8ff0bc974b8..840db629a46c34 100644 --- a/drivers/power/supply/adp5061.c +++ b/drivers/power/supply/adp5061.c @@ -694,8 +694,7 @@ static const struct power_supply_desc adp5061_desc = { .num_properties = ARRAY_SIZE(adp5061_props), }; -static int adp5061_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adp5061_probe(struct i2c_client *client) { struct power_supply_config psy_cfg = {}; struct adp5061_state *st; @@ -737,7 +736,7 @@ static struct i2c_driver adp5061_driver = { .driver = { .name = KBUILD_MODNAME, }, - .probe = adp5061_probe, + .probe_new = adp5061_probe, .id_table = adp5061_id, }; module_i2c_driver(adp5061_driver); diff --git a/drivers/power/supply/bd99954-charger.c b/drivers/power/supply/bd99954-charger.c index 96e93e1b80949c..250362e15c98ba 100644 --- a/drivers/power/supply/bd99954-charger.c +++ b/drivers/power/supply/bd99954-charger.c @@ -768,27 +768,13 @@ static const struct power_supply_desc bd9995x_power_supply_desc = { * Describe the setting in linear_range table. */ static const struct linear_range input_current_limit_ranges[] = { - { - .min = 0, - .step = 32000, - .min_sel = 0x0, - .max_sel = 0x1ff, - }, + LINEAR_RANGE(0, 0x0, 0x1ff, 32000), }; /* Possible trickle, pre-charging and termination current values */ static const struct linear_range charging_current_ranges[] = { - { - .min = 0, - .step = 64000, - .min_sel = 0x0, - .max_sel = 0x10, - }, { - .min = 1024000, - .step = 0, - .min_sel = 0x11, - .max_sel = 0x1f, - }, + LINEAR_RANGE(0, 0x0, 0x10, 64000), + LINEAR_RANGE(1024000, 0x11, 0x1f, 0), }; /* @@ -796,72 +782,28 @@ static const struct linear_range charging_current_ranges[] = { * and battery over voltage protection have same possible values */ static const struct linear_range charge_voltage_regulation_ranges[] = { - { - .min = 2560000, - .step = 0, - .min_sel = 0, - .max_sel = 0xA0, - }, { - .min = 2560000, - .step = 16000, - .min_sel = 0xA0, - .max_sel = 0x4B0, - }, { - .min = 19200000, - .step = 0, - .min_sel = 0x4B0, - .max_sel = 0x7FF, - }, + LINEAR_RANGE(2560000, 0, 0xA0, 0), + LINEAR_RANGE(2560000, 0xA0, 0x4B0, 16000), + LINEAR_RANGE(19200000, 0x4B0, 0x7FF, 0), }; /* Possible VSYS voltage regulation values */ static const struct linear_range vsys_voltage_regulation_ranges[] = { - { - .min = 2560000, - .step = 0, - .min_sel = 0, - .max_sel = 0x28, - }, { - .min = 2560000, - .step = 64000, - .min_sel = 0x28, - .max_sel = 0x12C, - }, { - .min = 19200000, - .step = 0, - .min_sel = 0x12C, - .max_sel = 0x1FF, - }, + LINEAR_RANGE(2560000, 0, 0x28, 0), + LINEAR_RANGE(2560000, 0x28, 0x12C, 64000), + LINEAR_RANGE(19200000, 0x12C, 0x1FF, 0), }; /* Possible settings for switching from trickle to pre-charging limits */ static const struct linear_range trickle_to_pre_threshold_ranges[] = { - { - .min = 2048000, - .step = 0, - .min_sel = 0, - .max_sel = 0x20, - }, { - .min = 2048000, - .step = 64000, - .min_sel = 0x20, - .max_sel = 0x12C, - }, { - .min = 19200000, - .step = 0, - .min_sel = 0x12C, - .max_sel = 0x1FF - } + LINEAR_RANGE(2048000, 0, 0x20, 0), + LINEAR_RANGE(2048000, 0x20, 0x12C, 64000), + LINEAR_RANGE(19200000, 0x12C, 0x1FF, 0), }; /* Possible current values for fast-charging constant current phase */ static const struct linear_range fast_charge_current_ranges[] = { - { - .min = 0, - .step = 64000, - .min_sel = 0, - .max_sel = 0xFF, - } + LINEAR_RANGE(0, 0, 0xFF, 64000), }; struct battery_init { diff --git a/drivers/power/supply/bq2415x_charger.c b/drivers/power/supply/bq2415x_charger.c index 6b99e1c675b87c..d2cb7431dced00 100644 --- a/drivers/power/supply/bq2415x_charger.c +++ b/drivers/power/supply/bq2415x_charger.c @@ -1520,9 +1520,9 @@ static int bq2415x_power_supply_init(struct bq2415x_device *bq) } /* main bq2415x probe function */ -static int bq2415x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int bq2415x_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); int ret; int num; char *name = NULL; @@ -1780,7 +1780,7 @@ static struct i2c_driver bq2415x_driver = { .of_match_table = of_match_ptr(bq2415x_of_match_table), .acpi_match_table = ACPI_PTR(bq2415x_i2c_acpi_match), }, - .probe = bq2415x_probe, + .probe_new = bq2415x_probe, .remove = bq2415x_remove, .id_table = bq2415x_i2c_id_table, }; diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index 2274679c5ddd21..2b2c3a4391c19b 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -1767,9 +1767,9 @@ static int bq24190_get_config(struct bq24190_dev_info *bdi) return 0; } -static int bq24190_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int bq24190_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; struct power_supply_config charger_cfg = {}, battery_cfg = {}; @@ -2032,7 +2032,7 @@ static const struct of_device_id bq24190_of_match[] = { MODULE_DEVICE_TABLE(of, bq24190_of_match); static struct i2c_driver bq24190_driver = { - .probe = bq24190_probe, + .probe_new = bq24190_probe, .remove = bq24190_remove, .shutdown = bq24190_shutdown, .id_table = bq24190_i2c_ids, diff --git a/drivers/power/supply/bq24257_charger.c b/drivers/power/supply/bq24257_charger.c index a309bbedfe5219..ab4c49788c5862 100644 --- a/drivers/power/supply/bq24257_charger.c +++ b/drivers/power/supply/bq24257_charger.c @@ -947,9 +947,9 @@ static int bq24257_fw_probe(struct bq24257_device *bq) return 0; } -static int bq24257_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int bq24257_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; const struct acpi_device_id *acpi_id; @@ -1167,7 +1167,7 @@ static struct i2c_driver bq24257_driver = { .acpi_match_table = ACPI_PTR(bq24257_acpi_match), .pm = &bq24257_pm, }, - .probe = bq24257_probe, + .probe_new = bq24257_probe, .remove = bq24257_remove, .id_table = bq24257_i2c_ids, }; diff --git a/drivers/power/supply/bq24735-charger.c b/drivers/power/supply/bq24735-charger.c index 3ce36d09c017cf..cfca3a82d5a8d0 100644 --- a/drivers/power/supply/bq24735-charger.c +++ b/drivers/power/supply/bq24735-charger.c @@ -352,8 +352,7 @@ static struct bq24735_platform *bq24735_parse_dt_data(struct i2c_client *client) return pdata; } -static int bq24735_charger_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int bq24735_charger_probe(struct i2c_client *client) { int ret; struct bq24735 *charger; @@ -506,7 +505,7 @@ static struct i2c_driver bq24735_charger_driver = { .name = "bq24735-charger", .of_match_table = bq24735_match_ids, }, - .probe = bq24735_charger_probe, + .probe_new = bq24735_charger_probe, .id_table = bq24735_charger_id, }; diff --git a/drivers/power/supply/bq2515x_charger.c b/drivers/power/supply/bq2515x_charger.c index 4f76ad9c2f18e0..da224ae8dc6155 100644 --- a/drivers/power/supply/bq2515x_charger.c +++ b/drivers/power/supply/bq2515x_charger.c @@ -1078,9 +1078,9 @@ static const struct regmap_config bq25155_regmap_config = { .volatile_reg = bq2515x_volatile_register, }; -static int bq2515x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int bq2515x_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct device *dev = &client->dev; struct bq2515x_device *bq2515x; struct power_supply_config charger_cfg = {}; @@ -1158,7 +1158,7 @@ static struct i2c_driver bq2515x_driver = { .name = "bq2515x-charger", .of_match_table = bq2515x_of_match, }, - .probe = bq2515x_probe, + .probe_new = bq2515x_probe, .id_table = bq2515x_i2c_ids, }; module_i2c_driver(bq2515x_driver); diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c index 01ad84fd147c8a..db13e288e439a8 100644 --- a/drivers/power/supply/bq256xx_charger.c +++ b/drivers/power/supply/bq256xx_charger.c @@ -1619,9 +1619,9 @@ static int bq256xx_parse_dt(struct bq256xx_device *bq, return 0; } -static int bq256xx_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int bq256xx_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct device *dev = &client->dev; struct bq256xx_device *bq; struct power_supply_config psy_cfg = { }; @@ -1744,7 +1744,7 @@ static struct i2c_driver bq256xx_driver = { .of_match_table = bq256xx_of_match, .acpi_match_table = bq256xx_acpi_match, }, - .probe = bq256xx_probe, + .probe_new = bq256xx_probe, .id_table = bq256xx_i2c_ids, }; module_i2c_driver(bq256xx_driver); diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index 6020b58c641d23..2d731ea58323b5 100644 --- a/drivers/power/supply/bq25890_charger.c +++ b/drivers/power/supply/bq25890_charger.c @@ -529,8 +529,53 @@ static int bq25890_power_supply_get_property(struct power_supply *psy, val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; break; - case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: - val->intval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG); + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + val->intval = bq25890_find_val(bq->init_data.iprechg, TBL_ITERM); + break; + + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + val->intval = bq25890_find_val(bq->init_data.iterm, TBL_ITERM); + break; + + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = bq25890_field_read(bq, F_IINLIM); + if (ret < 0) + return ret; + + val->intval = bq25890_find_val(ret, TBL_IINLIM); + break; + + case POWER_SUPPLY_PROP_CURRENT_NOW: /* I_BAT now */ + /* + * This is ADC-sampled immediate charge current supplied + * from charger to battery. The property name is confusing, + * for clarification refer to: + * Documentation/ABI/testing/sysfs-class-power + * /sys/class/power_supply//current_now + */ + ret = bq25890_field_read(bq, F_ICHGR); /* read measured value */ + if (ret < 0) + return ret; + + /* converted_val = ADC_val * 50mA (table 10.3.19) */ + val->intval = ret * -50000; + break; + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: /* I_BAT user limit */ + /* + * This is user-configured constant charge current supplied + * from charger to battery in first phase of charging, when + * battery voltage is below constant charge voltage. + * + * This value reflects the current hardware setting. + * + * The POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX is the + * maximum value of this property. + */ + ret = bq25890_field_read(bq, F_ICHG); + if (ret < 0) + return ret; + val->intval = bq25890_find_val(ret, TBL_ICHG); /* When temperature is too low, charge current is decreased */ if (bq->state.ntc_fault == NTC_FAULT_COOL) { @@ -545,12 +590,25 @@ static int bq25890_power_supply_get_property(struct power_supply *psy, } break; - case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: - if (!state.online) { - val->intval = 0; - break; - } + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: /* I_BAT max */ + /* + * This is maximum allowed constant charge current supplied + * from charger to battery in first phase of charging, when + * battery voltage is below constant charge voltage. + * + * This value is constant for each battery and set from DT. + */ + val->intval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: /* V_BAT now */ + /* + * This is ADC-sampled immediate charge voltage supplied + * from charger to battery. The property name is confusing, + * for clarification refer to: + * Documentation/ABI/testing/sysfs-class-power + * /sys/class/power_supply//voltage_now + */ ret = bq25890_field_read(bq, F_BATV); /* read measured value */ if (ret < 0) return ret; @@ -559,42 +617,33 @@ static int bq25890_power_supply_get_property(struct power_supply *psy, val->intval = 2304000 + ret * 20000; break; - case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: - val->intval = bq25890_find_val(bq->init_data.vreg, TBL_VREG); - break; - - case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: - val->intval = bq25890_find_val(bq->init_data.iprechg, TBL_ITERM); - break; - - case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: - val->intval = bq25890_find_val(bq->init_data.iterm, TBL_ITERM); - break; - - case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: - ret = bq25890_field_read(bq, F_IINLIM); - if (ret < 0) - return ret; - - val->intval = bq25890_find_val(ret, TBL_IINLIM); - break; - - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - ret = bq25890_field_read(bq, F_SYSV); /* read measured value */ + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: /* V_BAT user limit */ + /* + * This is user-configured constant charge voltage supplied + * from charger to battery in second phase of charging, when + * battery voltage reached constant charge voltage. + * + * This value reflects the current hardware setting. + * + * The POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX is the + * maximum value of this property. + */ + ret = bq25890_field_read(bq, F_VREG); if (ret < 0) return ret; - /* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */ - val->intval = 2304000 + ret * 20000; + val->intval = bq25890_find_val(ret, TBL_VREG); break; - case POWER_SUPPLY_PROP_CURRENT_NOW: - ret = bq25890_field_read(bq, F_ICHGR); /* read measured value */ - if (ret < 0) - return ret; - - /* converted_val = ADC_val * 50mA (table 10.3.19) */ - val->intval = ret * -50000; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: /* V_BAT max */ + /* + * This is maximum allowed constant charge voltage supplied + * from charger to battery in second phase of charging, when + * battery voltage reached constant charge voltage. + * + * This value is constant for each battery and set from DT. + */ + val->intval = bq25890_find_val(bq->init_data.vreg, TBL_VREG); break; case POWER_SUPPLY_PROP_TEMP: @@ -618,9 +667,18 @@ static int bq25890_power_supply_set_property(struct power_supply *psy, const union power_supply_propval *val) { struct bq25890_device *bq = power_supply_get_drvdata(psy); + int maxval; u8 lval; switch (psp) { + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + maxval = bq25890_find_val(bq->init_data.ichg, TBL_ICHG); + lval = bq25890_find_idx(min(val->intval, maxval), TBL_ICHG); + return bq25890_field_write(bq, F_ICHG, lval); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + maxval = bq25890_find_val(bq->init_data.vreg, TBL_VREG); + lval = bq25890_find_idx(min(val->intval, maxval), TBL_VREG); + return bq25890_field_write(bq, F_VREG, lval); case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: lval = bq25890_find_idx(val->intval, TBL_IINLIM); return bq25890_field_write(bq, F_IINLIM, lval); @@ -633,6 +691,8 @@ static int bq25890_power_supply_property_is_writeable(struct power_supply *psy, enum power_supply_property psp) { switch (psp) { + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: return true; default: @@ -880,6 +940,7 @@ static const enum power_supply_property bq25890_power_supply_props[] = { POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, @@ -1034,10 +1095,32 @@ static int bq25890_vbus_is_enabled(struct regulator_dev *rdev) return bq25890_field_read(bq, F_OTG_CFG); } +static int bq25890_vbus_get_voltage(struct regulator_dev *rdev) +{ + struct bq25890_device *bq = rdev_get_drvdata(rdev); + + return bq25890_get_vbus_voltage(bq); +} + +static int bq25890_vsys_get_voltage(struct regulator_dev *rdev) +{ + struct bq25890_device *bq = rdev_get_drvdata(rdev); + int ret; + + /* Should be some output voltage ? */ + ret = bq25890_field_read(bq, F_SYSV); /* read measured value */ + if (ret < 0) + return ret; + + /* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */ + return 2304000 + ret * 20000; +} + static const struct regulator_ops bq25890_vbus_ops = { .enable = bq25890_vbus_enable, .disable = bq25890_vbus_disable, .is_enabled = bq25890_vbus_is_enabled, + .get_voltage = bq25890_vbus_get_voltage, }; static const struct regulator_desc bq25890_vbus_desc = { @@ -1046,9 +1129,54 @@ static const struct regulator_desc bq25890_vbus_desc = { .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, .ops = &bq25890_vbus_ops, - .fixed_uV = 5000000, - .n_voltages = 1, }; + +static const struct regulator_ops bq25890_vsys_ops = { + .get_voltage = bq25890_vsys_get_voltage, +}; + +static const struct regulator_desc bq25890_vsys_desc = { + .name = "vsys", + .of_match = "vsys", + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .ops = &bq25890_vsys_ops, +}; + +static int bq25890_register_regulator(struct bq25890_device *bq) +{ + struct bq25890_platform_data *pdata = dev_get_platdata(bq->dev); + struct regulator_config cfg = { + .dev = bq->dev, + .driver_data = bq, + }; + struct regulator_dev *reg; + + if (pdata) + cfg.init_data = pdata->regulator_init_data; + + reg = devm_regulator_register(bq->dev, &bq25890_vbus_desc, &cfg); + if (IS_ERR(reg)) { + return dev_err_probe(bq->dev, PTR_ERR(reg), + "registering vbus regulator"); + } + + /* pdata->regulator_init_data is for vbus only */ + cfg.init_data = NULL; + reg = devm_regulator_register(bq->dev, &bq25890_vsys_desc, &cfg); + if (IS_ERR(reg)) { + return dev_err_probe(bq->dev, PTR_ERR(reg), + "registering vsys regulator"); + } + + return 0; +} +#else +static inline int +bq25890_register_regulator(struct bq25890_device *bq) +{ + return 0; +} #endif static int bq25890_get_chip_version(struct bq25890_device *bq) @@ -1189,8 +1317,14 @@ static int bq25890_fw_probe(struct bq25890_device *bq) return 0; } -static int bq25890_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static void bq25890_non_devm_cleanup(void *data) +{ + struct bq25890_device *bq = data; + + cancel_delayed_work_sync(&bq->pump_express_work); +} + +static int bq25890_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct bq25890_device *bq; @@ -1244,56 +1378,47 @@ static int bq25890_probe(struct i2c_client *client, /* OTG reporting */ bq->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); - if (!IS_ERR_OR_NULL(bq->usb_phy)) { - INIT_WORK(&bq->usb_work, bq25890_usb_work); - bq->usb_nb.notifier_call = bq25890_usb_notifier; - usb_register_notifier(bq->usb_phy, &bq->usb_nb); - } -#ifdef CONFIG_REGULATOR - else { - struct bq25890_platform_data *pdata = dev_get_platdata(dev); - struct regulator_config cfg = { }; - struct regulator_dev *reg; - - cfg.dev = dev; - cfg.driver_data = bq; - if (pdata) - cfg.init_data = pdata->regulator_init_data; - - reg = devm_regulator_register(dev, &bq25890_vbus_desc, &cfg); - if (IS_ERR(reg)) - return dev_err_probe(dev, PTR_ERR(reg), "registering regulator"); - } -#endif + + /* + * This must be before bq25890_power_supply_init(), so that it runs + * after devm unregisters the power_supply. + */ + ret = devm_add_action_or_reset(dev, bq25890_non_devm_cleanup, bq); + if (ret) + return ret; + + ret = bq25890_register_regulator(bq); + if (ret) + return ret; ret = bq25890_power_supply_init(bq); - if (ret < 0) { - dev_err(dev, "Failed to register power supply\n"); - goto err_unregister_usb_notifier; - } + if (ret < 0) + return dev_err_probe(dev, ret, "registering power supply\n"); ret = devm_request_threaded_irq(dev, client->irq, NULL, bq25890_irq_handler_thread, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, BQ25890_IRQ_PIN, bq); if (ret) - goto err_unregister_usb_notifier; - - return 0; + return ret; -err_unregister_usb_notifier: - if (!IS_ERR_OR_NULL(bq->usb_phy)) - usb_unregister_notifier(bq->usb_phy, &bq->usb_nb); + if (!IS_ERR_OR_NULL(bq->usb_phy)) { + INIT_WORK(&bq->usb_work, bq25890_usb_work); + bq->usb_nb.notifier_call = bq25890_usb_notifier; + usb_register_notifier(bq->usb_phy, &bq->usb_nb); + } - return ret; + return 0; } static void bq25890_remove(struct i2c_client *client) { struct bq25890_device *bq = i2c_get_clientdata(client); - if (!IS_ERR_OR_NULL(bq->usb_phy)) + if (!IS_ERR_OR_NULL(bq->usb_phy)) { usb_unregister_notifier(bq->usb_phy, &bq->usb_nb); + cancel_work_sync(&bq->usb_work); + } if (!bq->skip_reset) { /* reset all registers to default values */ @@ -1400,7 +1525,7 @@ static struct i2c_driver bq25890_driver = { .acpi_match_table = ACPI_PTR(bq25890_acpi_match), .pm = &bq25890_pm, }, - .probe = bq25890_probe, + .probe_new = bq25890_probe, .remove = bq25890_remove, .shutdown = bq25890_shutdown, .id_table = bq25890_i2c_ids, diff --git a/drivers/power/supply/bq25980_charger.c b/drivers/power/supply/bq25980_charger.c index 9339f564928278..a59d9762bc9168 100644 --- a/drivers/power/supply/bq25980_charger.c +++ b/drivers/power/supply/bq25980_charger.c @@ -1207,9 +1207,9 @@ static int bq25980_parse_dt(struct bq25980_device *bq) return 0; } -static int bq25980_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int bq25980_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct device *dev = &client->dev; struct bq25980_device *bq; int ret; @@ -1287,7 +1287,7 @@ static struct i2c_driver bq25980_driver = { .name = "bq25980-charger", .of_match_table = bq25980_of_match, }, - .probe = bq25980_probe, + .probe_new = bq25980_probe, .id_table = bq25980_i2c_ids, }; module_i2c_driver(bq25980_driver); diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index 94b00bb89c177f..f8768997333bc5 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -136,9 +136,9 @@ static int bq27xxx_battery_i2c_bulk_write(struct bq27xxx_device_info *di, return 0; } -static int bq27xxx_battery_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int bq27xxx_battery_i2c_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct bq27xxx_device_info *di; int ret; char *name; @@ -295,7 +295,7 @@ static struct i2c_driver bq27xxx_battery_i2c_driver = { .name = "bq27xxx-battery", .of_match_table = of_match_ptr(bq27xxx_battery_i2c_of_match_table), }, - .probe = bq27xxx_battery_i2c_probe, + .probe_new = bq27xxx_battery_i2c_probe, .remove = bq27xxx_battery_i2c_remove, .id_table = bq27xxx_i2c_id_table, }; diff --git a/drivers/power/supply/cw2015_battery.c b/drivers/power/supply/cw2015_battery.c index 6d52641151d9ac..473522b4326adc 100644 --- a/drivers/power/supply/cw2015_battery.c +++ b/drivers/power/supply/cw2015_battery.c @@ -699,6 +699,9 @@ static int cw_bat_probe(struct i2c_client *client) } cw_bat->battery_workqueue = create_singlethread_workqueue("rk_battery"); + if (!cw_bat->battery_workqueue) + return -ENOMEM; + devm_delayed_work_autocancel(&client->dev, &cw_bat->battery_delay_work, cw_bat_work); queue_delayed_work(cw_bat->battery_workqueue, diff --git a/drivers/power/supply/ds2782_battery.c b/drivers/power/supply/ds2782_battery.c index d78cd05402f66c..9b9619246902c6 100644 --- a/drivers/power/supply/ds2782_battery.c +++ b/drivers/power/supply/ds2782_battery.c @@ -368,9 +368,9 @@ static const struct ds278x_battery_ops ds278x_ops[] = { } }; -static int ds278x_battery_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ds278x_battery_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct ds278x_platform_data *pdata = client->dev.platform_data; struct power_supply_config psy_cfg = {}; struct ds278x_info *info; @@ -458,7 +458,7 @@ static struct i2c_driver ds278x_battery_driver = { .name = "ds2782-battery", .pm = &ds278x_battery_pm_ops, }, - .probe = ds278x_battery_probe, + .probe_new = ds278x_battery_probe, .remove = ds278x_battery_remove, .id_table = ds278x_id, }; diff --git a/drivers/power/supply/lp8727_charger.c b/drivers/power/supply/lp8727_charger.c index 384a374b52c195..e6c21377d53c2e 100644 --- a/drivers/power/supply/lp8727_charger.c +++ b/drivers/power/supply/lp8727_charger.c @@ -540,7 +540,7 @@ static struct lp8727_platform_data *lp8727_parse_dt(struct device *dev) } #endif -static int lp8727_probe(struct i2c_client *cl, const struct i2c_device_id *id) +static int lp8727_probe(struct i2c_client *cl) { struct lp8727_chg *pchg; struct lp8727_platform_data *pdata; @@ -615,7 +615,7 @@ static struct i2c_driver lp8727_driver = { .name = "lp8727", .of_match_table = of_match_ptr(lp8727_dt_ids), }, - .probe = lp8727_probe, + .probe_new = lp8727_probe, .remove = lp8727_remove, .id_table = lp8727_ids, }; diff --git a/drivers/power/supply/lp8788-charger.c b/drivers/power/supply/lp8788-charger.c index 56c57529c2287f..f5f47a0aa1e3d5 100644 --- a/drivers/power/supply/lp8788-charger.c +++ b/drivers/power/supply/lp8788-charger.c @@ -520,7 +520,7 @@ static int lp8788_set_irqs(struct platform_device *pdev, static int lp8788_irq_register(struct platform_device *pdev, struct lp8788_charger *pchg) { - const char *name[] = { + static const char * const name[] = { LP8788_CHG_IRQ, LP8788_PRSW_IRQ, LP8788_BATT_IRQ }; int i; diff --git a/drivers/power/supply/ltc2941-battery-gauge.c b/drivers/power/supply/ltc2941-battery-gauge.c index 657305214d68dc..d3fb4282598393 100644 --- a/drivers/power/supply/ltc2941-battery-gauge.c +++ b/drivers/power/supply/ltc2941-battery-gauge.c @@ -439,8 +439,7 @@ static enum power_supply_property ltc294x_properties[] = { POWER_SUPPLY_PROP_CURRENT_NOW, }; -static int ltc294x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc294x_i2c_probe(struct i2c_client *client) { struct power_supply_config psy_cfg = {}; struct ltc294x_info *info; @@ -636,7 +635,7 @@ static struct i2c_driver ltc294x_driver = { .of_match_table = ltc294x_i2c_of_match, .pm = LTC294X_PM_OPS, }, - .probe = ltc294x_i2c_probe, + .probe_new = ltc294x_i2c_probe, .shutdown = ltc294x_i2c_shutdown, .id_table = ltc294x_i2c_id, }; diff --git a/drivers/power/supply/ltc4162-l-charger.c b/drivers/power/supply/ltc4162-l-charger.c index 1a5cb4405ee3ca..db2bb523357052 100644 --- a/drivers/power/supply/ltc4162-l-charger.c +++ b/drivers/power/supply/ltc4162-l-charger.c @@ -819,8 +819,7 @@ static void ltc4162l_clear_interrupts(struct ltc4162l_info *info) regmap_write(info->regmap, LTC4162L_CHARGE_STATUS_ALERTS_REG, 0); } -static int ltc4162l_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc4162l_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -916,7 +915,7 @@ static const struct of_device_id ltc4162l_of_match[] = { MODULE_DEVICE_TABLE(of, ltc4162l_of_match); static struct i2c_driver ltc4162l_driver = { - .probe = ltc4162l_probe, + .probe_new = ltc4162l_probe, .alert = ltc4162l_alert, .id_table = ltc4162l_i2c_id_table, .driver = { diff --git a/drivers/power/supply/max14656_charger_detector.c b/drivers/power/supply/max14656_charger_detector.c index fc36828895bf66..0d0180fcfa63bb 100644 --- a/drivers/power/supply/max14656_charger_detector.c +++ b/drivers/power/supply/max14656_charger_detector.c @@ -234,8 +234,7 @@ static enum power_supply_property max14656_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static int max14656_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max14656_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -317,7 +316,7 @@ static struct i2c_driver max14656_i2c_driver = { .name = "max14656", .of_match_table = max14656_match_table, }, - .probe = max14656_probe, + .probe_new = max14656_probe, .id_table = max14656_id, }; module_i2c_driver(max14656_i2c_driver); diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c index a9aef1e8b186e9..d1075959dd466b 100644 --- a/drivers/power/supply/max17040_battery.c +++ b/drivers/power/supply/max17040_battery.c @@ -430,9 +430,9 @@ static const struct power_supply_desc max17040_battery_desc = { .num_properties = ARRAY_SIZE(max17040_battery_props), }; -static int max17040_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max17040_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct i2c_adapter *adapter = client->adapter; struct power_supply_config psy_cfg = {}; struct max17040_chip *chip; @@ -599,7 +599,7 @@ static struct i2c_driver max17040_i2c_driver = { .of_match_table = max17040_of_match, .pm = MAX17040_PM_OPS, }, - .probe = max17040_probe, + .probe_new = max17040_probe, .id_table = max17040_id, }; module_i2c_driver(max17040_i2c_driver); diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c index ab031bbfbe785b..89cabe8ed3b06e 100644 --- a/drivers/power/supply/max17042_battery.c +++ b/drivers/power/supply/max17042_battery.c @@ -1031,9 +1031,9 @@ static const struct power_supply_desc max17042_no_current_sense_psy_desc = { .num_properties = ARRAY_SIZE(max17042_battery_props) - 2, }; -static int max17042_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max17042_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct i2c_adapter *adapter = client->adapter; const struct power_supply_desc *max17042_desc = &max17042_psy_desc; struct power_supply_config psy_cfg = {}; @@ -1220,7 +1220,7 @@ static struct i2c_driver max17042_i2c_driver = { .of_match_table = of_match_ptr(max17042_dt_match), .pm = &max17042_pm_ops, }, - .probe = max17042_probe, + .probe_new = max17042_probe, .id_table = max17042_id, }; module_i2c_driver(max17042_i2c_driver); diff --git a/drivers/power/supply/mt6360_charger.c b/drivers/power/supply/mt6360_charger.c index 3abaa72e06683c..92e48e3a485364 100644 --- a/drivers/power/supply/mt6360_charger.c +++ b/drivers/power/supply/mt6360_charger.c @@ -113,16 +113,13 @@ enum { MT6360_RANGE_MAX, }; -#define MT6360_LINEAR_RANGE(idx, _min, _min_sel, _max_sel, _step) \ - [idx] = REGULATOR_LINEAR_RANGE(_min, _min_sel, _max_sel, _step) - static const struct linear_range mt6360_chg_range[MT6360_RANGE_MAX] = { - MT6360_LINEAR_RANGE(MT6360_RANGE_VMIVR, 3900000, 0, 0x5F, 100000), - MT6360_LINEAR_RANGE(MT6360_RANGE_ICHG, 100000, 0, 0x31, 100000), - MT6360_LINEAR_RANGE(MT6360_RANGE_VOREG, 3900000, 0, 0x51, 10000), - MT6360_LINEAR_RANGE(MT6360_RANGE_AICR, 100000, 0, 0x3F, 50000), - MT6360_LINEAR_RANGE(MT6360_RANGE_IPREC, 100000, 0, 0x0F, 50000), - MT6360_LINEAR_RANGE(MT6360_RANGE_IEOC, 100000, 0, 0x0F, 50000), + LINEAR_RANGE_IDX(MT6360_RANGE_VMIVR, 3900000, 0, 0x5F, 100000), + LINEAR_RANGE_IDX(MT6360_RANGE_ICHG, 100000, 0, 0x31, 100000), + LINEAR_RANGE_IDX(MT6360_RANGE_VOREG, 3900000, 0, 0x51, 10000), + LINEAR_RANGE_IDX(MT6360_RANGE_AICR, 100000, 0, 0x3F, 50000), + LINEAR_RANGE_IDX(MT6360_RANGE_IPREC, 100000, 0, 0x0F, 50000), + LINEAR_RANGE_IDX(MT6360_RANGE_IEOC, 100000, 0, 0x0F, 50000), }; struct mt6360_chg_info { diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 4b5fb172fa994b..7c790c41e2fe31 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -750,6 +750,11 @@ int power_supply_get_battery_info(struct power_supply *psy, int i, tab_len, size; propname = kasprintf(GFP_KERNEL, "ocv-capacity-table-%d", index); + if (!propname) { + power_supply_put_battery_info(psy, info); + err = -ENOMEM; + goto out_put_node; + } list = of_get_property(battery_np, propname, &size); if (!list || !size) { dev_err(&psy->dev, "failed to get %s\n", propname); @@ -870,7 +875,6 @@ EXPORT_SYMBOL_GPL(power_supply_temp2resist_simple); * power_supply_vbat2ri() - find the battery internal resistance * from the battery voltage * @info: The battery information container - * @table: Pointer to battery resistance temperature table * @vbat_uv: The battery voltage in microvolt * @charging: If we are charging (true) or not (false) * @@ -1387,8 +1391,8 @@ __power_supply_register(struct device *parent, register_cooler_failed: psy_unregister_thermal(psy); register_thermal_failed: - device_del(dev); wakeup_init_failed: + device_del(dev); device_add_failed: check_supplies_failed: dev_set_name_failed: diff --git a/drivers/power/supply/rk817_charger.c b/drivers/power/supply/rk817_charger.c index f20a6ac584ccdb..4f9c1c41791655 100644 --- a/drivers/power/supply/rk817_charger.c +++ b/drivers/power/supply/rk817_charger.c @@ -1060,8 +1060,10 @@ static int rk817_charger_probe(struct platform_device *pdev) return -ENODEV; charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL); - if (!charger) + if (!charger) { + of_node_put(node); return -ENOMEM; + } charger->rk808 = rk808; diff --git a/drivers/power/supply/rt5033_battery.c b/drivers/power/supply/rt5033_battery.c index 736dec608ff6d9..5c04cf30521931 100644 --- a/drivers/power/supply/rt5033_battery.c +++ b/drivers/power/supply/rt5033_battery.c @@ -112,8 +112,7 @@ static const struct power_supply_desc rt5033_battery_desc = { .num_properties = ARRAY_SIZE(rt5033_battery_props), }; -static int rt5033_battery_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int rt5033_battery_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct power_supply_config psy_cfg = {}; @@ -173,7 +172,7 @@ static struct i2c_driver rt5033_battery_driver = { .name = "rt5033-battery", .of_match_table = rt5033_battery_of_match, }, - .probe = rt5033_battery_probe, + .probe_new = rt5033_battery_probe, .remove = rt5033_battery_remove, .id_table = rt5033_battery_id, }; diff --git a/drivers/power/supply/rt9455_charger.c b/drivers/power/supply/rt9455_charger.c index 72962286d70459..31fb6526a1fdf1 100644 --- a/drivers/power/supply/rt9455_charger.c +++ b/drivers/power/supply/rt9455_charger.c @@ -1581,8 +1581,7 @@ static const struct regmap_config rt9455_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int rt9455_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int rt9455_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -1738,7 +1737,7 @@ MODULE_DEVICE_TABLE(acpi, rt9455_i2c_acpi_match); #endif static struct i2c_driver rt9455_driver = { - .probe = rt9455_probe, + .probe_new = rt9455_probe, .remove = rt9455_remove, .id_table = rt9455_i2c_id_table, .driver = { diff --git a/drivers/power/supply/sbs-charger.c b/drivers/power/supply/sbs-charger.c index b08f7d0c418159..75ebcbf0a78837 100644 --- a/drivers/power/supply/sbs-charger.c +++ b/drivers/power/supply/sbs-charger.c @@ -162,8 +162,7 @@ static const struct power_supply_desc sbs_desc = { .get_property = sbs_get_property, }; -static int sbs_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sbs_probe(struct i2c_client *client) { struct power_supply_config psy_cfg = {}; struct sbs_info *chip; @@ -241,7 +240,7 @@ static const struct i2c_device_id sbs_id[] = { MODULE_DEVICE_TABLE(i2c, sbs_id); static struct i2c_driver sbs_driver = { - .probe = sbs_probe, + .probe_new = sbs_probe, .id_table = sbs_id, .driver = { .name = "sbs-charger", diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c index 71ec8f74f83596..bde977391fd4c1 100644 --- a/drivers/power/supply/sbs-manager.c +++ b/drivers/power/supply/sbs-manager.c @@ -315,9 +315,9 @@ static void sbsm_del_mux_adapter(void *data) i2c_mux_del_adapters(sbsm->muxc); } -static int sbsm_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sbsm_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct i2c_adapter *adapter = client->adapter; struct sbsm_data *data; struct device *dev = &client->dev; @@ -409,7 +409,7 @@ static struct i2c_driver sbsm_driver = { .name = "sbsm", .of_match_table = of_match_ptr(sbsm_dt_ids), }, - .probe = sbsm_probe, + .probe_new = sbsm_probe, .alert = sbsm_alert, .id_table = sbsm_ids }; diff --git a/drivers/power/supply/smb347-charger.c b/drivers/power/supply/smb347-charger.c index 996a82f8a2a1dd..b5f0383102824e 100644 --- a/drivers/power/supply/smb347-charger.c +++ b/drivers/power/supply/smb347-charger.c @@ -1528,9 +1528,9 @@ static const struct regulator_desc smb347_usb_vbus_regulator_desc = { .n_voltages = 1, }; -static int smb347_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int smb347_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct power_supply_config mains_usb_cfg = {}; struct regulator_config usb_rdev_cfg = {}; struct device *dev = &client->dev; @@ -1629,7 +1629,7 @@ static struct i2c_driver smb347_driver = { .name = "smb347", .of_match_table = smb3xx_of_match, }, - .probe = smb347_probe, + .probe_new = smb347_probe, .remove = smb347_remove, .shutdown = smb347_shutdown, .id_table = smb347_id, diff --git a/drivers/power/supply/ucs1002_power.c b/drivers/power/supply/ucs1002_power.c index ef673ec3db568a..836d44c9fb74f7 100644 --- a/drivers/power/supply/ucs1002_power.c +++ b/drivers/power/supply/ucs1002_power.c @@ -532,8 +532,7 @@ static const struct regulator_desc ucs1002_regulator_descriptor = { .n_voltages = 1, }; -static int ucs1002_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) +static int ucs1002_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct power_supply_config charger_config = {}; @@ -681,7 +680,7 @@ static struct i2c_driver ucs1002_driver = { .name = "ucs1002", .of_match_table = ucs1002_of_match, }, - .probe = ucs1002_probe, + .probe_new = ucs1002_probe, }; module_i2c_driver(ucs1002_driver); diff --git a/drivers/power/supply/z2_battery.c b/drivers/power/supply/z2_battery.c index 1897c29848600b..0ba4a590a0a5fc 100644 --- a/drivers/power/supply/z2_battery.c +++ b/drivers/power/supply/z2_battery.c @@ -176,8 +176,7 @@ static int z2_batt_ps_init(struct z2_charger *charger, int props) return 0; } -static int z2_batt_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int z2_batt_probe(struct i2c_client *client) { int ret = 0; int props = 1; /* POWER_SUPPLY_PROP_PRESENT */ @@ -206,10 +205,12 @@ static int z2_batt_probe(struct i2c_client *client, charger->charge_gpiod = devm_gpiod_get_optional(&client->dev, NULL, GPIOD_IN); - if (IS_ERR(charger->charge_gpiod)) - return dev_err_probe(&client->dev, + if (IS_ERR(charger->charge_gpiod)) { + ret = dev_err_probe(&client->dev, PTR_ERR(charger->charge_gpiod), "failed to get charge GPIO\n"); + goto err; + } if (charger->charge_gpiod) { gpiod_set_consumer_name(charger->charge_gpiod, "BATT CHRG"); @@ -306,7 +307,7 @@ static struct i2c_driver z2_batt_driver = { .name = "z2-battery", .pm = Z2_BATTERY_PM_OPS }, - .probe = z2_batt_probe, + .probe_new = z2_batt_probe, .remove = z2_batt_remove, .id_table = z2_batt_id, }; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index b64bc49c7f30ed..0bc40b763b0652 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1055,6 +1055,13 @@ config ADVANTECH_WDT feature. More information can be found at +config ADVANTECH_EC_WDT + tristate "Advantech Embedded Controller Watchdog Timer" + depends on X86 + help + This driver supports Advantech products with ITE based Embedded Controller. + It does not support Advantech products with other ECs or without EC. + config ALIM1535_WDT tristate "ALi M1535 PMU Watchdog Timer" depends on X86 && PCI diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index d41e5f830ae7f8..9cbf6580f16c9f 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -102,6 +102,7 @@ obj-$(CONFIG_SUNPLUS_WATCHDOG) += sunplus_wdt.o # X86 (i386 + ia64 + x86_64) Architecture obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o +obj-$(CONFIG_ADVANTECH_EC_WDT) += advantech_ec_wdt.o obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o obj-$(CONFIG_EBC_C384_WDT) += ebc-c384_wdt.o diff --git a/drivers/watchdog/advantech_ec_wdt.c b/drivers/watchdog/advantech_ec_wdt.c new file mode 100644 index 00000000000000..7c380f90ca5831 --- /dev/null +++ b/drivers/watchdog/advantech_ec_wdt.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Advantech Embedded Controller Watchdog Driver + * + * This driver supports Advantech products with ITE based Embedded Controller. + * It does not support Advantech products with other ECs or without EC. + * + * Copyright (C) 2022 Advantech Europe B.V. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "advantech_ec_wdt" + +/* EC IO region */ +#define EC_BASE_ADDR 0x299 +#define EC_ADDR_EXTENT 2 + +/* EC minimum IO access delay in ms */ +#define EC_MIN_DELAY 10 + +/* EC interface definitions */ +#define EC_ADDR_CMD (EC_BASE_ADDR + 1) +#define EC_ADDR_DATA EC_BASE_ADDR +#define EC_CMD_EC_PROBE 0x30 +#define EC_CMD_COMM 0x89 +#define EC_CMD_WDT_START 0x28 +#define EC_CMD_WDT_STOP 0x29 +#define EC_CMD_WDT_RESET 0x2A +#define EC_DAT_EN_DLY_H 0x58 +#define EC_DAT_EN_DLY_L 0x59 +#define EC_DAT_RST_DLY_H 0x5E +#define EC_DAT_RST_DLY_L 0x5F +#define EC_MAGIC 0x95 + +/* module parameters */ +#define MIN_TIME 1 +#define MAX_TIME 6000 /* 100 minutes */ +#define DEFAULT_TIME 60 + +static unsigned int timeout; +static ktime_t ec_timestamp; + +module_param(timeout, uint, 0); +MODULE_PARM_DESC(timeout, + "Default Watchdog timer setting (" __MODULE_STRING(DEFAULT_TIME) "s). The range is from " __MODULE_STRING(MIN_TIME) " to " __MODULE_STRING(MAX_TIME) "."); + +static void adv_ec_wdt_timing_gate(void) +{ + ktime_t time_cur, time_delta; + + /* ensure minimum delay between IO accesses*/ + time_cur = ktime_get(); + time_delta = ktime_to_ms(ktime_sub(time_cur, ec_timestamp)); + if (time_delta < EC_MIN_DELAY) { + time_delta = EC_MIN_DELAY - time_delta; + usleep_range(time_delta * 1000, (time_delta + 1) * 1000); + } + ec_timestamp = ktime_get(); +} + +static void adv_ec_wdt_outb(unsigned char value, unsigned short port) +{ + adv_ec_wdt_timing_gate(); + outb(value, port); +} + +static unsigned char adv_ec_wdt_inb(unsigned short port) +{ + adv_ec_wdt_timing_gate(); + return inb(port); +} + +static int adv_ec_wdt_ping(struct watchdog_device *wdd) +{ + adv_ec_wdt_outb(EC_CMD_WDT_RESET, EC_ADDR_CMD); + return 0; +} + +static int adv_ec_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) +{ + unsigned int val; + + /* scale time to EC 100 ms base */ + val = t * 10; + + /* reset enable delay, just in case it was set by BIOS etc. */ + adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD); + adv_ec_wdt_outb(EC_DAT_EN_DLY_H, EC_ADDR_DATA); + adv_ec_wdt_outb(0, EC_ADDR_DATA); + + adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD); + adv_ec_wdt_outb(EC_DAT_EN_DLY_L, EC_ADDR_DATA); + adv_ec_wdt_outb(0, EC_ADDR_DATA); + + /* set reset delay */ + adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD); + adv_ec_wdt_outb(EC_DAT_RST_DLY_H, EC_ADDR_DATA); + adv_ec_wdt_outb(val >> 8, EC_ADDR_DATA); + + adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD); + adv_ec_wdt_outb(EC_DAT_RST_DLY_L, EC_ADDR_DATA); + adv_ec_wdt_outb(val & 0xFF, EC_ADDR_DATA); + + wdd->timeout = t; + return 0; +} + +static int adv_ec_wdt_start(struct watchdog_device *wdd) +{ + adv_ec_wdt_set_timeout(wdd, wdd->timeout); + adv_ec_wdt_outb(EC_CMD_WDT_START, EC_ADDR_CMD); + + return 0; +} + +static int adv_ec_wdt_stop(struct watchdog_device *wdd) +{ + adv_ec_wdt_outb(EC_CMD_WDT_STOP, EC_ADDR_CMD); + + return 0; +} + +static const struct watchdog_info adv_ec_wdt_info = { + .identity = DRIVER_NAME, + .options = WDIOF_SETTIMEOUT | + WDIOF_MAGICCLOSE | + WDIOF_KEEPALIVEPING, +}; + +static const struct watchdog_ops adv_ec_wdt_ops = { + .owner = THIS_MODULE, + .start = adv_ec_wdt_start, + .stop = adv_ec_wdt_stop, + .ping = adv_ec_wdt_ping, + .set_timeout = adv_ec_wdt_set_timeout, +}; + +static struct watchdog_device adv_ec_wdt_dev = { + .info = &adv_ec_wdt_info, + .ops = &adv_ec_wdt_ops, + .min_timeout = MIN_TIME, + .max_timeout = MAX_TIME, + .timeout = DEFAULT_TIME, +}; + +static int adv_ec_wdt_probe(struct device *dev, unsigned int id) +{ + if (!devm_request_region(dev, EC_BASE_ADDR, EC_ADDR_EXTENT, dev_name(dev))) { + dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", + EC_BASE_ADDR, EC_BASE_ADDR + EC_ADDR_EXTENT); + return -EBUSY; + } + + watchdog_init_timeout(&adv_ec_wdt_dev, timeout, dev); + watchdog_stop_on_reboot(&adv_ec_wdt_dev); + watchdog_stop_on_unregister(&adv_ec_wdt_dev); + + return devm_watchdog_register_device(dev, &adv_ec_wdt_dev); +} + +static struct isa_driver adv_ec_wdt_driver = { + .probe = adv_ec_wdt_probe, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init adv_ec_wdt_init(void) +{ + unsigned int val; + + /* quick probe for EC */ + if (!request_region(EC_BASE_ADDR, EC_ADDR_EXTENT, DRIVER_NAME)) + return -EBUSY; + + adv_ec_wdt_outb(EC_CMD_EC_PROBE, EC_ADDR_CMD); + val = adv_ec_wdt_inb(EC_ADDR_DATA); + release_region(EC_BASE_ADDR, EC_ADDR_EXTENT); + + if (val != EC_MAGIC) + return -ENODEV; + + return isa_register_driver(&adv_ec_wdt_driver, 1); +} + +static void __exit adv_ec_wdt_exit(void) +{ + isa_unregister_driver(&adv_ec_wdt_driver); +} + +module_init(adv_ec_wdt_init); +module_exit(adv_ec_wdt_exit); + +MODULE_AUTHOR("Thomas Kastner "); +MODULE_DESCRIPTION("Advantech Embedded Controller Watchdog Device Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("20221019"); +MODULE_ALIAS("isa:" DRIVER_NAME); diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c index 0cff2adfbfc966..86b5331bc49116 100644 --- a/drivers/watchdog/aspeed_wdt.c +++ b/drivers/watchdog/aspeed_wdt.c @@ -5,11 +5,14 @@ * Joel Stanley */ +#include #include +#include #include #include #include #include +#include #include #include @@ -18,28 +21,41 @@ module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +struct aspeed_wdt_config { + u32 ext_pulse_width_mask; + u32 irq_shift; + u32 irq_mask; +}; + struct aspeed_wdt { struct watchdog_device wdd; void __iomem *base; u32 ctrl; -}; - -struct aspeed_wdt_config { - u32 ext_pulse_width_mask; + const struct aspeed_wdt_config *cfg; }; static const struct aspeed_wdt_config ast2400_config = { .ext_pulse_width_mask = 0xff, + .irq_shift = 0, + .irq_mask = 0, }; static const struct aspeed_wdt_config ast2500_config = { .ext_pulse_width_mask = 0xfffff, + .irq_shift = 12, + .irq_mask = GENMASK(31, 12), +}; + +static const struct aspeed_wdt_config ast2600_config = { + .ext_pulse_width_mask = 0xfffff, + .irq_shift = 0, + .irq_mask = GENMASK(31, 10), }; static const struct of_device_id aspeed_wdt_of_table[] = { { .compatible = "aspeed,ast2400-wdt", .data = &ast2400_config }, { .compatible = "aspeed,ast2500-wdt", .data = &ast2500_config }, - { .compatible = "aspeed,ast2600-wdt", .data = &ast2500_config }, + { .compatible = "aspeed,ast2600-wdt", .data = &ast2600_config }, { }, }; MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table); @@ -58,6 +74,7 @@ MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table); #define WDT_CTRL_RESET_SYSTEM BIT(1) #define WDT_CTRL_ENABLE BIT(0) #define WDT_TIMEOUT_STATUS 0x10 +#define WDT_TIMEOUT_STATUS_IRQ BIT(2) #define WDT_TIMEOUT_STATUS_BOOT_SECONDARY BIT(1) #define WDT_CLEAR_TIMEOUT_STATUS 0x14 #define WDT_CLEAR_TIMEOUT_AND_BOOT_CODE_SELECTION BIT(0) @@ -160,6 +177,26 @@ static int aspeed_wdt_set_timeout(struct watchdog_device *wdd, return 0; } +static int aspeed_wdt_set_pretimeout(struct watchdog_device *wdd, + unsigned int pretimeout) +{ + struct aspeed_wdt *wdt = to_aspeed_wdt(wdd); + u32 actual = pretimeout * WDT_RATE_1MHZ; + u32 s = wdt->cfg->irq_shift; + u32 m = wdt->cfg->irq_mask; + + wdd->pretimeout = pretimeout; + wdt->ctrl &= ~m; + if (pretimeout) + wdt->ctrl |= ((actual << s) & m) | WDT_CTRL_WDT_INTR; + else + wdt->ctrl &= ~WDT_CTRL_WDT_INTR; + + writel(wdt->ctrl, wdt->base + WDT_CTRL); + + return 0; +} + static int aspeed_wdt_restart(struct watchdog_device *wdd, unsigned long action, void *data) { @@ -232,6 +269,7 @@ static const struct watchdog_ops aspeed_wdt_ops = { .stop = aspeed_wdt_stop, .ping = aspeed_wdt_ping, .set_timeout = aspeed_wdt_set_timeout, + .set_pretimeout = aspeed_wdt_set_pretimeout, .restart = aspeed_wdt_restart, .owner = THIS_MODULE, }; @@ -243,10 +281,29 @@ static const struct watchdog_info aspeed_wdt_info = { .identity = KBUILD_MODNAME, }; +static const struct watchdog_info aspeed_wdt_pretimeout_info = { + .options = WDIOF_KEEPALIVEPING + | WDIOF_PRETIMEOUT + | WDIOF_MAGICCLOSE + | WDIOF_SETTIMEOUT, + .identity = KBUILD_MODNAME, +}; + +static irqreturn_t aspeed_wdt_irq(int irq, void *arg) +{ + struct watchdog_device *wdd = arg; + struct aspeed_wdt *wdt = to_aspeed_wdt(wdd); + u32 status = readl(wdt->base + WDT_TIMEOUT_STATUS); + + if (status & WDT_TIMEOUT_STATUS_IRQ) + watchdog_notify_pretimeout(wdd); + + return IRQ_HANDLED; +} + static int aspeed_wdt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - const struct aspeed_wdt_config *config; const struct of_device_id *ofdid; struct aspeed_wdt *wdt; struct device_node *np; @@ -259,11 +316,33 @@ static int aspeed_wdt_probe(struct platform_device *pdev) if (!wdt) return -ENOMEM; + np = dev->of_node; + + ofdid = of_match_node(aspeed_wdt_of_table, np); + if (!ofdid) + return -EINVAL; + wdt->cfg = ofdid->data; + wdt->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(wdt->base)) return PTR_ERR(wdt->base); wdt->wdd.info = &aspeed_wdt_info; + + if (wdt->cfg->irq_mask) { + int irq = platform_get_irq_optional(pdev, 0); + + if (irq > 0) { + ret = devm_request_irq(dev, irq, aspeed_wdt_irq, + IRQF_SHARED, dev_name(dev), + wdt); + if (ret) + return ret; + + wdt->wdd.info = &aspeed_wdt_pretimeout_info; + } + } + wdt->wdd.ops = &aspeed_wdt_ops; wdt->wdd.max_hw_heartbeat_ms = WDT_MAX_TIMEOUT_MS; wdt->wdd.parent = dev; @@ -273,13 +352,6 @@ static int aspeed_wdt_probe(struct platform_device *pdev) watchdog_set_nowayout(&wdt->wdd, nowayout); - np = dev->of_node; - - ofdid = of_match_node(aspeed_wdt_of_table, np); - if (!ofdid) - return -EINVAL; - config = ofdid->data; - /* * On clock rates: * - ast2400 wdt can run at PCLK, or 1MHz @@ -331,7 +403,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev) (of_device_is_compatible(np, "aspeed,ast2600-wdt"))) { u32 reg = readl(wdt->base + WDT_RESET_WIDTH); - reg &= config->ext_pulse_width_mask; + reg &= wdt->cfg->ext_pulse_width_mask; if (of_property_read_bool(np, "aspeed,ext-active-high")) reg |= WDT_ACTIVE_HIGH_MAGIC; else @@ -339,7 +411,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev) writel(reg, wdt->base + WDT_RESET_WIDTH); - reg &= config->ext_pulse_width_mask; + reg &= wdt->cfg->ext_pulse_width_mask; if (of_property_read_bool(np, "aspeed,ext-push-pull")) reg |= WDT_PUSH_PULL_MAGIC; else @@ -349,7 +421,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev) } if (!of_property_read_u32(np, "aspeed,ext-pulse-duration", &duration)) { - u32 max_duration = config->ext_pulse_width_mask + 1; + u32 max_duration = wdt->cfg->ext_pulse_width_mask + 1; if (duration == 0 || duration > max_duration) { dev_err(dev, "Invalid pulse duration: %uus\n", diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c index 6d751eb8191d6c..5126454bb86138 100644 --- a/drivers/watchdog/at91rm9200_wdt.c +++ b/drivers/watchdog/at91rm9200_wdt.c @@ -278,8 +278,6 @@ static void at91wdt_shutdown(struct platform_device *pdev) at91_wdt_stop(); } -#ifdef CONFIG_PM - static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message) { at91_wdt_stop(); @@ -293,11 +291,6 @@ static int at91wdt_resume(struct platform_device *pdev) return 0; } -#else -#define at91wdt_suspend NULL -#define at91wdt_resume NULL -#endif - static const struct of_device_id at91_wdt_dt_ids[] = { { .compatible = "atmel,at91rm9200-wdt" }, { /* sentinel */ } @@ -308,8 +301,8 @@ static struct platform_driver at91wdt_driver = { .probe = at91wdt_probe, .remove = at91wdt_remove, .shutdown = at91wdt_shutdown, - .suspend = at91wdt_suspend, - .resume = at91wdt_resume, + .suspend = pm_ptr(at91wdt_suspend), + .resume = pm_ptr(at91wdt_resume), .driver = { .name = "atmel_st_watchdog", .of_match_table = at91_wdt_dt_ids, diff --git a/drivers/watchdog/db8500_wdt.c b/drivers/watchdog/db8500_wdt.c index 6ed8b63d310d12..97148ac0aa54a8 100644 --- a/drivers/watchdog/db8500_wdt.c +++ b/drivers/watchdog/db8500_wdt.c @@ -105,7 +105,6 @@ static int db8500_wdt_probe(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM static int db8500_wdt_suspend(struct platform_device *pdev, pm_message_t state) { @@ -130,15 +129,11 @@ static int db8500_wdt_resume(struct platform_device *pdev) } return 0; } -#else -#define db8500_wdt_suspend NULL -#define db8500_wdt_resume NULL -#endif static struct platform_driver db8500_wdt_driver = { .probe = db8500_wdt_probe, - .suspend = db8500_wdt_suspend, - .resume = db8500_wdt_resume, + .suspend = pm_ptr(db8500_wdt_suspend), + .resume = pm_ptr(db8500_wdt_resume), .driver = { .name = "db8500_wdt", }, diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 34693f11385f6c..e937b4dd28be75 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -423,14 +423,18 @@ static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev) return time_left; } -static void iTCO_wdt_set_running(struct iTCO_wdt_private *p) +/* Returns true if the watchdog was running */ +static bool iTCO_wdt_set_running(struct iTCO_wdt_private *p) { u16 val; - /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is * enabled */ + /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled */ val = inw(TCO1_CNT(p)); - if (!(val & BIT(11))) + if (!(val & BIT(11))) { set_bit(WDOG_HW_RUNNING, &p->wddev.status); + return true; + } + return false; } /* @@ -518,9 +522,6 @@ static int iTCO_wdt_probe(struct platform_device *pdev) return -ENODEV; /* Cannot reset NO_REBOOT bit */ } - /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ - p->update_no_reboot_bit(p->no_reboot_priv, true); - if (turn_SMI_watchdog_clear_off >= p->iTCO_version) { /* * Bit 13: TCO_EN -> 0 @@ -572,7 +573,13 @@ static int iTCO_wdt_probe(struct platform_device *pdev) watchdog_set_drvdata(&p->wddev, p); platform_set_drvdata(pdev, p); - iTCO_wdt_set_running(p); + if (!iTCO_wdt_set_running(p)) { + /* + * If the watchdog was not running set NO_REBOOT now to + * prevent later reboots. + */ + p->update_no_reboot_bit(p->no_reboot_priv, true); + } /* Check that the heartbeat value is within it's range; if not reset to the default */ diff --git a/drivers/watchdog/kempld_wdt.c b/drivers/watchdog/kempld_wdt.c index 40bd518ed87387..e6c7a290668043 100644 --- a/drivers/watchdog/kempld_wdt.c +++ b/drivers/watchdog/kempld_wdt.c @@ -75,9 +75,7 @@ struct kempld_wdt_data { struct watchdog_device wdd; unsigned int pretimeout; struct kempld_wdt_stage stage[KEMPLD_WDT_MAX_STAGES]; -#ifdef CONFIG_PM u8 pm_status_store; -#endif }; #define DEFAULT_TIMEOUT 30 /* seconds */ @@ -495,7 +493,6 @@ static int kempld_wdt_probe(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM /* Disable watchdog if it is active during suspend */ static int kempld_wdt_suspend(struct platform_device *pdev, pm_message_t message) @@ -531,18 +528,14 @@ static int kempld_wdt_resume(struct platform_device *pdev) else return kempld_wdt_stop(wdd); } -#else -#define kempld_wdt_suspend NULL -#define kempld_wdt_resume NULL -#endif static struct platform_driver kempld_wdt_driver = { .driver = { .name = "kempld-wdt", }, .probe = kempld_wdt_probe, - .suspend = kempld_wdt_suspend, - .resume = kempld_wdt_resume, + .suspend = pm_ptr(kempld_wdt_suspend), + .resume = pm_ptr(kempld_wdt_resume), }; module_platform_driver(kempld_wdt_driver); diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c index e977875367926e..3e6212591e697b 100644 --- a/drivers/watchdog/mtk_wdt.c +++ b/drivers/watchdog/mtk_wdt.c @@ -10,9 +10,11 @@ */ #include +#include #include #include #include +#include #include #include #include @@ -78,6 +80,10 @@ static const struct mtk_wdt_data mt2712_data = { .toprgu_sw_rst_num = MT2712_TOPRGU_SW_RST_NUM, }; +static const struct mtk_wdt_data mt6795_data = { + .toprgu_sw_rst_num = MT6795_TOPRGU_SW_RST_NUM, +}; + static const struct mtk_wdt_data mt7986_data = { .toprgu_sw_rst_num = MT7986_TOPRGU_SW_RST_NUM, }; @@ -90,6 +96,10 @@ static const struct mtk_wdt_data mt8186_data = { .toprgu_sw_rst_num = MT8186_TOPRGU_SW_RST_NUM, }; +static const struct mtk_wdt_data mt8188_data = { + .toprgu_sw_rst_num = MT8188_TOPRGU_SW_RST_NUM, +}; + static const struct mtk_wdt_data mt8192_data = { .toprgu_sw_rst_num = MT8192_TOPRGU_SW_RST_NUM, }; @@ -426,9 +436,11 @@ static int mtk_wdt_resume(struct device *dev) static const struct of_device_id mtk_wdt_dt_ids[] = { { .compatible = "mediatek,mt2712-wdt", .data = &mt2712_data }, { .compatible = "mediatek,mt6589-wdt" }, + { .compatible = "mediatek,mt6795-wdt", .data = &mt6795_data }, { .compatible = "mediatek,mt7986-wdt", .data = &mt7986_data }, { .compatible = "mediatek,mt8183-wdt", .data = &mt8183_data }, { .compatible = "mediatek,mt8186-wdt", .data = &mt8186_data }, + { .compatible = "mediatek,mt8188-wdt", .data = &mt8188_data }, { .compatible = "mediatek,mt8192-wdt", .data = &mt8192_data }, { .compatible = "mediatek,mt8195-wdt", .data = &mt8195_data }, { /* sentinel */ } diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index 74d785b2b478f4..e75aa86f63cbb4 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c @@ -316,8 +316,6 @@ static int omap_wdt_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM - /* REVISIT ... not clear this is the best way to handle system suspend; and * it's very inappropriate for selective device suspend (e.g. suspending this * through sysfs rather than by stopping the watchdog daemon). Also, this @@ -353,11 +351,6 @@ static int omap_wdt_resume(struct platform_device *pdev) return 0; } -#else -#define omap_wdt_suspend NULL -#define omap_wdt_resume NULL -#endif - static const struct of_device_id omap_wdt_of_match[] = { { .compatible = "ti,omap3-wdt", }, {}, @@ -368,8 +361,8 @@ static struct platform_driver omap_wdt_driver = { .probe = omap_wdt_probe, .remove = omap_wdt_remove, .shutdown = omap_wdt_shutdown, - .suspend = omap_wdt_suspend, - .resume = omap_wdt_resume, + .suspend = pm_ptr(omap_wdt_suspend), + .resume = pm_ptr(omap_wdt_resume), .driver = { .name = "omap_wdt", .of_match_table = omap_wdt_of_match, diff --git a/drivers/watchdog/rn5t618_wdt.c b/drivers/watchdog/rn5t618_wdt.c index 6e524c8e26a8f0..40d8ebd8c0acd5 100644 --- a/drivers/watchdog/rn5t618_wdt.c +++ b/drivers/watchdog/rn5t618_wdt.c @@ -144,6 +144,8 @@ static int rn5t618_wdt_probe(struct platform_device *pdev) struct rn5t618 *rn5t618 = dev_get_drvdata(dev->parent); struct rn5t618_wdt *wdt; int min_timeout, max_timeout; + int ret; + unsigned int val; wdt = devm_kzalloc(dev, sizeof(struct rn5t618_wdt), GFP_KERNEL); if (!wdt) @@ -160,6 +162,16 @@ static int rn5t618_wdt_probe(struct platform_device *pdev) wdt->wdt_dev.timeout = max_timeout; wdt->wdt_dev.parent = dev; + /* Read out previous power-off factor */ + ret = regmap_read(wdt->rn5t618->regmap, RN5T618_POFFHIS, &val); + if (ret) + return ret; + + if (val & RN5T618_POFFHIS_VINDET) + wdt->wdt_dev.bootstatus = WDIOF_POWERUNDER; + else if (val & RN5T618_POFFHIS_WDG) + wdt->wdt_dev.bootstatus = WDIOF_CARDRESET; + watchdog_set_drvdata(&wdt->wdt_dev, wdt); watchdog_init_timeout(&wdt->wdt_dev, timeout, dev); watchdog_set_nowayout(&wdt->wdt_dev, nowayout); diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c index 36b4a660928d3d..09d17e20f4a76a 100644 --- a/drivers/watchdog/twl4030_wdt.c +++ b/drivers/watchdog/twl4030_wdt.c @@ -81,7 +81,6 @@ static int twl4030_wdt_probe(struct platform_device *pdev) return devm_watchdog_register_device(dev, wdt); } -#ifdef CONFIG_PM static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state) { struct watchdog_device *wdt = platform_get_drvdata(pdev); @@ -99,10 +98,6 @@ static int twl4030_wdt_resume(struct platform_device *pdev) return 0; } -#else -#define twl4030_wdt_suspend NULL -#define twl4030_wdt_resume NULL -#endif static const struct of_device_id twl_wdt_of_match[] = { { .compatible = "ti,twl4030-wdt", }, @@ -112,8 +107,8 @@ MODULE_DEVICE_TABLE(of, twl_wdt_of_match); static struct platform_driver twl4030_wdt_driver = { .probe = twl4030_wdt_probe, - .suspend = twl4030_wdt_suspend, - .resume = twl4030_wdt_resume, + .suspend = pm_ptr(twl4030_wdt_suspend), + .resume = pm_ptr(twl4030_wdt_resume), .driver = { .name = "twl4030_wdt", .of_match_table = twl_wdt_of_match, diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 05bee80ac7dee5..e782b4f1d1043e 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -427,8 +427,6 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) return error; kaddr = kmap_atomic(page); - if (dsize > gfs2_max_stuffed_size(ip)) - dsize = gfs2_max_stuffed_size(ip); memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), dsize); memset(kaddr + dsize, 0, PAGE_SIZE - dsize); kunmap_atomic(kaddr); diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 3bdb2c668a71c3..e7537fd305dd29 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -61,9 +61,6 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, void *kaddr = kmap(page); u64 dsize = i_size_read(inode); - if (dsize > gfs2_max_stuffed_size(ip)) - dsize = gfs2_max_stuffed_size(ip); - memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), dsize); memset(kaddr + dsize, 0, PAGE_SIZE - dsize); kunmap(page); diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 60c6fb91fb589d..eea5be4fbf0eff 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -1445,14 +1445,13 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) static void __flock_holder_uninit(struct file *file, struct gfs2_holder *fl_gh) { - struct gfs2_glock *gl = fl_gh->gh_gl; + struct gfs2_glock *gl = gfs2_glock_hold(fl_gh->gh_gl); /* * Make sure gfs2_glock_put() won't sleep under the file->f_lock * spinlock. */ - gfs2_glock_hold(gl); spin_lock(&file->f_lock); gfs2_holder_uninit(fl_gh); spin_unlock(&file->f_lock); diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index df335c258eb083..524f3c96b9a4c1 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -186,10 +186,11 @@ void gfs2_glock_free(struct gfs2_glock *gl) * */ -void gfs2_glock_hold(struct gfs2_glock *gl) +struct gfs2_glock *gfs2_glock_hold(struct gfs2_glock *gl) { GLOCK_BUG_ON(gl, __lockref_is_dead(&gl->gl_lockref)); lockref_get(&gl->gl_lockref); + return gl; } /** @@ -205,12 +206,6 @@ static int demote_ok(const struct gfs2_glock *gl) if (gl->gl_state == LM_ST_UNLOCKED) return 0; - /* - * Note that demote_ok is used for the lru process of disposing of - * glocks. For this purpose, we don't care if the glock's holders - * have the HIF_MAY_DEMOTE flag set or not. If someone is using - * them, don't demote. - */ if (!list_empty(&gl->gl_holders)) return 0; if (glops->go_demote_ok) @@ -393,7 +388,7 @@ static void do_error(struct gfs2_glock *gl, const int ret) struct gfs2_holder *gh, *tmp; list_for_each_entry_safe(gh, tmp, &gl->gl_holders, gh_list) { - if (!test_bit(HIF_WAIT, &gh->gh_iflags)) + if (test_bit(HIF_HOLDER, &gh->gh_iflags)) continue; if (ret & LM_OUT_ERROR) gh->gh_error = -EIO; @@ -407,45 +402,6 @@ static void do_error(struct gfs2_glock *gl, const int ret) } } -/** - * demote_incompat_holders - demote incompatible demoteable holders - * @gl: the glock we want to promote - * @current_gh: the newly promoted holder - * - * We're passing the newly promoted holder in @current_gh, but actually, any of - * the strong holders would do. - */ -static void demote_incompat_holders(struct gfs2_glock *gl, - struct gfs2_holder *current_gh) -{ - struct gfs2_holder *gh, *tmp; - - /* - * Demote incompatible holders before we make ourselves eligible. - * (This holder may or may not allow auto-demoting, but we don't want - * to demote the new holder before it's even granted.) - */ - list_for_each_entry_safe(gh, tmp, &gl->gl_holders, gh_list) { - /* - * Since holders are at the front of the list, we stop when we - * find the first non-holder. - */ - if (!test_bit(HIF_HOLDER, &gh->gh_iflags)) - return; - if (gh == current_gh) - continue; - if (test_bit(HIF_MAY_DEMOTE, &gh->gh_iflags) && - !may_grant(gl, current_gh, gh)) { - /* - * We should not recurse into do_promote because - * __gfs2_glock_dq only calls handle_callback, - * gfs2_glock_add_to_lru and __gfs2_glock_queue_work. - */ - __gfs2_glock_dq(gh); - } - } -} - /** * find_first_holder - find the first "holder" gh * @gl: the glock @@ -464,26 +420,6 @@ static inline struct gfs2_holder *find_first_holder(const struct gfs2_glock *gl) return NULL; } -/** - * find_first_strong_holder - find the first non-demoteable holder - * @gl: the glock - * - * Find the first holder that doesn't have the HIF_MAY_DEMOTE flag set. - */ -static inline struct gfs2_holder * -find_first_strong_holder(struct gfs2_glock *gl) -{ - struct gfs2_holder *gh; - - list_for_each_entry(gh, &gl->gl_holders, gh_list) { - if (!test_bit(HIF_HOLDER, &gh->gh_iflags)) - return NULL; - if (!test_bit(HIF_MAY_DEMOTE, &gh->gh_iflags)) - return gh; - } - return NULL; -} - /* * gfs2_instantiate - Call the glops instantiate function * @gh: The glock holder @@ -540,9 +476,8 @@ int gfs2_instantiate(struct gfs2_holder *gh) static int do_promote(struct gfs2_glock *gl) { struct gfs2_holder *gh, *current_gh; - bool incompat_holders_demoted = false; - current_gh = find_first_strong_holder(gl); + current_gh = find_first_holder(gl); list_for_each_entry(gh, &gl->gl_holders, gh_list) { if (test_bit(HIF_HOLDER, &gh->gh_iflags)) continue; @@ -561,11 +496,8 @@ static int do_promote(struct gfs2_glock *gl) set_bit(HIF_HOLDER, &gh->gh_iflags); trace_gfs2_promote(gh); gfs2_holder_wake(gh); - if (!incompat_holders_demoted) { + if (!current_gh) current_gh = gh; - demote_incompat_holders(gl, current_gh); - incompat_holders_demoted = true; - } } return 0; } @@ -927,6 +859,48 @@ __acquires(&gl->gl_lockref.lock) return; } +/** + * glock_set_object - set the gl_object field of a glock + * @gl: the glock + * @object: the object + */ +void glock_set_object(struct gfs2_glock *gl, void *object) +{ + void *prev_object; + + spin_lock(&gl->gl_lockref.lock); + prev_object = gl->gl_object; + gl->gl_object = object; + spin_unlock(&gl->gl_lockref.lock); + if (gfs2_assert_warn(gl->gl_name.ln_sbd, prev_object == NULL)) { + pr_warn("glock=%u/%llx\n", + gl->gl_name.ln_type, + (unsigned long long)gl->gl_name.ln_number); + gfs2_dump_glock(NULL, gl, true); + } +} + +/** + * glock_clear_object - clear the gl_object field of a glock + * @gl: the glock + */ +void glock_clear_object(struct gfs2_glock *gl, void *object) +{ + void *prev_object; + + spin_lock(&gl->gl_lockref.lock); + prev_object = gl->gl_object; + gl->gl_object = NULL; + spin_unlock(&gl->gl_lockref.lock); + if (gfs2_assert_warn(gl->gl_name.ln_sbd, + prev_object == object || prev_object == NULL)) { + pr_warn("glock=%u/%llx\n", + gl->gl_name.ln_type, + (unsigned long long)gl->gl_name.ln_number); + gfs2_dump_glock(NULL, gl, true); + } +} + void gfs2_inode_remember_delete(struct gfs2_glock *gl, u64 generation) { struct gfs2_inode_lvb *ri = (void *)gl->gl_lksb.sb_lvbptr; @@ -980,8 +954,6 @@ static bool gfs2_try_evict(struct gfs2_glock *gl) ip = NULL; spin_unlock(&gl->gl_lockref.lock); if (ip) { - struct gfs2_glock *inode_gl = NULL; - gl->gl_no_formal_ino = ip->i_no_formal_ino; set_bit(GIF_DEFERRED_DELETE, &ip->i_flags); d_prune_aliases(&ip->i_inode); @@ -991,14 +963,14 @@ static bool gfs2_try_evict(struct gfs2_glock *gl) spin_lock(&gl->gl_lockref.lock); ip = gl->gl_object; if (ip) { - inode_gl = ip->i_gl; - lockref_get(&inode_gl->gl_lockref); clear_bit(GIF_DEFERRED_DELETE, &ip->i_flags); + if (!igrab(&ip->i_inode)) + ip = NULL; } spin_unlock(&gl->gl_lockref.lock); - if (inode_gl) { - gfs2_glock_poke(inode_gl); - gfs2_glock_put(inode_gl); + if (ip) { + gfs2_glock_poke(ip->i_gl); + iput(&ip->i_inode); } evicted = !ip; } @@ -1039,6 +1011,7 @@ static void delete_work_func(struct work_struct *work) if (gfs2_queue_delete_work(gl, 5 * HZ)) return; } + goto out; } inode = gfs2_lookup_by_inum(sdp, no_addr, gl->gl_no_formal_ino, @@ -1051,6 +1024,7 @@ static void delete_work_func(struct work_struct *work) d_prune_aliases(inode); iput(inode); } +out: gfs2_glock_put(gl); } @@ -1256,13 +1230,12 @@ void __gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, u16 flags, struct gfs2_holder *gh, unsigned long ip) { INIT_LIST_HEAD(&gh->gh_list); - gh->gh_gl = gl; + gh->gh_gl = gfs2_glock_hold(gl); gh->gh_ip = ip; gh->gh_owner_pid = get_pid(task_pid(current)); gh->gh_state = state; gh->gh_flags = flags; gh->gh_iflags = 0; - gfs2_glock_hold(gl); } /** @@ -1496,7 +1469,7 @@ __acquires(&gl->gl_lockref.lock) if (test_bit(GLF_LOCK, &gl->gl_flags)) { struct gfs2_holder *current_gh; - current_gh = find_first_strong_holder(gl); + current_gh = find_first_holder(gl); try_futile = !may_grant(gl, current_gh, gh); } if (test_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags)) @@ -1508,8 +1481,6 @@ __acquires(&gl->gl_lockref.lock) continue; if (gh->gh_gl->gl_ops->go_type == LM_TYPE_FLOCK) continue; - if (test_bit(HIF_MAY_DEMOTE, &gh2->gh_iflags)) - continue; if (!pid_is_meaningful(gh2)) continue; goto trap_recursive; @@ -1619,69 +1590,28 @@ static inline bool needs_demote(struct gfs2_glock *gl) static void __gfs2_glock_dq(struct gfs2_holder *gh) { struct gfs2_glock *gl = gh->gh_gl; - struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; unsigned delay = 0; int fast_path = 0; /* - * This while loop is similar to function demote_incompat_holders: - * If the glock is due to be demoted (which may be from another node - * or even if this holder is GL_NOCACHE), the weak holders are - * demoted as well, allowing the glock to be demoted. + * This holder should not be cached, so mark it for demote. + * Note: this should be done before the check for needs_demote + * below. */ - while (gh) { - /* - * If we're in the process of file system withdraw, we cannot - * just dequeue any glocks until our journal is recovered, lest - * we introduce file system corruption. We need two exceptions - * to this rule: We need to allow unlocking of nondisk glocks - * and the glock for our own journal that needs recovery. - */ - if (test_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags) && - glock_blocked_by_withdraw(gl) && - gh->gh_gl != sdp->sd_jinode_gl) { - sdp->sd_glock_dqs_held++; - spin_unlock(&gl->gl_lockref.lock); - might_sleep(); - wait_on_bit(&sdp->sd_flags, SDF_WITHDRAW_RECOVERY, - TASK_UNINTERRUPTIBLE); - spin_lock(&gl->gl_lockref.lock); - } + if (gh->gh_flags & GL_NOCACHE) + handle_callback(gl, LM_ST_UNLOCKED, 0, false); - /* - * This holder should not be cached, so mark it for demote. - * Note: this should be done before the check for needs_demote - * below. - */ - if (gh->gh_flags & GL_NOCACHE) - handle_callback(gl, LM_ST_UNLOCKED, 0, false); - - list_del_init(&gh->gh_list); - clear_bit(HIF_HOLDER, &gh->gh_iflags); - trace_gfs2_glock_queue(gh, 0); + list_del_init(&gh->gh_list); + clear_bit(HIF_HOLDER, &gh->gh_iflags); + trace_gfs2_glock_queue(gh, 0); - /* - * If there hasn't been a demote request we are done. - * (Let the remaining holders, if any, keep holding it.) - */ - if (!needs_demote(gl)) { - if (list_empty(&gl->gl_holders)) - fast_path = 1; - break; - } - /* - * If we have another strong holder (we cannot auto-demote) - * we are done. It keeps holding it until it is done. - */ - if (find_first_strong_holder(gl)) - break; - - /* - * If we have a weak holder at the head of the list, it - * (and all others like it) must be auto-demoted. If there - * are no more weak holders, we exit the while loop. - */ - gh = find_first_holder(gl); + /* + * If there hasn't been a demote request we are done. + * (Let the remaining holders, if any, keep holding it.) + */ + if (!needs_demote(gl)) { + if (list_empty(&gl->gl_holders)) + fast_path = 1; } if (!test_bit(GLF_LFLUSH, &gl->gl_flags) && demote_ok(gl)) @@ -1705,8 +1635,17 @@ static void __gfs2_glock_dq(struct gfs2_holder *gh) void gfs2_glock_dq(struct gfs2_holder *gh) { struct gfs2_glock *gl = gh->gh_gl; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; spin_lock(&gl->gl_lockref.lock); + if (!gfs2_holder_queued(gh)) { + /* + * May have already been dequeued because the locking request + * was GL_ASYNC and it has failed in the meantime. + */ + goto out; + } + if (list_is_first(&gh->gh_list, &gl->gl_holders) && !test_bit(HIF_HOLDER, &gh->gh_iflags)) { spin_unlock(&gl->gl_lockref.lock); @@ -1715,7 +1654,26 @@ void gfs2_glock_dq(struct gfs2_holder *gh) spin_lock(&gl->gl_lockref.lock); } + /* + * If we're in the process of file system withdraw, we cannot just + * dequeue any glocks until our journal is recovered, lest we introduce + * file system corruption. We need two exceptions to this rule: We need + * to allow unlocking of nondisk glocks and the glock for our own + * journal that needs recovery. + */ + if (test_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags) && + glock_blocked_by_withdraw(gl) && + gh->gh_gl != sdp->sd_jinode_gl) { + sdp->sd_glock_dqs_held++; + spin_unlock(&gl->gl_lockref.lock); + might_sleep(); + wait_on_bit(&sdp->sd_flags, SDF_WITHDRAW_RECOVERY, + TASK_UNINTERRUPTIBLE); + spin_lock(&gl->gl_lockref.lock); + } + __gfs2_glock_dq(gh); +out: spin_unlock(&gl->gl_lockref.lock); } @@ -1888,33 +1846,6 @@ void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state) if (test_bit(GLF_REPLY_PENDING, &gl->gl_flags)) delay = gl->gl_hold_time; } - /* - * Note 1: We cannot call demote_incompat_holders from handle_callback - * or gfs2_set_demote due to recursion problems like: gfs2_glock_dq -> - * handle_callback -> demote_incompat_holders -> gfs2_glock_dq - * Plus, we only want to demote the holders if the request comes from - * a remote cluster node because local holder conflicts are resolved - * elsewhere. - * - * Note 2: if a remote node wants this glock in EX mode, lock_dlm will - * request that we set our state to UNLOCKED. Here we mock up a holder - * to make it look like someone wants the lock EX locally. Any SH - * and DF requests should be able to share the lock without demoting. - * - * Note 3: We only want to demote the demoteable holders when there - * are no more strong holders. The demoteable holders might as well - * keep the glock until the last strong holder is done with it. - */ - if (!find_first_strong_holder(gl)) { - struct gfs2_holder mock_gh = { - .gh_gl = gl, - .gh_state = (state == LM_ST_UNLOCKED) ? - LM_ST_EXCLUSIVE : state, - .gh_iflags = BIT(HIF_HOLDER) - }; - - demote_incompat_holders(gl, &mock_gh); - } handle_callback(gl, state, delay, true); __gfs2_glock_queue_work(gl, delay); spin_unlock(&gl->gl_lockref.lock); @@ -2306,8 +2237,6 @@ static const char *hflags2str(char *buf, u16 flags, unsigned long iflags) *p++ = 'H'; if (test_bit(HIF_WAIT, &iflags)) *p++ = 'W'; - if (test_bit(HIF_MAY_DEMOTE, &iflags)) - *p++ = 'D'; if (flags & GL_SKIP) *p++ = 's'; *p = 0; diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 0d068f4fd7d673..f37ac087e2c14f 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -156,8 +156,6 @@ static inline struct gfs2_holder *gfs2_glock_is_locked_by_me(struct gfs2_glock * list_for_each_entry(gh, &gl->gl_holders, gh_list) { if (!test_bit(HIF_HOLDER, &gh->gh_iflags)) break; - if (test_bit(HIF_MAY_DEMOTE, &gh->gh_iflags)) - continue; if (gh->gh_owner_pid == pid) goto out; } @@ -196,7 +194,7 @@ static inline struct address_space *gfs2_glock2aspace(struct gfs2_glock *gl) extern int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, const struct gfs2_glock_operations *glops, int create, struct gfs2_glock **glp); -extern void gfs2_glock_hold(struct gfs2_glock *gl); +extern struct gfs2_glock *gfs2_glock_hold(struct gfs2_glock *gl); extern void gfs2_glock_put(struct gfs2_glock *gl); extern void gfs2_glock_queue_put(struct gfs2_glock *gl); @@ -288,6 +286,9 @@ extern void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp); extern void gfs2_register_debugfs(void); extern void gfs2_unregister_debugfs(void); +extern void glock_set_object(struct gfs2_glock *gl, void *object); +extern void glock_clear_object(struct gfs2_glock *gl, void *object); + extern const struct lm_lockops gfs2_dlm_ops; static inline void gfs2_holder_mark_uninitialized(struct gfs2_holder *gh) @@ -305,64 +306,6 @@ static inline bool gfs2_holder_queued(struct gfs2_holder *gh) return !list_empty(&gh->gh_list); } -/** - * glock_set_object - set the gl_object field of a glock - * @gl: the glock - * @object: the object - */ -static inline void glock_set_object(struct gfs2_glock *gl, void *object) -{ - spin_lock(&gl->gl_lockref.lock); - if (gfs2_assert_warn(gl->gl_name.ln_sbd, gl->gl_object == NULL)) - gfs2_dump_glock(NULL, gl, true); - gl->gl_object = object; - spin_unlock(&gl->gl_lockref.lock); -} - -/** - * glock_clear_object - clear the gl_object field of a glock - * @gl: the glock - * @object: the object - * - * I'd love to similarly add this: - * else if (gfs2_assert_warn(gl->gl_sbd, gl->gl_object == object)) - * gfs2_dump_glock(NULL, gl, true); - * Unfortunately, that's not possible because as soon as gfs2_delete_inode - * frees the block in the rgrp, another process can reassign it for an I_NEW - * inode in gfs2_create_inode because that calls new_inode, not gfs2_iget. - * That means gfs2_delete_inode may subsequently try to call this function - * for a glock that's already pointing to a brand new inode. If we clear the - * new inode's gl_object, we'll introduce metadata corruption. Function - * gfs2_delete_inode calls clear_inode which calls gfs2_clear_inode which also - * tries to clear gl_object, so it's more than just gfs2_delete_inode. - * - */ -static inline void glock_clear_object(struct gfs2_glock *gl, void *object) -{ - spin_lock(&gl->gl_lockref.lock); - if (gl->gl_object == object) - gl->gl_object = NULL; - spin_unlock(&gl->gl_lockref.lock); -} - -static inline void gfs2_holder_allow_demote(struct gfs2_holder *gh) -{ - struct gfs2_glock *gl = gh->gh_gl; - - spin_lock(&gl->gl_lockref.lock); - set_bit(HIF_MAY_DEMOTE, &gh->gh_iflags); - spin_unlock(&gl->gl_lockref.lock); -} - -static inline void gfs2_holder_disallow_demote(struct gfs2_holder *gh) -{ - struct gfs2_glock *gl = gh->gh_gl; - - spin_lock(&gl->gl_lockref.lock); - clear_bit(HIF_MAY_DEMOTE, &gh->gh_iflags); - spin_unlock(&gl->gl_lockref.lock); -} - extern void gfs2_inode_remember_delete(struct gfs2_glock *gl, u64 generation); extern bool gfs2_inode_already_deleted(struct gfs2_glock *gl, u64 generation); diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 49210a2e7ce753..d78b61ecc1cdf9 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -397,38 +397,39 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) struct timespec64 atime; u16 height, depth; umode_t mode = be32_to_cpu(str->di_mode); - bool is_new = ip->i_inode.i_state & I_NEW; + struct inode *inode = &ip->i_inode; + bool is_new = inode->i_state & I_NEW; if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr))) goto corrupt; - if (unlikely(!is_new && inode_wrong_type(&ip->i_inode, mode))) + if (unlikely(!is_new && inode_wrong_type(inode, mode))) goto corrupt; ip->i_no_formal_ino = be64_to_cpu(str->di_num.no_formal_ino); - ip->i_inode.i_mode = mode; + inode->i_mode = mode; if (is_new) { - ip->i_inode.i_rdev = 0; + inode->i_rdev = 0; switch (mode & S_IFMT) { case S_IFBLK: case S_IFCHR: - ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major), - be32_to_cpu(str->di_minor)); + inode->i_rdev = MKDEV(be32_to_cpu(str->di_major), + be32_to_cpu(str->di_minor)); break; } } - i_uid_write(&ip->i_inode, be32_to_cpu(str->di_uid)); - i_gid_write(&ip->i_inode, be32_to_cpu(str->di_gid)); - set_nlink(&ip->i_inode, be32_to_cpu(str->di_nlink)); - i_size_write(&ip->i_inode, be64_to_cpu(str->di_size)); - gfs2_set_inode_blocks(&ip->i_inode, be64_to_cpu(str->di_blocks)); + i_uid_write(inode, be32_to_cpu(str->di_uid)); + i_gid_write(inode, be32_to_cpu(str->di_gid)); + set_nlink(inode, be32_to_cpu(str->di_nlink)); + i_size_write(inode, be64_to_cpu(str->di_size)); + gfs2_set_inode_blocks(inode, be64_to_cpu(str->di_blocks)); atime.tv_sec = be64_to_cpu(str->di_atime); atime.tv_nsec = be32_to_cpu(str->di_atime_nsec); - if (timespec64_compare(&ip->i_inode.i_atime, &atime) < 0) - ip->i_inode.i_atime = atime; - ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime); - ip->i_inode.i_mtime.tv_nsec = be32_to_cpu(str->di_mtime_nsec); - ip->i_inode.i_ctime.tv_sec = be64_to_cpu(str->di_ctime); - ip->i_inode.i_ctime.tv_nsec = be32_to_cpu(str->di_ctime_nsec); + if (timespec64_compare(&inode->i_atime, &atime) < 0) + inode->i_atime = atime; + inode->i_mtime.tv_sec = be64_to_cpu(str->di_mtime); + inode->i_mtime.tv_nsec = be32_to_cpu(str->di_mtime_nsec); + inode->i_ctime.tv_sec = be64_to_cpu(str->di_ctime); + inode->i_ctime.tv_nsec = be32_to_cpu(str->di_ctime_nsec); ip->i_goal = be64_to_cpu(str->di_goal_meta); ip->i_generation = be64_to_cpu(str->di_generation); @@ -436,7 +437,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) ip->i_diskflags = be32_to_cpu(str->di_flags); ip->i_eattr = be64_to_cpu(str->di_eattr); /* i_diskflags and i_eattr must be set before gfs2_set_inode_flags() */ - gfs2_set_inode_flags(&ip->i_inode); + gfs2_set_inode_flags(inode); height = be16_to_cpu(str->di_height); if (unlikely(height > GFS2_MAX_META_HEIGHT)) goto corrupt; @@ -448,8 +449,11 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) ip->i_depth = (u8)depth; ip->i_entries = be32_to_cpu(str->di_entries); - if (S_ISREG(ip->i_inode.i_mode)) - gfs2_set_aops(&ip->i_inode); + if (gfs2_is_stuffed(ip) && inode->i_size > gfs2_max_stuffed_size(ip)) + goto corrupt; + + if (S_ISREG(inode->i_mode)) + gfs2_set_aops(inode); return 0; corrupt: diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index d09d9892cd055b..c26765080f280c 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -252,7 +252,6 @@ struct gfs2_lkstats { enum { /* States */ - HIF_MAY_DEMOTE = 1, HIF_HOLDER = 6, /* Set for gh that "holds" the glock */ HIF_WAIT = 10, }; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 1371e067d2a7cd..614db3055c024f 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -142,6 +142,11 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, if (unlikely(error)) goto fail; + /* + * The only caller that sets @blktype to GFS2_BLKST_UNLINKED is + * delete_work_func(). Make sure not to cancel the delete work + * from within itself here. + */ if (blktype == GFS2_BLKST_UNLINKED) extra_flags |= LM_FLAG_TRY; else @@ -403,12 +408,17 @@ static int alloc_dinode(struct gfs2_inode *ip, u32 flags, unsigned *dblocks) goto out_ipreserv; error = gfs2_alloc_blocks(ip, &ip->i_no_addr, dblocks, 1, &ip->i_generation); + if (error) + goto out_trans_end; + ip->i_no_formal_ino = ip->i_generation; ip->i_inode.i_ino = ip->i_no_addr; ip->i_goal = ip->i_no_addr; + if (*dblocks > 1) + ip->i_eattr = ip->i_no_addr + 1; +out_trans_end: gfs2_trans_end(sdp); - out_ipreserv: gfs2_inplace_release(ip); out_quota: @@ -586,6 +596,12 @@ static int gfs2_initxattrs(struct inode *inode, const struct xattr *xattr_array, * @size: The initial size of the inode (ignored for directories) * @excl: Force fail if inode exists * + * FIXME: Change to allocate the disk blocks and write them out in the same + * transaction. That way, we can no longer end up in a situation in which an + * inode is allocated, the node crashes, and the block looks like a valid + * inode. (With atomic creates in place, we will also no longer need to zero + * the link count and dirty the inode here on failure.) + * * Returns: 0 on success, or error code */ @@ -596,12 +612,12 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, { const struct qstr *name = &dentry->d_name; struct posix_acl *default_acl, *acl; - struct gfs2_holder ghs[2]; + struct gfs2_holder d_gh, gh; struct inode *inode = NULL; struct gfs2_inode *dip = GFS2_I(dir), *ip; struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_glock *io_gl; - int error, free_vfs_inode = 1; + int error; u32 aflags = 0; unsigned blocks = 1; struct gfs2_diradd da = { .bh = NULL, .save_loc = 1, }; @@ -617,10 +633,10 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, if (error) goto fail; - error = gfs2_glock_nq_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); + error = gfs2_glock_nq_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, &d_gh); if (error) goto fail; - gfs2_holder_mark_uninitialized(ghs + 1); + gfs2_holder_mark_uninitialized(&gh); error = create_ok(dip, name, mode); if (error) @@ -642,7 +658,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, else error = finish_no_open(file, NULL); } - gfs2_glock_dq_uninit(ghs); + gfs2_glock_dq_uninit(&d_gh); goto fail; } else if (error != -ENOENT) { goto fail_gunlock; @@ -656,12 +672,12 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, error = -ENOMEM; if (!inode) goto fail_gunlock; + ip = GFS2_I(inode); error = posix_acl_create(dir, &mode, &default_acl, &acl); if (error) goto fail_gunlock; - ip = GFS2_I(inode); error = gfs2_qa_get(ip); if (error) goto fail_free_acls; @@ -723,15 +739,19 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, goto fail_free_inode; gfs2_cancel_delete_work(io_gl); +retry: error = insert_inode_locked4(inode, ip->i_no_addr, iget_test, &ip->i_no_addr); - BUG_ON(error); + if (error == -EBUSY) + goto retry; + if (error) + goto fail_gunlock2; error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT | GL_NOPID, &ip->i_iopen_gh); if (error) goto fail_gunlock2; - error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1); + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, &gh); if (error) goto fail_gunlock3; @@ -739,10 +759,8 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, if (error) goto fail_gunlock3; - if (blocks > 1) { - ip->i_eattr = ip->i_no_addr + 1; + if (blocks > 1) gfs2_init_xattr(ip); - } init_dinode(dip, ip, symname); gfs2_trans_end(sdp); @@ -750,9 +768,6 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, glock_set_object(io_gl, ip); gfs2_set_iop(inode); - free_vfs_inode = 0; /* After this point, the inode is no longer - considered free. Any failures need to undo - the gfs2 structures. */ if (default_acl) { error = __gfs2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); if (error) @@ -785,9 +800,9 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, file->f_mode |= FMODE_CREATED; error = finish_open(file, dentry, gfs2_open_common); } - gfs2_glock_dq_uninit(ghs); + gfs2_glock_dq_uninit(&d_gh); gfs2_qa_put(ip); - gfs2_glock_dq_uninit(ghs + 1); + gfs2_glock_dq_uninit(&gh); gfs2_glock_put(io_gl); gfs2_qa_put(dip); unlock_new_inode(inode); @@ -801,10 +816,6 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, fail_gunlock2: gfs2_glock_put(io_gl); fail_free_inode: - if (ip->i_gl) { - if (free_vfs_inode) /* else evict will do the put for us */ - gfs2_glock_put(ip->i_gl); - } gfs2_rs_deltree(&ip->i_res); gfs2_qa_put(ip); fail_free_acls: @@ -812,20 +823,19 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, posix_acl_release(acl); fail_gunlock: gfs2_dir_no_add(&da); - gfs2_glock_dq_uninit(ghs); + gfs2_glock_dq_uninit(&d_gh); if (!IS_ERR_OR_NULL(inode)) { + set_bit(GIF_ALLOC_FAILED, &ip->i_flags); clear_nlink(inode); - if (!free_vfs_inode) + if (ip->i_no_addr) mark_inode_dirty(inode); - set_bit(free_vfs_inode ? GIF_FREE_VFS_INODE : GIF_ALLOC_FAILED, - &GFS2_I(inode)->i_flags); if (inode->i_state & I_NEW) iget_failed(inode); else iput(inode); } - if (gfs2_holder_initialized(ghs + 1)) - gfs2_glock_dq_uninit(ghs + 1); + if (gfs2_holder_initialized(&gh)) + gfs2_glock_dq_uninit(&gh); fail: gfs2_qa_put(dip); return error; diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 6ed728aae9a539..3c41b864ee5bc9 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -442,6 +442,12 @@ void gfs2_journal_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen) struct buffer_head *bh; int ty; + if (!ip->i_gl) { + /* This can only happen during incomplete inode creation. */ + BUG_ON(!test_bit(GIF_ALLOC_FAILED, &ip->i_flags)); + return; + } + gfs2_ail1_wipe(sdp, bstart, blen); while (blen) { ty = REMOVE_META; diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index b018957a1bb244..999cc146d70834 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -379,6 +379,7 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp) void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) { + const struct inode *inode = &ip->i_inode; struct gfs2_dinode *str = buf; str->di_header.mh_magic = cpu_to_be32(GFS2_MAGIC); @@ -386,15 +387,15 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) str->di_header.mh_format = cpu_to_be32(GFS2_FORMAT_DI); str->di_num.no_addr = cpu_to_be64(ip->i_no_addr); str->di_num.no_formal_ino = cpu_to_be64(ip->i_no_formal_ino); - str->di_mode = cpu_to_be32(ip->i_inode.i_mode); - str->di_uid = cpu_to_be32(i_uid_read(&ip->i_inode)); - str->di_gid = cpu_to_be32(i_gid_read(&ip->i_inode)); - str->di_nlink = cpu_to_be32(ip->i_inode.i_nlink); - str->di_size = cpu_to_be64(i_size_read(&ip->i_inode)); - str->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode)); - str->di_atime = cpu_to_be64(ip->i_inode.i_atime.tv_sec); - str->di_mtime = cpu_to_be64(ip->i_inode.i_mtime.tv_sec); - str->di_ctime = cpu_to_be64(ip->i_inode.i_ctime.tv_sec); + str->di_mode = cpu_to_be32(inode->i_mode); + str->di_uid = cpu_to_be32(i_uid_read(inode)); + str->di_gid = cpu_to_be32(i_gid_read(inode)); + str->di_nlink = cpu_to_be32(inode->i_nlink); + str->di_size = cpu_to_be64(i_size_read(inode)); + str->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(inode)); + str->di_atime = cpu_to_be64(inode->i_atime.tv_sec); + str->di_mtime = cpu_to_be64(inode->i_mtime.tv_sec); + str->di_ctime = cpu_to_be64(inode->i_ctime.tv_sec); str->di_goal_meta = cpu_to_be64(ip->i_goal); str->di_goal_data = cpu_to_be64(ip->i_goal); @@ -402,16 +403,16 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) str->di_flags = cpu_to_be32(ip->i_diskflags); str->di_height = cpu_to_be16(ip->i_height); - str->di_payload_format = cpu_to_be32(S_ISDIR(ip->i_inode.i_mode) && + str->di_payload_format = cpu_to_be32(S_ISDIR(inode->i_mode) && !(ip->i_diskflags & GFS2_DIF_EXHASH) ? GFS2_FORMAT_DE : 0); str->di_depth = cpu_to_be16(ip->i_depth); str->di_entries = cpu_to_be32(ip->i_entries); str->di_eattr = cpu_to_be64(ip->i_eattr); - str->di_atime_nsec = cpu_to_be32(ip->i_inode.i_atime.tv_nsec); - str->di_mtime_nsec = cpu_to_be32(ip->i_inode.i_mtime.tv_nsec); - str->di_ctime_nsec = cpu_to_be32(ip->i_inode.i_ctime.tv_nsec); + str->di_atime_nsec = cpu_to_be32(inode->i_atime.tv_nsec); + str->di_mtime_nsec = cpu_to_be32(inode->i_mtime.tv_nsec); + str->di_ctime_nsec = cpu_to_be32(inode->i_ctime.tv_nsec); } /** @@ -475,6 +476,12 @@ static void gfs2_dirty_inode(struct inode *inode, int flags) int need_endtrans = 0; int ret; + if (unlikely(!ip->i_gl)) { + /* This can only happen during incomplete inode creation. */ + BUG_ON(!test_bit(GIF_ALLOC_FAILED, &ip->i_flags)); + return; + } + if (unlikely(gfs2_withdrawn(sdp))) return; if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { @@ -927,8 +934,7 @@ static int gfs2_drop_inode(struct inode *inode) { struct gfs2_inode *ip = GFS2_I(inode); - if (!test_bit(GIF_FREE_VFS_INODE, &ip->i_flags) && - inode->i_nlink && + if (inode->i_nlink && gfs2_holder_initialized(&ip->i_iopen_gh)) { struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl; if (test_bit(GLF_DEMOTE, &gl->gl_flags)) @@ -1076,7 +1082,13 @@ static void gfs2_final_release_pages(struct gfs2_inode *ip) struct inode *inode = &ip->i_inode; struct gfs2_glock *gl = ip->i_gl; - truncate_inode_pages(gfs2_glock2aspace(ip->i_gl), 0); + if (unlikely(!gl)) { + /* This can only happen during incomplete inode creation. */ + BUG_ON(!test_bit(GIF_ALLOC_FAILED, &ip->i_flags)); + return; + } + + truncate_inode_pages(gfs2_glock2aspace(gl), 0); truncate_inode_pages(&inode->i_data, 0); if (atomic_read(&gl->gl_revokes) == 0) { @@ -1218,10 +1230,8 @@ static enum dinode_demise evict_should_delete(struct inode *inode, struct gfs2_sbd *sdp = sb->s_fs_info; int ret; - if (test_bit(GIF_ALLOC_FAILED, &ip->i_flags)) { - BUG_ON(!gfs2_glock_is_locked_by_me(ip->i_gl)); + if (unlikely(test_bit(GIF_ALLOC_FAILED, &ip->i_flags))) goto should_delete; - } if (test_bit(GIF_DEFERRED_DELETE, &ip->i_flags)) return SHOULD_DEFER_EVICTION; @@ -1294,13 +1304,22 @@ static int evict_unlinked_inode(struct inode *inode) goto out; } - /* We're about to clear the bitmap for the dinode, but as soon as we - do, gfs2_create_inode can create another inode at the same block - location and try to set gl_object again. We clear gl_object here so - that subsequent inode creates don't see an old gl_object. */ - glock_clear_object(ip->i_gl, ip); + if (ip->i_gl) + gfs2_inode_remember_delete(ip->i_gl, ip->i_no_formal_ino); + + /* + * As soon as we clear the bitmap for the dinode, gfs2_create_inode() + * can get called to recreate it, or even gfs2_inode_lookup() if the + * inode was recreated on another node in the meantime. + * + * However, inserting the new inode into the inode hash table will not + * succeed until the old inode is removed, and that only happens after + * ->evict_inode() returns. The new inode is attached to its inode and + * iopen glocks after inserting it into the inode hash table, so at + * that point we can be sure that both glocks are unused. + */ + ret = gfs2_dinode_dealloc(ip); - gfs2_inode_remember_delete(ip->i_gl, ip->i_no_formal_ino); out: return ret; } @@ -1367,12 +1386,7 @@ static void gfs2_evict_inode(struct inode *inode) struct gfs2_holder gh; int ret; - if (test_bit(GIF_FREE_VFS_INODE, &ip->i_flags)) { - clear_inode(inode); - return; - } - - if (inode->i_nlink || sb_rdonly(sb)) + if (inode->i_nlink || sb_rdonly(sb) || !ip->i_no_addr) goto out; gfs2_holder_mark_uninitialized(&gh); @@ -1405,12 +1419,9 @@ static void gfs2_evict_inode(struct inode *inode) struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl; glock_clear_object(gl, ip); - if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) { - ip->i_iopen_gh.gh_flags |= GL_NOCACHE; - gfs2_glock_dq(&ip->i_iopen_gh); - } gfs2_glock_hold(gl); - gfs2_holder_uninit(&ip->i_iopen_gh); + ip->i_iopen_gh.gh_flags |= GL_NOCACHE; + gfs2_glock_dq_uninit(&ip->i_iopen_gh); gfs2_glock_put_eventually(gl); } if (ip->i_gl) { @@ -1429,6 +1440,7 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb) ip = alloc_inode_sb(sb, gfs2_inode_cachep, GFP_KERNEL); if (!ip) return NULL; + ip->i_no_addr = 0; ip->i_flags = 0; ip->i_gl = NULL; gfs2_holder_mark_uninitialized(&ip->i_iopen_gh); diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index f6a66050380e9d..518c0677e12ae4 100644 --- a/fs/gfs2/xattr.c +++ b/fs/gfs2/xattr.c @@ -1412,11 +1412,13 @@ static int ea_dealloc_block(struct gfs2_inode *ip) ip->i_eattr = 0; gfs2_add_inode_blocks(&ip->i_inode, -1); - error = gfs2_meta_inode_buffer(ip, &dibh); - if (!error) { - gfs2_trans_add_meta(ip->i_gl, dibh); - gfs2_dinode_out(ip, dibh->b_data); - brelse(dibh); + if (likely(!test_bit(GIF_ALLOC_FAILED, &ip->i_flags))) { + error = gfs2_meta_inode_buffer(ip, &dibh); + if (!error) { + gfs2_trans_add_meta(ip->i_gl, dibh); + gfs2_dinode_out(ip, dibh->b_data); + brelse(dibh); + } } gfs2_trans_end(sdp); @@ -1445,14 +1447,16 @@ int gfs2_ea_dealloc(struct gfs2_inode *ip) if (error) return error; - error = ea_foreach(ip, ea_dealloc_unstuffed, NULL); - if (error) - goto out_quota; - - if (ip->i_diskflags & GFS2_DIF_EA_INDIRECT) { - error = ea_dealloc_indirect(ip); + if (likely(!test_bit(GIF_ALLOC_FAILED, &ip->i_flags))) { + error = ea_foreach(ip, ea_dealloc_unstuffed, NULL); if (error) goto out_quota; + + if (ip->i_diskflags & GFS2_DIF_EA_INDIRECT) { + error = ea_dealloc_indirect(ip); + if (error) + goto out_quota; + } } error = ea_dealloc_block(ip); diff --git a/include/dt-bindings/reset/mt8188-resets.h b/include/dt-bindings/reset/mt8188-resets.h new file mode 100644 index 00000000000000..377cdfda82a983 --- /dev/null +++ b/include/dt-bindings/reset/mt8188-resets.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)*/ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Runyang Chen + */ + +#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT8188 +#define _DT_BINDINGS_RESET_CONTROLLER_MT8188 + +#define MT8188_TOPRGU_CONN_MCU_SW_RST 0 +#define MT8188_TOPRGU_INFRA_GRST_SW_RST 1 +#define MT8188_TOPRGU_IPU0_SW_RST 2 +#define MT8188_TOPRGU_IPU1_SW_RST 3 +#define MT8188_TOPRGU_IPU2_SW_RST 4 +#define MT8188_TOPRGU_AUD_ASRC_SW_RST 5 +#define MT8188_TOPRGU_INFRA_SW_RST 6 +#define MT8188_TOPRGU_MMSYS_SW_RST 7 +#define MT8188_TOPRGU_MFG_SW_RST 8 +#define MT8188_TOPRGU_VENC_SW_RST 9 +#define MT8188_TOPRGU_VDEC_SW_RST 10 +#define MT8188_TOPRGU_CAM_VCORE_SW_RST 11 +#define MT8188_TOPRGU_SCP_SW_RST 12 +#define MT8188_TOPRGU_APMIXEDSYS_SW_RST 13 +#define MT8188_TOPRGU_AUDIO_SW_RST 14 +#define MT8188_TOPRGU_CAMSYS_SW_RST 15 +#define MT8188_TOPRGU_MJC_SW_RST 16 +#define MT8188_TOPRGU_PERI_SW_RST 17 +#define MT8188_TOPRGU_PERI_AO_SW_RST 18 +#define MT8188_TOPRGU_PCIE_SW_RST 19 +#define MT8188_TOPRGU_ADSPSYS_SW_RST 21 +#define MT8188_TOPRGU_DPTX_SW_RST 22 +#define MT8188_TOPRGU_SPMI_MST_SW_RST 23 + +#define MT8188_TOPRGU_SW_RST_NUM 24 + +#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT8188 */ diff --git a/include/linux/mfd/rn5t618.h b/include/linux/mfd/rn5t618.h index 8aa0bda1af4fa2..aacb6d51e99cba 100644 --- a/include/linux/mfd/rn5t618.h +++ b/include/linux/mfd/rn5t618.h @@ -227,6 +227,15 @@ #define RN5T618_WATCHDOG_WDOGTIM_S 0 #define RN5T618_PWRIRQ_IR_WDOG BIT(6) +#define RN5T618_POFFHIS_PWRON BIT(0) +#define RN5T618_POFFHIS_TSHUT BIT(1) +#define RN5T618_POFFHIS_VINDET BIT(2) +#define RN5T618_POFFHIS_IODET BIT(3) +#define RN5T618_POFFHIS_CPU BIT(4) +#define RN5T618_POFFHIS_WDG BIT(5) +#define RN5T618_POFFHIS_DCLIM BIT(6) +#define RN5T618_POFFHIS_N_OE BIT(7) + enum { RN5T618_DCDC1, RN5T618_DCDC2, diff --git a/include/uapi/linux/hsi/cs-protocol.h b/include/uapi/linux/hsi/cs-protocol.h index c7f6e7672cb597..07c3bfb6746375 100644 --- a/include/uapi/linux/hsi/cs-protocol.h +++ b/include/uapi/linux/hsi/cs-protocol.h @@ -6,20 +6,6 @@ * * Contact: Kai Vehmanen * Original author: Peter Ujfalusi - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef _CS_PROTOCOL_H diff --git a/include/uapi/linux/hsi/hsi_char.h b/include/uapi/linux/hsi/hsi_char.h index 91623b0398b1b7..5ef72f0daf947b 100644 --- a/include/uapi/linux/hsi/hsi_char.h +++ b/include/uapi/linux/hsi/hsi_char.h @@ -5,20 +5,6 @@ * Copyright (C) 2010 Nokia Corporation. All rights reserved. * * Contact: Andras Domokos - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef __HSI_CHAR_H