* [PATCH v3 09/12] macintosh/via-pmu: Replace via-pmu68k driver with via-pmu driver
From: Finn Thain @ 2018-06-13 10:38 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Michael Schmitz, linuxppc-dev, linux-m68k, linux-kernel,
Geert Uytterhoeven
In-Reply-To: <cover.1528885172.git.fthain@telegraphics.com.au>
Now that the PowerMac via-pmu driver supports m68k PowerBooks,
switch over to that driver and remove the via-pmu68k driver.
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Tested-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
---
arch/m68k/configs/mac_defconfig | 2 +-
arch/m68k/configs/multi_defconfig | 2 +-
arch/m68k/mac/config.c | 2 +-
arch/m68k/mac/misc.c | 48 +--
drivers/macintosh/Kconfig | 13 +-
drivers/macintosh/Makefile | 1 -
drivers/macintosh/adb.c | 2 +-
drivers/macintosh/via-pmu68k.c | 846 --------------------------------------
include/uapi/linux/pmu.h | 2 +-
9 files changed, 14 insertions(+), 904 deletions(-)
delete mode 100644 drivers/macintosh/via-pmu68k.c
diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig
index 390d4a87441c..ee63f1242e9a 100644
--- a/arch/m68k/configs/mac_defconfig
+++ b/arch/m68k/configs/mac_defconfig
@@ -370,7 +370,7 @@ CONFIG_TCM_PSCSI=m
CONFIG_ADB=y
CONFIG_ADB_MACII=y
CONFIG_ADB_IOP=y
-CONFIG_ADB_PMU68K=y
+CONFIG_ADB_PMU=y
CONFIG_ADB_CUDA=y
CONFIG_INPUT_ADBHID=y
CONFIG_MAC_EMUMOUSEBTN=y
diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig
index 77be97d82dc3..6421a3da616c 100644
--- a/arch/m68k/configs/multi_defconfig
+++ b/arch/m68k/configs/multi_defconfig
@@ -403,7 +403,7 @@ CONFIG_TCM_PSCSI=m
CONFIG_ADB=y
CONFIG_ADB_MACII=y
CONFIG_ADB_IOP=y
-CONFIG_ADB_PMU68K=y
+CONFIG_ADB_PMU=y
CONFIG_ADB_CUDA=y
CONFIG_INPUT_ADBHID=y
CONFIG_MAC_EMUMOUSEBTN=y
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index e522307db47c..92e80cf0d8aa 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -891,7 +891,7 @@ static void __init mac_identify(void)
#ifdef CONFIG_ADB_CUDA
find_via_cuda();
#endif
-#ifdef CONFIG_ADB_PMU68K
+#ifdef CONFIG_ADB_PMU
find_via_pmu();
#endif
}
diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
index 7ccb799eeb57..28090a44fa09 100644
--- a/arch/m68k/mac/misc.c
+++ b/arch/m68k/mac/misc.c
@@ -85,7 +85,7 @@ static void cuda_write_pram(int offset, __u8 data)
}
#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU68K
+#ifdef CONFIG_ADB_PMU
static long pmu_read_time(void)
{
struct adb_request req;
@@ -136,7 +136,7 @@ static void pmu_write_pram(int offset, __u8 data)
while (!req.complete)
pmu_poll();
}
-#endif /* CONFIG_ADB_PMU68K */
+#endif /* CONFIG_ADB_PMU */
/*
* VIA PRAM/RTC access routines
@@ -367,38 +367,6 @@ static void cuda_shutdown(void)
}
#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU68K
-
-void pmu_restart(void)
-{
- struct adb_request req;
- if (pmu_request(&req, NULL,
- 2, PMU_SET_INTR_MASK, PMU_INT_ADB|PMU_INT_TICK) < 0)
- return;
- while (!req.complete)
- pmu_poll();
- if (pmu_request(&req, NULL, 1, PMU_RESET) < 0)
- return;
- while (!req.complete)
- pmu_poll();
-}
-
-void pmu_shutdown(void)
-{
- struct adb_request req;
- if (pmu_request(&req, NULL,
- 2, PMU_SET_INTR_MASK, PMU_INT_ADB|PMU_INT_TICK) < 0)
- return;
- while (!req.complete)
- pmu_poll();
- if (pmu_request(&req, NULL, 5, PMU_SHUTDOWN, 'M', 'A', 'T', 'T') < 0)
- return;
- while (!req.complete)
- pmu_poll();
-}
-
-#endif
-
/*
*-------------------------------------------------------------------
* Below this point are the generic routines; they'll dispatch to the
@@ -423,7 +391,7 @@ void mac_pram_read(int offset, __u8 *buffer, int len)
func = cuda_read_pram;
break;
#endif
-#ifdef CONFIG_ADB_PMU68K
+#ifdef CONFIG_ADB_PMU
case MAC_ADB_PB2:
func = pmu_read_pram;
break;
@@ -453,7 +421,7 @@ void mac_pram_write(int offset, __u8 *buffer, int len)
func = cuda_write_pram;
break;
#endif
-#ifdef CONFIG_ADB_PMU68K
+#ifdef CONFIG_ADB_PMU
case MAC_ADB_PB2:
func = pmu_write_pram;
break;
@@ -477,7 +445,7 @@ void mac_poweroff(void)
macintosh_config->adb_type == MAC_ADB_CUDA) {
cuda_shutdown();
#endif
-#ifdef CONFIG_ADB_PMU68K
+#ifdef CONFIG_ADB_PMU
} else if (macintosh_config->adb_type == MAC_ADB_PB2) {
pmu_shutdown();
#endif
@@ -518,7 +486,7 @@ void mac_reset(void)
macintosh_config->adb_type == MAC_ADB_CUDA) {
cuda_restart();
#endif
-#ifdef CONFIG_ADB_PMU68K
+#ifdef CONFIG_ADB_PMU
} else if (macintosh_config->adb_type == MAC_ADB_PB2) {
pmu_restart();
#endif
@@ -670,7 +638,7 @@ int mac_hwclk(int op, struct rtc_time *t)
now = cuda_read_time();
break;
#endif
-#ifdef CONFIG_ADB_PMU68K
+#ifdef CONFIG_ADB_PMU
case MAC_ADB_PB2:
now = pmu_read_time();
break;
@@ -706,7 +674,7 @@ int mac_hwclk(int op, struct rtc_time *t)
cuda_write_time(now);
break;
#endif
-#ifdef CONFIG_ADB_PMU68K
+#ifdef CONFIG_ADB_PMU
case MAC_ADB_PB2:
pmu_write_time(now);
break;
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 26abae4c899d..47c350cdfb12 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -39,17 +39,6 @@ config ADB_IOP
<http://www.angelfire.com/ca2/dev68k/iopdesc.html> to enable direct
support for it, say 'Y' here.
-config ADB_PMU68K
- bool "Include PMU (Powerbook) ADB driver"
- depends on ADB && MAC
- help
- Say Y here if want your kernel to support the m68k based Powerbooks.
- This includes the PowerBook 140, PowerBook 145, PowerBook 150,
- PowerBook 160, PowerBook 165, PowerBook 165c, PowerBook 170,
- PowerBook 180, PowerBook, 180c, PowerBook 190cs, PowerBook 520,
- PowerBook Duo 210, PowerBook Duo 230, PowerBook Duo 250,
- PowerBook Duo 270c, PowerBook Duo 280 and PowerBook Duo 280c.
-
# we want to change this to something like CONFIG_SYSCTRL_CUDA/PMU
config ADB_CUDA
bool "Support for Cuda/Egret based Macs and PowerMacs"
@@ -66,7 +55,7 @@ config ADB_CUDA
config ADB_PMU
bool "Support for PMU based PowerMacs and PowerBooks"
- depends on PPC_PMAC
+ depends on PPC_PMAC || MAC
help
On PowerBooks, iBooks, and recent iMacs and Power Macintoshes, the
PMU is an embedded microprocessor whose primary function is to
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index ee803638e595..49819b1b6f20 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -22,7 +22,6 @@ obj-$(CONFIG_PMAC_SMU) += smu.o
obj-$(CONFIG_ADB) += adb.o
obj-$(CONFIG_ADB_MACII) += via-macii.o
obj-$(CONFIG_ADB_IOP) += adb-iop.o
-obj-$(CONFIG_ADB_PMU68K) += via-pmu68k.o
obj-$(CONFIG_ADB_MACIO) += macio-adb.o
obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 4c8097e0e6fe..76e98f0f7a3e 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -65,7 +65,7 @@ static struct adb_driver *adb_driver_list[] = {
#ifdef CONFIG_ADB_IOP
&adb_iop_driver,
#endif
-#if defined(CONFIG_ADB_PMU) || defined(CONFIG_ADB_PMU68K)
+#ifdef CONFIG_ADB_PMU
&via_pmu_driver,
#endif
#ifdef CONFIG_ADB_MACIO
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c
deleted file mode 100644
index bec8e1837d7d..000000000000
--- a/drivers/macintosh/via-pmu68k.c
+++ /dev/null
@@ -1,846 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Device driver for the PMU on 68K-based Apple PowerBooks
- *
- * The VIA (versatile interface adapter) interfaces to the PMU,
- * a 6805 microprocessor core whose primary function is to control
- * battery charging and system power on the PowerBooks.
- * The PMU also controls the ADB (Apple Desktop Bus) which connects
- * to the keyboard and mouse, as well as the non-volatile RAM
- * and the RTC (real time clock) chip.
- *
- * Adapted for 68K PMU by Joshua M. Thompson
- *
- * Based largely on the PowerMac PMU code by Paul Mackerras and
- * Fabio Riccardi.
- *
- * Also based on the PMU driver from MkLinux by Apple Computer, Inc.
- * and the Open Software Foundation, Inc.
- */
-
-#include <stdarg.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/miscdevice.h>
-#include <linux/blkdev.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <linux/cuda.h>
-
-#include <asm/macintosh.h>
-#include <asm/macints.h>
-#include <asm/mac_via.h>
-
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <linux/uaccess.h>
-
-/* Misc minor number allocated for /dev/pmu */
-#define PMU_MINOR 154
-
-/* VIA registers - spaced 0x200 bytes apart */
-#define RS 0x200 /* skip between registers */
-#define B 0 /* B-side data */
-#define A RS /* A-side data */
-#define DIRB (2*RS) /* B-side direction (1=output) */
-#define DIRA (3*RS) /* A-side direction (1=output) */
-#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */
-#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */
-#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */
-#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */
-#define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */
-#define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */
-#define SR (10*RS) /* Shift register */
-#define ACR (11*RS) /* Auxiliary control register */
-#define PCR (12*RS) /* Peripheral control register */
-#define IFR (13*RS) /* Interrupt flag register */
-#define IER (14*RS) /* Interrupt enable register */
-#define ANH (15*RS) /* A-side data, no handshake */
-
-/* Bits in B data register: both active low */
-#define TACK 0x02 /* Transfer acknowledge (input) */
-#define TREQ 0x04 /* Transfer request (output) */
-
-/* Bits in ACR */
-#define SR_CTRL 0x1c /* Shift register control bits */
-#define SR_EXT 0x0c /* Shift on external clock */
-#define SR_OUT 0x10 /* Shift out if 1 */
-
-/* Bits in IFR and IER */
-#define SR_INT 0x04 /* Shift register full/empty */
-#define CB1_INT 0x10 /* transition on CB1 input */
-
-static enum pmu_state {
- idle,
- sending,
- intack,
- reading,
- reading_intr,
-} pmu_state;
-
-static struct adb_request *current_req;
-static struct adb_request *last_req;
-static struct adb_request *req_awaiting_reply;
-static unsigned char interrupt_data[32];
-static unsigned char *reply_ptr;
-static int data_index;
-static int data_len;
-static int adb_int_pending;
-static int pmu_adb_flags;
-static int adb_dev_map;
-static struct adb_request bright_req_1, bright_req_2, bright_req_3;
-static int pmu_kind = PMU_UNKNOWN;
-static int pmu_fully_inited;
-
-int asleep;
-
-static int pmu_probe(void);
-static int pmu_init(void);
-static void pmu_start(void);
-static irqreturn_t pmu_interrupt(int irq, void *arg);
-static int pmu_send_request(struct adb_request *req, int sync);
-static int pmu_autopoll(int devs);
-void pmu_poll(void);
-static int pmu_reset_bus(void);
-
-static int init_pmu(void);
-static void pmu_start(void);
-static void send_byte(int x);
-static void recv_byte(void);
-static void pmu_done(struct adb_request *req);
-static void pmu_handle_data(unsigned char *data, int len);
-static void set_volume(int level);
-static void pmu_enable_backlight(int on);
-static void pmu_set_brightness(int level);
-
-struct adb_driver via_pmu_driver = {
- .name = "68K PMU",
- .probe = pmu_probe,
- .init = pmu_init,
- .send_request = pmu_send_request,
- .autopoll = pmu_autopoll,
- .poll = pmu_poll,
- .reset_bus = pmu_reset_bus,
-};
-
-/*
- * This table indicates for each PMU opcode:
- * - the number of data bytes to be sent with the command, or -1
- * if a length byte should be sent,
- * - the number of response bytes which the PMU will return, or
- * -1 if it will send a length byte.
- */
-static s8 pmu_data_len[256][2] = {
-/* 0 1 2 3 4 5 6 7 */
-/*00*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*08*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
-/*10*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*18*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0},
-/*20*/ {-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*28*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0,-1},
-/*30*/ { 4, 0},{20, 0},{-1, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*38*/ { 0, 4},{ 0,20},{ 2,-1},{ 2, 1},{ 3,-1},{-1,-1},{-1,-1},{ 4, 0},
-/*40*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*48*/ { 0, 1},{ 0, 1},{-1,-1},{ 1, 0},{ 1, 0},{-1,-1},{-1,-1},{-1,-1},
-/*50*/ { 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0},
-/*58*/ { 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},
-/*60*/ { 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*68*/ { 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},
-/*70*/ { 1, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*78*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{ 5, 1},{ 4, 1},{ 4, 1},
-/*80*/ { 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*88*/ { 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
-/*90*/ { 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*98*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
-/*a0*/ { 2, 0},{ 2, 0},{ 2, 0},{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},
-/*a8*/ { 1, 1},{ 1, 0},{ 3, 0},{ 2, 0},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
-/*b0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*b8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
-/*c0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*c8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
-/*d0*/ { 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*d8*/ { 1, 1},{ 1, 1},{-1,-1},{-1,-1},{ 0, 1},{ 0,-1},{-1,-1},{-1,-1},
-/*e0*/ {-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{ 4, 0},{-1, 0},{-1, 0},
-/*e8*/ { 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0},
-/*f0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*f8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
-};
-
-int __init find_via_pmu(void)
-{
- switch (macintosh_config->adb_type) {
- case MAC_ADB_PB2:
- pmu_kind = PMU_68K_V2;
- break;
- default:
- pmu_kind = PMU_UNKNOWN;
- return -ENODEV;
- }
-
- pmu_state = idle;
-
- if (!init_pmu())
- goto fail_init;
-
- pr_info("adb: PMU 68K driver v0.5 for Unified ADB\n");
-
- return 1;
-
-fail_init:
- pmu_kind = PMU_UNKNOWN;
- return 0;
-}
-
-static int pmu_probe(void)
-{
- if (pmu_kind == PMU_UNKNOWN)
- return -ENODEV;
- return 0;
-}
-
-static int pmu_init(void)
-{
- if (pmu_kind == PMU_UNKNOWN)
- return -ENODEV;
- return 0;
-}
-
-static int __init via_pmu_start(void)
-{
- if (pmu_kind == PMU_UNKNOWN)
- return -ENODEV;
-
- if (request_irq(IRQ_MAC_ADB_SR, pmu_interrupt, 0, "PMU_SR",
- pmu_interrupt)) {
- pr_err("%s: can't get SR irq\n", __func__);
- return -ENODEV;
- }
- if (request_irq(IRQ_MAC_ADB_CL, pmu_interrupt, 0, "PMU_CL",
- pmu_interrupt)) {
- pr_err("%s: can't get CL irq\n", __func__);
- free_irq(IRQ_MAC_ADB_SR, pmu_interrupt);
- return -ENODEV;
- }
-
- pmu_fully_inited = 1;
-
- /* Enable backlight */
- pmu_enable_backlight(1);
-
- return 0;
-}
-
-arch_initcall(via_pmu_start);
-
-static int __init init_pmu(void)
-{
- int timeout;
- volatile struct adb_request req;
-
- via2[B] |= TREQ; /* negate TREQ */
- via2[DIRB] = (via2[DIRB] | TREQ) & ~TACK; /* TACK in, TREQ out */
-
- pmu_request((struct adb_request *) &req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB);
- timeout = 100000;
- while (!req.complete) {
- if (--timeout < 0) {
- printk(KERN_ERR "pmu_init: no response from PMU\n");
- return -EAGAIN;
- }
- udelay(10);
- pmu_poll();
- }
-
- /* ack all pending interrupts */
- timeout = 100000;
- interrupt_data[0] = 1;
- while (interrupt_data[0] || pmu_state != idle) {
- if (--timeout < 0) {
- printk(KERN_ERR "pmu_init: timed out acking intrs\n");
- return -EAGAIN;
- }
- if (pmu_state == idle) {
- adb_int_pending = 1;
- pmu_interrupt(0, NULL);
- }
- pmu_poll();
- udelay(10);
- }
-
- pmu_request((struct adb_request *) &req, NULL, 2, PMU_SET_INTR_MASK,
- PMU_INT_ADB_AUTO|PMU_INT_SNDBRT|PMU_INT_ADB);
- timeout = 100000;
- while (!req.complete) {
- if (--timeout < 0) {
- printk(KERN_ERR "pmu_init: no response from PMU\n");
- return -EAGAIN;
- }
- udelay(10);
- pmu_poll();
- }
-
- bright_req_1.complete = 1;
- bright_req_2.complete = 1;
- bright_req_3.complete = 1;
-
- return 1;
-}
-
-int
-pmu_get_model(void)
-{
- return pmu_kind;
-}
-
-/* Send an ADB command */
-static int
-pmu_send_request(struct adb_request *req, int sync)
-{
- int i, ret;
-
- if (!pmu_fully_inited)
- {
- req->complete = 1;
- return -ENXIO;
- }
-
- ret = -EINVAL;
-
- switch (req->data[0]) {
- case PMU_PACKET:
- for (i = 0; i < req->nbytes - 1; ++i)
- req->data[i] = req->data[i+1];
- --req->nbytes;
- if (pmu_data_len[req->data[0]][1] != 0) {
- req->reply[0] = ADB_RET_OK;
- req->reply_len = 1;
- } else
- req->reply_len = 0;
- ret = pmu_queue_request(req);
- break;
- case CUDA_PACKET:
- switch (req->data[1]) {
- case CUDA_GET_TIME:
- if (req->nbytes != 2)
- break;
- req->data[0] = PMU_READ_RTC;
- req->nbytes = 1;
- req->reply_len = 3;
- req->reply[0] = CUDA_PACKET;
- req->reply[1] = 0;
- req->reply[2] = CUDA_GET_TIME;
- ret = pmu_queue_request(req);
- break;
- case CUDA_SET_TIME:
- if (req->nbytes != 6)
- break;
- req->data[0] = PMU_SET_RTC;
- req->nbytes = 5;
- for (i = 1; i <= 4; ++i)
- req->data[i] = req->data[i+1];
- req->reply_len = 3;
- req->reply[0] = CUDA_PACKET;
- req->reply[1] = 0;
- req->reply[2] = CUDA_SET_TIME;
- ret = pmu_queue_request(req);
- break;
- case CUDA_GET_PRAM:
- if (req->nbytes != 4)
- break;
- req->data[0] = PMU_READ_NVRAM;
- req->data[1] = req->data[2];
- req->data[2] = req->data[3];
- req->nbytes = 3;
- req->reply_len = 3;
- req->reply[0] = CUDA_PACKET;
- req->reply[1] = 0;
- req->reply[2] = CUDA_GET_PRAM;
- ret = pmu_queue_request(req);
- break;
- case CUDA_SET_PRAM:
- if (req->nbytes != 5)
- break;
- req->data[0] = PMU_WRITE_NVRAM;
- req->data[1] = req->data[2];
- req->data[2] = req->data[3];
- req->data[3] = req->data[4];
- req->nbytes = 4;
- req->reply_len = 3;
- req->reply[0] = CUDA_PACKET;
- req->reply[1] = 0;
- req->reply[2] = CUDA_SET_PRAM;
- ret = pmu_queue_request(req);
- break;
- }
- break;
- case ADB_PACKET:
- for (i = req->nbytes - 1; i > 1; --i)
- req->data[i+2] = req->data[i];
- req->data[3] = req->nbytes - 2;
- req->data[2] = pmu_adb_flags;
- /*req->data[1] = req->data[1];*/
- req->data[0] = PMU_ADB_CMD;
- req->nbytes += 2;
- req->reply_expected = 1;
- req->reply_len = 0;
- ret = pmu_queue_request(req);
- break;
- }
- if (ret)
- {
- req->complete = 1;
- return ret;
- }
-
- if (sync) {
- while (!req->complete)
- pmu_poll();
- }
-
- return 0;
-}
-
-/* Enable/disable autopolling */
-static int
-pmu_autopoll(int devs)
-{
- struct adb_request req;
-
- if (!pmu_fully_inited) return -ENXIO;
-
- if (devs) {
- adb_dev_map = devs;
- pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86,
- adb_dev_map >> 8, adb_dev_map);
- pmu_adb_flags = 2;
- } else {
- pmu_request(&req, NULL, 1, PMU_ADB_POLL_OFF);
- pmu_adb_flags = 0;
- }
- while (!req.complete)
- pmu_poll();
- return 0;
-}
-
-/* Reset the ADB bus */
-static int
-pmu_reset_bus(void)
-{
- struct adb_request req;
- long timeout;
- int save_autopoll = adb_dev_map;
-
- if (!pmu_fully_inited) return -ENXIO;
-
- /* anyone got a better idea?? */
- pmu_autopoll(0);
-
- req.nbytes = 5;
- req.done = NULL;
- req.data[0] = PMU_ADB_CMD;
- req.data[1] = 0;
- req.data[2] = 3; /* ADB_BUSRESET ??? */
- req.data[3] = 0;
- req.data[4] = 0;
- req.reply_len = 0;
- req.reply_expected = 1;
- if (pmu_queue_request(&req) != 0)
- {
- printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n");
- return -EIO;
- }
- while (!req.complete)
- pmu_poll();
- timeout = 100000;
- while (!req.complete) {
- if (--timeout < 0) {
- printk(KERN_ERR "pmu_adb_reset_bus (reset): no response from PMU\n");
- return -EIO;
- }
- udelay(10);
- pmu_poll();
- }
-
- if (save_autopoll != 0)
- pmu_autopoll(save_autopoll);
-
- return 0;
-}
-
-/* Construct and send a pmu request */
-int
-pmu_request(struct adb_request *req, void (*done)(struct adb_request *),
- int nbytes, ...)
-{
- va_list list;
- int i;
-
- if (nbytes < 0 || nbytes > 32) {
- printk(KERN_ERR "pmu_request: bad nbytes (%d)\n", nbytes);
- req->complete = 1;
- return -EINVAL;
- }
- req->nbytes = nbytes;
- req->done = done;
- va_start(list, nbytes);
- for (i = 0; i < nbytes; ++i)
- req->data[i] = va_arg(list, int);
- va_end(list);
- if (pmu_data_len[req->data[0]][1] != 0) {
- req->reply[0] = ADB_RET_OK;
- req->reply_len = 1;
- } else
- req->reply_len = 0;
- req->reply_expected = 0;
- return pmu_queue_request(req);
-}
-
-int
-pmu_queue_request(struct adb_request *req)
-{
- unsigned long flags;
- int nsend;
-
- if (req->nbytes <= 0) {
- req->complete = 1;
- return 0;
- }
- nsend = pmu_data_len[req->data[0]][0];
- if (nsend >= 0 && req->nbytes != nsend + 1) {
- req->complete = 1;
- return -EINVAL;
- }
-
- req->next = NULL;
- req->sent = 0;
- req->complete = 0;
- local_irq_save(flags);
-
- if (current_req != 0) {
- last_req->next = req;
- last_req = req;
- } else {
- current_req = req;
- last_req = req;
- if (pmu_state == idle)
- pmu_start();
- }
-
- local_irq_restore(flags);
- return 0;
-}
-
-static void
-send_byte(int x)
-{
- via1[ACR] |= SR_CTRL;
- via1[SR] = x;
- via2[B] &= ~TREQ; /* assert TREQ */
-}
-
-static void
-recv_byte(void)
-{
- char c;
-
- via1[ACR] = (via1[ACR] | SR_EXT) & ~SR_OUT;
- c = via1[SR]; /* resets SR */
- via2[B] &= ~TREQ;
-}
-
-static void
-pmu_start(void)
-{
- unsigned long flags;
- struct adb_request *req;
-
- /* assert pmu_state == idle */
- /* get the packet to send */
- local_irq_save(flags);
- req = current_req;
- if (req == 0 || pmu_state != idle
- || (req->reply_expected && req_awaiting_reply))
- goto out;
-
- pmu_state = sending;
- data_index = 1;
- data_len = pmu_data_len[req->data[0]][0];
-
- /* set the shift register to shift out and send a byte */
- send_byte(req->data[0]);
-
-out:
- local_irq_restore(flags);
-}
-
-void
-pmu_poll(void)
-{
- unsigned long flags;
-
- local_irq_save(flags);
- if (via1[IFR] & SR_INT) {
- via1[IFR] = SR_INT;
- pmu_interrupt(IRQ_MAC_ADB_SR, NULL);
- }
- if (via1[IFR] & CB1_INT) {
- via1[IFR] = CB1_INT;
- pmu_interrupt(IRQ_MAC_ADB_CL, NULL);
- }
- local_irq_restore(flags);
-}
-
-static irqreturn_t
-pmu_interrupt(int irq, void *dev_id)
-{
- struct adb_request *req;
- int timeout, bite = 0; /* to prevent compiler warning */
-
-#if 0
- printk("pmu_interrupt: irq %d state %d acr %02X, b %02X data_index %d/%d adb_int_pending %d\n",
- irq, pmu_state, (uint) via1[ACR], (uint) via2[B], data_index, data_len, adb_int_pending);
-#endif
-
- if (irq == IRQ_MAC_ADB_CL) { /* CB1 interrupt */
- adb_int_pending = 1;
- } else if (irq == IRQ_MAC_ADB_SR) { /* SR interrupt */
- if (via2[B] & TACK) {
- printk(KERN_DEBUG "PMU: SR_INT but ack still high! (%x)\n", via2[B]);
- }
-
- /* if reading grab the byte */
- if ((via1[ACR] & SR_OUT) == 0) bite = via1[SR];
-
- /* reset TREQ and wait for TACK to go high */
- via2[B] |= TREQ;
- timeout = 3200;
- while (!(via2[B] & TACK)) {
- if (--timeout < 0) {
- printk(KERN_ERR "PMU not responding (!ack)\n");
- goto finish;
- }
- udelay(10);
- }
-
- switch (pmu_state) {
- case sending:
- req = current_req;
- if (data_len < 0) {
- data_len = req->nbytes - 1;
- send_byte(data_len);
- break;
- }
- if (data_index <= data_len) {
- send_byte(req->data[data_index++]);
- break;
- }
- req->sent = 1;
- data_len = pmu_data_len[req->data[0]][1];
- if (data_len == 0) {
- pmu_state = idle;
- current_req = req->next;
- if (req->reply_expected)
- req_awaiting_reply = req;
- else
- pmu_done(req);
- } else {
- pmu_state = reading;
- data_index = 0;
- reply_ptr = req->reply + req->reply_len;
- recv_byte();
- }
- break;
-
- case intack:
- data_index = 0;
- data_len = -1;
- pmu_state = reading_intr;
- reply_ptr = interrupt_data;
- recv_byte();
- break;
-
- case reading:
- case reading_intr:
- if (data_len == -1) {
- data_len = bite;
- if (bite > 32)
- printk(KERN_ERR "PMU: bad reply len %d\n",
- bite);
- } else {
- reply_ptr[data_index++] = bite;
- }
- if (data_index < data_len) {
- recv_byte();
- break;
- }
-
- if (pmu_state == reading_intr) {
- pmu_handle_data(interrupt_data, data_index);
- } else {
- req = current_req;
- current_req = req->next;
- req->reply_len += data_index;
- pmu_done(req);
- }
- pmu_state = idle;
-
- break;
-
- default:
- printk(KERN_ERR "pmu_interrupt: unknown state %d?\n",
- pmu_state);
- }
- }
-finish:
- if (pmu_state == idle) {
- if (adb_int_pending) {
- pmu_state = intack;
- send_byte(PMU_INT_ACK);
- adb_int_pending = 0;
- } else if (current_req) {
- pmu_start();
- }
- }
-
-#if 0
- printk("pmu_interrupt: exit state %d acr %02X, b %02X data_index %d/%d adb_int_pending %d\n",
- pmu_state, (uint) via1[ACR], (uint) via2[B], data_index, data_len, adb_int_pending);
-#endif
- return IRQ_HANDLED;
-}
-
-static void
-pmu_done(struct adb_request *req)
-{
- req->complete = 1;
- if (req->done)
- (*req->done)(req);
-}
-
-/* Interrupt data could be the result data from an ADB cmd */
-static void
-pmu_handle_data(unsigned char *data, int len)
-{
- static int show_pmu_ints = 1;
-
- asleep = 0;
- if (len < 1) {
- adb_int_pending = 0;
- return;
- }
- if (data[0] & PMU_INT_ADB) {
- if ((data[0] & PMU_INT_ADB_AUTO) == 0) {
- struct adb_request *req = req_awaiting_reply;
- if (req == 0) {
- printk(KERN_ERR "PMU: extra ADB reply\n");
- return;
- }
- req_awaiting_reply = NULL;
- if (len <= 2)
- req->reply_len = 0;
- else {
- memcpy(req->reply, data + 1, len - 1);
- req->reply_len = len - 1;
- }
- pmu_done(req);
- } else {
- adb_input(data+1, len-1, 1);
- }
- } else {
- if (data[0] == 0x08 && len == 3) {
- /* sound/brightness buttons pressed */
- pmu_set_brightness(data[1] >> 3);
- set_volume(data[2]);
- } else if (show_pmu_ints
- && !(data[0] == PMU_INT_TICK && len == 1)) {
- int i;
- printk(KERN_DEBUG "pmu intr");
- for (i = 0; i < len; ++i)
- printk(" %.2x", data[i]);
- printk("\n");
- }
- }
-}
-
-static int backlight_level = -1;
-static int backlight_enabled = 0;
-
-#define LEVEL_TO_BRIGHT(lev) ((lev) < 1? 0x7f: 0x4a - ((lev) << 1))
-
-static void
-pmu_enable_backlight(int on)
-{
- struct adb_request req;
-
- if (on) {
- /* first call: get current backlight value */
- if (backlight_level < 0) {
- switch(pmu_kind) {
- case PMU_68K_V2:
- pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe);
- while (!req.complete)
- pmu_poll();
- printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", (int)req.reply[1]);
- backlight_level = req.reply[1];
- break;
- default:
- backlight_enabled = 0;
- return;
- }
- }
- pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
- LEVEL_TO_BRIGHT(backlight_level));
- while (!req.complete)
- pmu_poll();
- }
- pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
- PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
- while (!req.complete)
- pmu_poll();
- backlight_enabled = on;
-}
-
-static void
-pmu_set_brightness(int level)
-{
- int bright;
-
- backlight_level = level;
- bright = LEVEL_TO_BRIGHT(level);
- if (!backlight_enabled)
- return;
- if (bright_req_1.complete)
- pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT,
- bright);
- if (bright_req_2.complete)
- pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL,
- PMU_POW_BACKLIGHT | (bright < 0x7f ? PMU_POW_ON : PMU_POW_OFF));
-}
-
-void
-pmu_enable_irled(int on)
-{
- struct adb_request req;
-
- pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_IRLED |
- (on ? PMU_POW_ON : PMU_POW_OFF));
- while (!req.complete)
- pmu_poll();
-}
-
-static void
-set_volume(int level)
-{
-}
-
-int
-pmu_present(void)
-{
- return (pmu_kind != PMU_UNKNOWN);
-}
diff --git a/include/uapi/linux/pmu.h b/include/uapi/linux/pmu.h
index e128f609281a..97256f90e6df 100644
--- a/include/uapi/linux/pmu.h
+++ b/include/uapi/linux/pmu.h
@@ -94,7 +94,7 @@ enum {
PMU_PADDINGTON_BASED, /* 1999 PowerBook G3 */
PMU_KEYLARGO_BASED, /* Core99 motherboard (PMU99) */
PMU_68K_V1, /* Unused/deprecated */
- PMU_68K_V2, /* 68K PMU, version 2 */
+ PMU_68K_V2, /* Unused/deprecated */
};
/* PMU PMU_POWER_EVENTS commands */
--
2.16.4
^ permalink raw reply related
* [PATCH v3 05/12] macintosh/via-pmu: Replace via pointer with via1 and via2 pointers
From: Finn Thain @ 2018-06-13 10:38 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Michael Schmitz, linuxppc-dev, linux-m68k, linux-kernel
In-Reply-To: <cover.1528885172.git.fthain@telegraphics.com.au>
On most PowerPC Macs, the PMU driver uses the shift register and
IO port B from a single VIA chip.
On 68k and early PowerPC PowerBooks, the driver uses the shift register
from one VIA chip together with IO port B from another.
Replace via with via1 and via2 to accommodate this. For the
CONFIG_PPC_PMAC case, set via1 = via2 so there is no change.
Tested-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
---
drivers/macintosh/via-pmu.c | 142 +++++++++++++++++++++-----------------------
1 file changed, 69 insertions(+), 73 deletions(-)
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index c4c324fb5fa6..2e09137410f6 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -76,7 +76,6 @@
#define BATTERY_POLLING_COUNT 2
static DEFINE_MUTEX(pmu_info_proc_mutex);
-static volatile unsigned char __iomem *via;
/* VIA registers - spaced 0x200 bytes apart */
#define RS 0x200 /* skip between registers */
@@ -145,6 +144,8 @@ static struct device_node *vias;
static int pmu_kind = PMU_UNKNOWN;
static int pmu_fully_inited;
static int pmu_has_adb;
+static volatile unsigned char __iomem *via1;
+static volatile unsigned char __iomem *via2;
static struct device_node *gpio_node;
static unsigned char __iomem *gpio_reg;
static int gpio_irq = 0;
@@ -340,14 +341,14 @@ int __init find_via_pmu(void)
} else
pmu_kind = PMU_UNKNOWN;
- via = ioremap(taddr, 0x2000);
- if (via == NULL) {
+ via1 = via2 = ioremap(taddr, 0x2000);
+ if (via1 == NULL) {
printk(KERN_ERR "via-pmu: Can't map address !\n");
goto fail_via_remap;
}
- out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */
- out_8(&via[IFR], 0x7f); /* clear IFR */
+ out_8(&via1[IER], IER_CLR | 0x7f); /* disable all intrs */
+ out_8(&via1[IFR], 0x7f); /* clear IFR */
pmu_state = idle;
@@ -362,8 +363,8 @@ int __init find_via_pmu(void)
return 1;
fail_init:
- iounmap(via);
- via = NULL;
+ iounmap(via1);
+ via1 = via2 = NULL;
fail_via_remap:
iounmap(gpio_reg);
gpio_reg = NULL;
@@ -437,7 +438,7 @@ static int __init via_pmu_start(void)
}
/* Enable interrupts */
- out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
+ out_8(&via1[IER], IER_SET | SR_INT | CB1_INT);
pmu_fully_inited = 1;
@@ -533,8 +534,8 @@ init_pmu(void)
struct adb_request req;
/* Negate TREQ. Set TACK to input and TREQ to output. */
- out_8(&via[B], in_8(&via[B]) | TREQ);
- out_8(&via[DIRB], (in_8(&via[DIRB]) | TREQ) & ~TACK);
+ out_8(&via2[B], in_8(&via2[B]) | TREQ);
+ out_8(&via2[DIRB], (in_8(&via2[DIRB]) | TREQ) & ~TACK);
pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
timeout = 100000;
@@ -1174,7 +1175,7 @@ wait_for_ack(void)
* reported
*/
int timeout = 4000;
- while ((in_8(&via[B]) & TACK) == 0) {
+ while ((in_8(&via2[B]) & TACK) == 0) {
if (--timeout < 0) {
printk(KERN_ERR "PMU not responding (!ack)\n");
return;
@@ -1188,23 +1189,19 @@ wait_for_ack(void)
static inline void
send_byte(int x)
{
- volatile unsigned char __iomem *v = via;
-
- out_8(&v[ACR], in_8(&v[ACR]) | SR_OUT | SR_EXT);
- out_8(&v[SR], x);
- out_8(&v[B], in_8(&v[B]) & ~TREQ); /* assert TREQ */
- (void)in_8(&v[B]);
+ out_8(&via1[ACR], in_8(&via1[ACR]) | SR_OUT | SR_EXT);
+ out_8(&via1[SR], x);
+ out_8(&via2[B], in_8(&via2[B]) & ~TREQ); /* assert TREQ */
+ (void)in_8(&via2[B]);
}
static inline void
recv_byte(void)
{
- volatile unsigned char __iomem *v = via;
-
- out_8(&v[ACR], (in_8(&v[ACR]) & ~SR_OUT) | SR_EXT);
- in_8(&v[SR]); /* resets SR */
- out_8(&v[B], in_8(&v[B]) & ~TREQ);
- (void)in_8(&v[B]);
+ out_8(&via1[ACR], (in_8(&via1[ACR]) & ~SR_OUT) | SR_EXT);
+ in_8(&via1[SR]); /* resets SR */
+ out_8(&via2[B], in_8(&via2[B]) & ~TREQ);
+ (void)in_8(&via2[B]);
}
static inline void
@@ -1307,7 +1304,7 @@ pmu_suspend(void)
if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) {
if (gpio_irq >= 0)
disable_irq_nosync(gpio_irq);
- out_8(&via[IER], CB1_INT | IER_CLR);
+ out_8(&via1[IER], CB1_INT | IER_CLR);
spin_unlock_irqrestore(&pmu_lock, flags);
break;
}
@@ -1331,7 +1328,7 @@ pmu_resume(void)
adb_int_pending = 1;
if (gpio_irq >= 0)
enable_irq(gpio_irq);
- out_8(&via[IER], CB1_INT | IER_SET);
+ out_8(&via1[IER], CB1_INT | IER_SET);
spin_unlock_irqrestore(&pmu_lock, flags);
pmu_poll();
}
@@ -1456,20 +1453,20 @@ pmu_sr_intr(void)
struct adb_request *req;
int bite = 0;
- if (in_8(&via[B]) & TREQ) {
- printk(KERN_ERR "PMU: spurious SR intr (%x)\n", in_8(&via[B]));
+ if (in_8(&via2[B]) & TREQ) {
+ printk(KERN_ERR "PMU: spurious SR intr (%x)\n", in_8(&via2[B]));
return NULL;
}
/* The ack may not yet be low when we get the interrupt */
- while ((in_8(&via[B]) & TACK) != 0)
+ while ((in_8(&via2[B]) & TACK) != 0)
;
/* if reading grab the byte, and reset the interrupt */
if (pmu_state == reading || pmu_state == reading_intr)
- bite = in_8(&via[SR]);
+ bite = in_8(&via1[SR]);
/* reset TREQ and wait for TACK to go high */
- out_8(&via[B], in_8(&via[B]) | TREQ);
+ out_8(&via2[B], in_8(&via2[B]) | TREQ);
wait_for_ack();
switch (pmu_state) {
@@ -1570,17 +1567,17 @@ via_pmu_interrupt(int irq, void *arg)
++disable_poll;
for (;;) {
- intr = in_8(&via[IFR]) & (SR_INT | CB1_INT);
+ intr = in_8(&via1[IFR]) & (SR_INT | CB1_INT);
if (intr == 0)
break;
handled = 1;
if (++nloop > 1000) {
printk(KERN_DEBUG "PMU: stuck in intr loop, "
"intr=%x, ier=%x pmu_state=%d\n",
- intr, in_8(&via[IER]), pmu_state);
+ intr, in_8(&via1[IER]), pmu_state);
break;
}
- out_8(&via[IFR], intr);
+ out_8(&via1[IFR], intr);
if (intr & CB1_INT) {
adb_int_pending = 1;
pmu_irq_stats[0]++;
@@ -1762,29 +1759,29 @@ static u32 save_via[8];
static void
save_via_state(void)
{
- save_via[0] = in_8(&via[ANH]);
- save_via[1] = in_8(&via[DIRA]);
- save_via[2] = in_8(&via[B]);
- save_via[3] = in_8(&via[DIRB]);
- save_via[4] = in_8(&via[PCR]);
- save_via[5] = in_8(&via[ACR]);
- save_via[6] = in_8(&via[T1CL]);
- save_via[7] = in_8(&via[T1CH]);
+ save_via[0] = in_8(&via1[ANH]);
+ save_via[1] = in_8(&via1[DIRA]);
+ save_via[2] = in_8(&via1[B]);
+ save_via[3] = in_8(&via1[DIRB]);
+ save_via[4] = in_8(&via1[PCR]);
+ save_via[5] = in_8(&via1[ACR]);
+ save_via[6] = in_8(&via1[T1CL]);
+ save_via[7] = in_8(&via1[T1CH]);
}
static void
restore_via_state(void)
{
- out_8(&via[ANH], save_via[0]);
- out_8(&via[DIRA], save_via[1]);
- out_8(&via[B], save_via[2]);
- out_8(&via[DIRB], save_via[3]);
- out_8(&via[PCR], save_via[4]);
- out_8(&via[ACR], save_via[5]);
- out_8(&via[T1CL], save_via[6]);
- out_8(&via[T1CH], save_via[7]);
- out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */
- out_8(&via[IFR], 0x7f); /* clear IFR */
- out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
+ out_8(&via1[ANH], save_via[0]);
+ out_8(&via1[DIRA], save_via[1]);
+ out_8(&via1[B], save_via[2]);
+ out_8(&via1[DIRB], save_via[3]);
+ out_8(&via1[PCR], save_via[4]);
+ out_8(&via1[ACR], save_via[5]);
+ out_8(&via1[T1CL], save_via[6]);
+ out_8(&via1[T1CH], save_via[7]);
+ out_8(&via1[IER], IER_CLR | 0x7f); /* disable all intrs */
+ out_8(&via1[IFR], 0x7f); /* clear IFR */
+ out_8(&via1[IER], IER_SET | SR_INT | CB1_INT);
}
#define GRACKLE_PM (1<<7)
@@ -2426,33 +2423,33 @@ device_initcall(pmu_device_init);
#ifdef DEBUG_SLEEP
static inline void
-polled_handshake(volatile unsigned char __iomem *via)
+polled_handshake(void)
{
- via[B] &= ~TREQ; eieio();
- while ((via[B] & TACK) != 0)
+ via2[B] &= ~TREQ; eieio();
+ while ((via2[B] & TACK) != 0)
;
- via[B] |= TREQ; eieio();
- while ((via[B] & TACK) == 0)
+ via2[B] |= TREQ; eieio();
+ while ((via2[B] & TACK) == 0)
;
}
static inline void
-polled_send_byte(volatile unsigned char __iomem *via, int x)
+polled_send_byte(int x)
{
- via[ACR] |= SR_OUT | SR_EXT; eieio();
- via[SR] = x; eieio();
- polled_handshake(via);
+ via1[ACR] |= SR_OUT | SR_EXT; eieio();
+ via1[SR] = x; eieio();
+ polled_handshake();
}
static inline int
-polled_recv_byte(volatile unsigned char __iomem *via)
+polled_recv_byte(void)
{
int x;
- via[ACR] = (via[ACR] & ~SR_OUT) | SR_EXT; eieio();
- x = via[SR]; eieio();
- polled_handshake(via);
- x = via[SR]; eieio();
+ via1[ACR] = (via1[ACR] & ~SR_OUT) | SR_EXT; eieio();
+ x = via1[SR]; eieio();
+ polled_handshake();
+ x = via1[SR]; eieio();
return x;
}
@@ -2461,7 +2458,6 @@ pmu_polled_request(struct adb_request *req)
{
unsigned long flags;
int i, l, c;
- volatile unsigned char __iomem *v = via;
req->complete = 1;
c = req->data[0];
@@ -2473,21 +2469,21 @@ pmu_polled_request(struct adb_request *req)
while (pmu_state != idle)
pmu_poll();
- while ((via[B] & TACK) == 0)
+ while ((via2[B] & TACK) == 0)
;
- polled_send_byte(v, c);
+ polled_send_byte(c);
if (l < 0) {
l = req->nbytes - 1;
- polled_send_byte(v, l);
+ polled_send_byte(l);
}
for (i = 1; i <= l; ++i)
- polled_send_byte(v, req->data[i]);
+ polled_send_byte(req->data[i]);
l = pmu_data_len[c][1];
if (l < 0)
- l = polled_recv_byte(v);
+ l = polled_recv_byte();
for (i = 0; i < l; ++i)
- req->reply[i + req->reply_len] = polled_recv_byte(v);
+ req->reply[i + req->reply_len] = polled_recv_byte();
if (req->done)
(*req->done)(req);
--
2.16.4
^ permalink raw reply related
* [PATCH v3 06/12] macintosh/via-pmu: Add support for m68k PowerBooks
From: Finn Thain @ 2018-06-13 10:38 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Michael Schmitz, linuxppc-dev, linux-m68k, linux-kernel
In-Reply-To: <cover.1528885172.git.fthain@telegraphics.com.au>
Put #ifdefs around the Open Firmware, xmon, interrupt dispatch,
battery and suspend code. Add the necessary interrupt handling to
support m68k PowerBooks.
The pmu_kind value is available to userspace using the
PMU_IOC_GET_MODEL ioctl. It is not clear yet what hardware classes
are be needed to describe m68k PowerBook models, so pmu_kind is given
the provisional value PMU_UNKNOWN.
To find out about the hardware, user programs can use /proc/bootinfo
or /proc/hardware, or send the PMU_GET_VERSION command using /dev/adb.
Tested-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
---
drivers/macintosh/Kconfig | 2 +-
drivers/macintosh/via-pmu.c | 101 +++++++++++++++++++++++++++++++++++++++-----
2 files changed, 91 insertions(+), 12 deletions(-)
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 97a420c11eed..9c6452b38c36 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -65,7 +65,7 @@ config ADB_CUDA
If unsure say Y.
config ADB_PMU
- bool "Support for PMU based PowerMacs"
+ bool "Support for PMU based PowerMacs and PowerBooks"
depends on PPC_PMAC
help
On PowerBooks, iBooks, and recent iMacs and Power Macintoshes, the
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 2e09137410f6..22cb7d94e3ce 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Device driver for the via-pmu on Apple Powermacs.
+ * Device driver for the PMU in Apple PowerBooks and PowerMacs.
*
* The VIA (versatile interface adapter) interfaces to the PMU,
* a 6805 microprocessor core whose primary function is to control
@@ -49,20 +49,26 @@
#include <linux/compat.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
-#include <asm/prom.h>
+#include <linux/uaccess.h>
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/sections.h>
#include <asm/irq.h>
+#ifdef CONFIG_PPC_PMAC
#include <asm/pmac_feature.h>
#include <asm/pmac_pfunc.h>
#include <asm/pmac_low_i2c.h>
-#include <linux/uaccess.h>
+#include <asm/prom.h>
#include <asm/mmu_context.h>
#include <asm/cputable.h>
#include <asm/time.h>
#include <asm/backlight.h>
+#else
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/mac_via.h>
+#endif
#include "via-pmu-event.h"
@@ -97,8 +103,13 @@ static DEFINE_MUTEX(pmu_info_proc_mutex);
#define ANH (15*RS) /* A-side data, no handshake */
/* Bits in B data register: both active low */
+#ifdef CONFIG_PPC_PMAC
#define TACK 0x08 /* Transfer acknowledge (input) */
#define TREQ 0x10 /* Transfer request (output) */
+#else
+#define TACK 0x02
+#define TREQ 0x04
+#endif
/* Bits in ACR */
#define SR_CTRL 0x1c /* Shift register control bits */
@@ -140,13 +151,15 @@ static int data_index;
static int data_len;
static volatile int adb_int_pending;
static volatile int disable_poll;
-static struct device_node *vias;
static int pmu_kind = PMU_UNKNOWN;
static int pmu_fully_inited;
static int pmu_has_adb;
+#ifdef CONFIG_PPC_PMAC
static volatile unsigned char __iomem *via1;
static volatile unsigned char __iomem *via2;
+static struct device_node *vias;
static struct device_node *gpio_node;
+#endif
static unsigned char __iomem *gpio_reg;
static int gpio_irq = 0;
static int gpio_irq_enabled = -1;
@@ -273,6 +286,7 @@ static char *pbook_type[] = {
int __init find_via_pmu(void)
{
+#ifdef CONFIG_PPC_PMAC
u64 taddr;
const u32 *reg;
@@ -355,9 +369,6 @@ int __init find_via_pmu(void)
if (!init_pmu())
goto fail_init;
- printk(KERN_INFO "PMU driver v%d initialized for %s, firmware: %02x\n",
- PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version);
-
sys_ctrler = SYS_CTRLER_PMU;
return 1;
@@ -373,6 +384,30 @@ int __init find_via_pmu(void)
vias = NULL;
pmu_state = uninitialized;
return 0;
+#else
+ if (macintosh_config->adb_type != MAC_ADB_PB2)
+ return 0;
+
+ pmu_kind = PMU_UNKNOWN;
+
+ spin_lock_init(&pmu_lock);
+
+ pmu_has_adb = 1;
+
+ pmu_intr_mask = PMU_INT_PCEJECT |
+ PMU_INT_SNDBRT |
+ PMU_INT_ADB |
+ PMU_INT_TICK;
+
+ pmu_state = idle;
+
+ if (!init_pmu()) {
+ pmu_state = uninitialized;
+ return 0;
+ }
+
+ return 1;
+#endif /* !CONFIG_PPC_PMAC */
}
#ifdef CONFIG_ADB
@@ -396,13 +431,14 @@ static int pmu_init(void)
*/
static int __init via_pmu_start(void)
{
- unsigned int irq;
+ unsigned int __maybe_unused irq;
if (pmu_state == uninitialized)
return -ENODEV;
batt_req.complete = 1;
+#ifdef CONFIG_PPC_PMAC
irq = irq_of_parse_and_map(vias, 0);
if (!irq) {
printk(KERN_ERR "via-pmu: can't map interrupt\n");
@@ -439,6 +475,19 @@ static int __init via_pmu_start(void)
/* Enable interrupts */
out_8(&via1[IER], IER_SET | SR_INT | CB1_INT);
+#else
+ if (request_irq(IRQ_MAC_ADB_SR, via_pmu_interrupt, IRQF_NO_SUSPEND,
+ "VIA-PMU-SR", NULL)) {
+ pr_err("%s: couldn't get SR irq\n", __func__);
+ return -ENODEV;
+ }
+ if (request_irq(IRQ_MAC_ADB_CL, via_pmu_interrupt, IRQF_NO_SUSPEND,
+ "VIA-PMU-CL", NULL)) {
+ pr_err("%s: couldn't get CL irq\n", __func__);
+ free_irq(IRQ_MAC_ADB_SR, NULL);
+ return -ENODEV;
+ }
+#endif /* !CONFIG_PPC_PMAC */
pmu_fully_inited = 1;
@@ -587,6 +636,10 @@ init_pmu(void)
option_server_mode ? "enabled" : "disabled");
}
}
+
+ printk(KERN_INFO "PMU driver v%d initialized for %s, firmware: %02x\n",
+ PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version);
+
return 1;
}
@@ -625,6 +678,7 @@ static void pmu_set_server_mode(int server_mode)
static void
done_battery_state_ohare(struct adb_request* req)
{
+#ifdef CONFIG_PPC_PMAC
/* format:
* [0] : flags
* 0x01 : AC indicator
@@ -706,6 +760,7 @@ done_battery_state_ohare(struct adb_request* req)
pmu_batteries[pmu_cur_battery].amperage = amperage;
pmu_batteries[pmu_cur_battery].voltage = voltage;
pmu_batteries[pmu_cur_battery].time_remaining = time;
+#endif /* CONFIG_PPC_PMAC */
clear_bit(0, &async_req_locks);
}
@@ -1393,6 +1448,7 @@ pmu_handle_data(unsigned char *data, int len)
}
pmu_done(req);
} else {
+#ifdef CONFIG_XMON
if (len == 4 && data[1] == 0x2c) {
extern int xmon_wants_key, xmon_adb_keycode;
if (xmon_wants_key) {
@@ -1400,6 +1456,7 @@ pmu_handle_data(unsigned char *data, int len)
return;
}
}
+#endif /* CONFIG_XMON */
#ifdef CONFIG_ADB
/*
* XXX On the [23]400 the PMU gives us an up
@@ -1567,7 +1624,25 @@ via_pmu_interrupt(int irq, void *arg)
++disable_poll;
for (;;) {
- intr = in_8(&via1[IFR]) & (SR_INT | CB1_INT);
+ /* On 68k Macs, VIA interrupts are dispatched individually.
+ * Unless we are polling, the relevant IRQ flag has already
+ * been cleared.
+ */
+ intr = 0;
+ if (IS_ENABLED(CONFIG_PPC_PMAC) || !irq) {
+ intr = in_8(&via1[IFR]) & (SR_INT | CB1_INT);
+ out_8(&via1[IFR], intr);
+ }
+#ifndef CONFIG_PPC_PMAC
+ switch (irq) {
+ case IRQ_MAC_ADB_CL:
+ intr = CB1_INT;
+ break;
+ case IRQ_MAC_ADB_SR:
+ intr = SR_INT;
+ break;
+ }
+#endif
if (intr == 0)
break;
handled = 1;
@@ -1577,7 +1652,6 @@ via_pmu_interrupt(int irq, void *arg)
intr, in_8(&via1[IER]), pmu_state);
break;
}
- out_8(&via1[IFR], intr);
if (intr & CB1_INT) {
adb_int_pending = 1;
pmu_irq_stats[0]++;
@@ -1587,6 +1661,9 @@ via_pmu_interrupt(int irq, void *arg)
if (req)
break;
}
+#ifndef CONFIG_PPC_PMAC
+ break;
+#endif
}
recheck:
@@ -1653,7 +1730,7 @@ pmu_unlock(void)
}
-static irqreturn_t
+static __maybe_unused irqreturn_t
gpio1_interrupt(int irq, void *arg)
{
unsigned long flags;
@@ -2287,6 +2364,7 @@ static int pmu_ioctl(struct file *filp,
int error = -EINVAL;
switch (cmd) {
+#ifdef CONFIG_PPC_PMAC
case PMU_IOC_SLEEP:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
@@ -2296,6 +2374,7 @@ static int pmu_ioctl(struct file *filp,
return put_user(0, argp);
else
return put_user(1, argp);
+#endif
#ifdef CONFIG_PMAC_BACKLIGHT_LEGACY
/* Compatibility ioctl's for backlight */
--
2.16.4
^ permalink raw reply related
* [PATCH v3 10/12] macintosh: Use common code to access RTC
From: Finn Thain @ 2018-06-13 10:38 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Michael Schmitz, linuxppc-dev, linux-m68k, linux-kernel,
Geert Uytterhoeven, Paul Mackerras, , Michael Ellerman
In-Reply-To: <cover.1528885172.git.fthain@telegraphics.com.au>
Now that the 68k Mac port has adopted the via-pmu driver, it must access
the PMU RTC using the appropriate command format. The same code can now
be used for both m68k and powerpc.
Replace the RTC code that's duplicated in arch/powerpc and arch/m68k
with common RTC accessors for Cuda and PMU devices.
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Paul Mackerras <paulus@samba.org>,
Cc: Michael Ellerman <mpe@ellerman.id.au>
Tested-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
---
arch/m68k/mac/misc.c | 64 ++---------------------------
arch/powerpc/platforms/powermac/time.c | 74 +---------------------------------
drivers/macintosh/via-cuda.c | 34 ++++++++++++++++
drivers/macintosh/via-pmu.c | 32 +++++++++++++++
include/linux/cuda.h | 3 ++
include/linux/pmu.h | 3 ++
6 files changed, 78 insertions(+), 132 deletions(-)
diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
index 28090a44fa09..397f9f942a9f 100644
--- a/arch/m68k/mac/misc.c
+++ b/arch/m68k/mac/misc.c
@@ -33,34 +33,6 @@
static void (*rom_reset)(void);
#ifdef CONFIG_ADB_CUDA
-static long cuda_read_time(void)
-{
- struct adb_request req;
- long time;
-
- if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
- return 0;
- while (!req.complete)
- cuda_poll();
-
- time = (req.reply[3] << 24) | (req.reply[4] << 16) |
- (req.reply[5] << 8) | req.reply[6];
- return time - RTC_OFFSET;
-}
-
-static void cuda_write_time(long data)
-{
- struct adb_request req;
-
- data += RTC_OFFSET;
- if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
- (data >> 24) & 0xFF, (data >> 16) & 0xFF,
- (data >> 8) & 0xFF, data & 0xFF) < 0)
- return;
- while (!req.complete)
- cuda_poll();
-}
-
static __u8 cuda_read_pram(int offset)
{
struct adb_request req;
@@ -86,34 +58,6 @@ static void cuda_write_pram(int offset, __u8 data)
#endif /* CONFIG_ADB_CUDA */
#ifdef CONFIG_ADB_PMU
-static long pmu_read_time(void)
-{
- struct adb_request req;
- long time;
-
- if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
- return 0;
- while (!req.complete)
- pmu_poll();
-
- time = (req.reply[1] << 24) | (req.reply[2] << 16) |
- (req.reply[3] << 8) | req.reply[4];
- return time - RTC_OFFSET;
-}
-
-static void pmu_write_time(long data)
-{
- struct adb_request req;
-
- data += RTC_OFFSET;
- if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
- (data >> 24) & 0xFF, (data >> 16) & 0xFF,
- (data >> 8) & 0xFF, data & 0xFF) < 0)
- return;
- while (!req.complete)
- pmu_poll();
-}
-
static __u8 pmu_read_pram(int offset)
{
struct adb_request req;
@@ -635,12 +579,12 @@ int mac_hwclk(int op, struct rtc_time *t)
#ifdef CONFIG_ADB_CUDA
case MAC_ADB_EGRET:
case MAC_ADB_CUDA:
- now = cuda_read_time();
+ now = cuda_get_time();
break;
#endif
#ifdef CONFIG_ADB_PMU
case MAC_ADB_PB2:
- now = pmu_read_time();
+ now = pmu_get_time();
break;
#endif
default:
@@ -671,12 +615,12 @@ int mac_hwclk(int op, struct rtc_time *t)
#ifdef CONFIG_ADB_CUDA
case MAC_ADB_EGRET:
case MAC_ADB_CUDA:
- cuda_write_time(now);
+ cuda_set_time(now);
break;
#endif
#ifdef CONFIG_ADB_PMU
case MAC_ADB_PB2:
- pmu_write_time(now);
+ pmu_set_time(now);
break;
#endif
default:
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index 274af6fa388e..e9c1f3dafe2f 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -42,9 +42,6 @@
#define DBG(x...)
#endif
-/* Apparently the RTC stores seconds since 1 Jan 1904 */
-#define RTC_OFFSET 2082844800
-
/*
* Calibrate the decrementer frequency with the VIA timer 1.
*/
@@ -103,43 +100,8 @@ static unsigned long from_rtc_time(struct rtc_time *tm)
#endif
#ifdef CONFIG_ADB_CUDA
-static unsigned long cuda_get_time(void)
-{
- struct adb_request req;
- unsigned int now;
-
- if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
- return 0;
- while (!req.complete)
- cuda_poll();
- if (req.reply_len != 7)
- printk(KERN_ERR "cuda_get_time: got %d byte reply\n",
- req.reply_len);
- now = (req.reply[3] << 24) + (req.reply[4] << 16)
- + (req.reply[5] << 8) + req.reply[6];
- return ((unsigned long)now) - RTC_OFFSET;
-}
-
#define cuda_get_rtc_time(tm) to_rtc_time(cuda_get_time(), (tm))
-
-static int cuda_set_rtc_time(struct rtc_time *tm)
-{
- unsigned int nowtime;
- struct adb_request req;
-
- nowtime = from_rtc_time(tm) + RTC_OFFSET;
- if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
- nowtime >> 24, nowtime >> 16, nowtime >> 8,
- nowtime) < 0)
- return -ENXIO;
- while (!req.complete)
- cuda_poll();
- if ((req.reply_len != 3) && (req.reply_len != 7))
- printk(KERN_ERR "cuda_set_rtc_time: got %d byte reply\n",
- req.reply_len);
- return 0;
-}
-
+#define cuda_set_rtc_time(tm) cuda_set_time(from_rtc_time(tm))
#else
#define cuda_get_time() 0
#define cuda_get_rtc_time(tm)
@@ -147,40 +109,8 @@ static int cuda_set_rtc_time(struct rtc_time *tm)
#endif
#ifdef CONFIG_ADB_PMU
-static unsigned long pmu_get_time(void)
-{
- struct adb_request req;
- unsigned int now;
-
- if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
- return 0;
- pmu_wait_complete(&req);
- if (req.reply_len != 4)
- printk(KERN_ERR "pmu_get_time: got %d byte reply from PMU\n",
- req.reply_len);
- now = (req.reply[0] << 24) + (req.reply[1] << 16)
- + (req.reply[2] << 8) + req.reply[3];
- return ((unsigned long)now) - RTC_OFFSET;
-}
-
#define pmu_get_rtc_time(tm) to_rtc_time(pmu_get_time(), (tm))
-
-static int pmu_set_rtc_time(struct rtc_time *tm)
-{
- unsigned int nowtime;
- struct adb_request req;
-
- nowtime = from_rtc_time(tm) + RTC_OFFSET;
- if (pmu_request(&req, NULL, 5, PMU_SET_RTC, nowtime >> 24,
- nowtime >> 16, nowtime >> 8, nowtime) < 0)
- return -ENXIO;
- pmu_wait_complete(&req);
- if (req.reply_len != 0)
- printk(KERN_ERR "pmu_set_rtc_time: %d byte reply from PMU\n",
- req.reply_len);
- return 0;
-}
-
+#define pmu_set_rtc_time(tm) pmu_set_time(from_rtc_time(tm))
#else
#define pmu_get_time() 0
#define pmu_get_rtc_time(tm)
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index 019556136e77..8e7fb2115f10 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -771,3 +771,37 @@ cuda_input(unsigned char *buf, int nb)
buf, nb, false);
}
}
+
+/* Offset between Unix time (1970-based) and Mac time (1904-based) */
+#define RTC_OFFSET 2082844800
+
+unsigned long cuda_get_time(void)
+{
+ struct adb_request req;
+ unsigned long now;
+
+ if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
+ return 0;
+ while (!req.complete)
+ cuda_poll();
+ if (req.reply_len != 7)
+ pr_err("%s: got %d byte reply\n", __func__, req.reply_len);
+ now = (req.reply[3] << 24) + (req.reply[4] << 16) +
+ (req.reply[5] << 8) + req.reply[6];
+ return now - RTC_OFFSET;
+}
+
+int cuda_set_time(unsigned long now)
+{
+ struct adb_request req;
+
+ now += RTC_OFFSET;
+ if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
+ now >> 24, now >> 16, now >> 8, now) < 0)
+ return -ENXIO;
+ while (!req.complete)
+ cuda_poll();
+ if ((req.reply_len != 3) && (req.reply_len != 7))
+ pr_err("%s: got %d byte reply\n", __func__, req.reply_len);
+ return 0;
+}
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 22cb7d94e3ce..38d7dd0bdb28 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -1820,6 +1820,38 @@ pmu_shutdown(void)
;
}
+/* Offset between Unix time (1970-based) and Mac time (1904-based) */
+#define RTC_OFFSET 2082844800
+
+unsigned long pmu_get_time(void)
+{
+ struct adb_request req;
+ unsigned long now;
+
+ if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
+ return 0;
+ pmu_wait_complete(&req);
+ if (req.reply_len != 4)
+ pr_err("%s: got %d byte reply\n", __func__, req.reply_len);
+ now = (req.reply[0] << 24) + (req.reply[1] << 16) +
+ (req.reply[2] << 8) + req.reply[3];
+ return now - RTC_OFFSET;
+}
+
+int pmu_set_time(unsigned long now)
+{
+ struct adb_request req;
+
+ now += RTC_OFFSET;
+ if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
+ now >> 24, now >> 16, now >> 8, now) < 0)
+ return -ENXIO;
+ pmu_wait_complete(&req);
+ if (req.reply_len != 0)
+ pr_err("%s: got %d byte reply\n", __func__, req.reply_len);
+ return 0;
+}
+
int
pmu_present(void)
{
diff --git a/include/linux/cuda.h b/include/linux/cuda.h
index 056867f09a01..a68669f746e1 100644
--- a/include/linux/cuda.h
+++ b/include/linux/cuda.h
@@ -16,4 +16,7 @@ extern int cuda_request(struct adb_request *req,
void (*done)(struct adb_request *), int nbytes, ...);
extern void cuda_poll(void);
+extern unsigned long cuda_get_time(void);
+extern int cuda_set_time(unsigned long now);
+
#endif /* _LINUX_CUDA_H */
diff --git a/include/linux/pmu.h b/include/linux/pmu.h
index 9ac8fc60ad49..feefd0bff9cf 100644
--- a/include/linux/pmu.h
+++ b/include/linux/pmu.h
@@ -34,6 +34,9 @@ static inline void pmu_resume(void)
{}
#endif
+extern unsigned long pmu_get_time(void);
+extern int pmu_set_time(unsigned long now);
+
extern void pmu_enable_irled(int on);
extern void pmu_restart(void);
--
2.16.4
^ permalink raw reply related
* [PATCH v3 12/12] macintosh/via-pmu: Disambiguate interrupt statistics
From: Finn Thain @ 2018-06-13 10:38 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Michael Schmitz, linuxppc-dev, linux-m68k, linux-kernel
In-Reply-To: <cover.1528885172.git.fthain@telegraphics.com.au>
Some of the event counters are overloaded which makes it very
difficult to interpret their values.
Counter 0 is supposed to report CB1 interrupts but it can also count
PMU_INT_WAITING_CHARGER events.
Counter 1 is supposed to report GPIO interrupts but it can also count
other events (depending upon the value of the PMU_INT_ADB bit).
Disambiguate these statistics with dedicated counters for GPIO and
CB1 interrupts.
Comments in the MkLinux source code say that the type 0 and type 1
interrupts are model-specific. Label them as "unknown".
This change to the contents of /proc/pmu/interrupts is by necessity
visible in userland. However, packages which interact with the PMU
(that is, pbbuttonsd, pmac-utils and pmud) don't open this file.
AFAIK, user software has no need to poll these counters.
Tested-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
---
The file now looks like this,
0: 0 (Unknown interrupt (type 0))
1: 0 (Unknown interrupt (type 1))
2: 0 (PC-Card eject button)
3: 23 (Sound/Brightness button)
4: 74 (ADB message)
5: 0 (Battery state change)
6: 0 (Environment interrupt)
7: 121 (Tick timer)
8: 0 (Ghost interrupt (zero len))
9: 1 (Empty interrupt (empty mask))
10: 2 (Max irqs in a row)
11: 194 (Total CB1 triggered events)
12: 0 (Total GPIO1 triggered events)
rather than this,
0: 194 (Total CB1 triggered events)
1: 0 (Total GPIO1 triggered events)
2: 0 (PC-Card eject button)
3: 23 (Sound/Brightness button)
4: 74 (ADB message)
5: 0 (Battery state change)
6: 0 (Environment interrupt)
7: 121 (Tick timer)
8: 0 (Ghost interrupt (zero len))
9: 1 (Empty interrupt (empty mask))
10: 2 (Max irqs in a row)
If some parser exists for this file, and if this change is problematic,
we could increment the driver version number in /proc/pmu/info, to
correspond with the format change.
---
drivers/macintosh/via-pmu.c | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 730c10f7fbb7..44919b3b56e0 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -172,7 +172,9 @@ static int drop_interrupts;
static int option_lid_wakeup = 1;
#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */
static unsigned long async_req_locks;
-static unsigned int pmu_irq_stats[11];
+
+#define NUM_IRQ_STATS 13
+static unsigned int pmu_irq_stats[NUM_IRQ_STATS];
static struct proc_dir_entry *proc_pmu_root;
static struct proc_dir_entry *proc_pmu_info;
@@ -884,9 +886,9 @@ static const struct file_operations pmu_info_proc_fops = {
static int pmu_irqstats_proc_show(struct seq_file *m, void *v)
{
int i;
- static const char *irq_names[] = {
- "Total CB1 triggered events",
- "Total GPIO1 triggered events",
+ static const char *irq_names[NUM_IRQ_STATS] = {
+ "Unknown interrupt (type 0)",
+ "Unknown interrupt (type 1)",
"PC-Card eject button",
"Sound/Brightness button",
"ADB message",
@@ -895,10 +897,12 @@ static int pmu_irqstats_proc_show(struct seq_file *m, void *v)
"Tick timer",
"Ghost interrupt (zero len)",
"Empty interrupt (empty mask)",
- "Max irqs in a row"
+ "Max irqs in a row",
+ "Total CB1 triggered events",
+ "Total GPIO1 triggered events",
};
- for (i=0; i<11; i++) {
+ for (i = 0; i < NUM_IRQ_STATS; i++) {
seq_printf(m, " %2u: %10u (%s)\n",
i, pmu_irq_stats[i], irq_names[i]);
}
@@ -1659,7 +1663,7 @@ via_pmu_interrupt(int irq, void *arg)
}
if (intr & CB1_INT) {
adb_int_pending = 1;
- pmu_irq_stats[0]++;
+ pmu_irq_stats[11]++;
}
if (intr & SR_INT) {
req = pmu_sr_intr();
@@ -1746,7 +1750,7 @@ gpio1_interrupt(int irq, void *arg)
disable_irq_nosync(gpio_irq);
gpio_irq_enabled = 0;
}
- pmu_irq_stats[1]++;
+ pmu_irq_stats[12]++;
adb_int_pending = 1;
spin_unlock_irqrestore(&pmu_lock, flags);
via_pmu_interrupt(0, NULL);
--
2.16.4
^ permalink raw reply related
* [PATCH v3 08/12] macintosh/via-pmu68k: Don't load driver on unsupported hardware
From: Finn Thain @ 2018-06-13 10:38 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Michael Schmitz, linuxppc-dev, linux-m68k, linux-kernel,
Geert Uytterhoeven
In-Reply-To: <cover.1528885172.git.fthain@telegraphics.com.au>
Don't load the via-pmu68k driver on early PowerBooks. The M50753 PMU
device found in those models was never supported by this driver.
Attempting to load the driver usually causes a boot hang.
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Reviewed-by: Michael Schmitz <schmitzmic@gmail.com>
---
arch/m68k/mac/misc.c | 6 ++----
drivers/macintosh/via-pmu68k.c | 4 ----
include/uapi/linux/pmu.h | 2 +-
3 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
index c68054361615..7ccb799eeb57 100644
--- a/arch/m68k/mac/misc.c
+++ b/arch/m68k/mac/misc.c
@@ -478,8 +478,7 @@ void mac_poweroff(void)
cuda_shutdown();
#endif
#ifdef CONFIG_ADB_PMU68K
- } else if (macintosh_config->adb_type == MAC_ADB_PB1
- || macintosh_config->adb_type == MAC_ADB_PB2) {
+ } else if (macintosh_config->adb_type == MAC_ADB_PB2) {
pmu_shutdown();
#endif
}
@@ -520,8 +519,7 @@ void mac_reset(void)
cuda_restart();
#endif
#ifdef CONFIG_ADB_PMU68K
- } else if (macintosh_config->adb_type == MAC_ADB_PB1
- || macintosh_config->adb_type == MAC_ADB_PB2) {
+ } else if (macintosh_config->adb_type == MAC_ADB_PB2) {
pmu_restart();
#endif
} else if (CPU_IS_030) {
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c
index d545ed45e482..bec8e1837d7d 100644
--- a/drivers/macintosh/via-pmu68k.c
+++ b/drivers/macintosh/via-pmu68k.c
@@ -175,9 +175,6 @@ static s8 pmu_data_len[256][2] = {
int __init find_via_pmu(void)
{
switch (macintosh_config->adb_type) {
- case MAC_ADB_PB1:
- pmu_kind = PMU_68K_V1;
- break;
case MAC_ADB_PB2:
pmu_kind = PMU_68K_V2;
break;
@@ -785,7 +782,6 @@ pmu_enable_backlight(int on)
/* first call: get current backlight value */
if (backlight_level < 0) {
switch(pmu_kind) {
- case PMU_68K_V1:
case PMU_68K_V2:
pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe);
while (!req.complete)
diff --git a/include/uapi/linux/pmu.h b/include/uapi/linux/pmu.h
index 89cb1acea93a..e128f609281a 100644
--- a/include/uapi/linux/pmu.h
+++ b/include/uapi/linux/pmu.h
@@ -93,7 +93,7 @@ enum {
PMU_HEATHROW_BASED, /* PowerBook G3 series */
PMU_PADDINGTON_BASED, /* 1999 PowerBook G3 */
PMU_KEYLARGO_BASED, /* Core99 motherboard (PMU99) */
- PMU_68K_V1, /* 68K PMU, version 1 */
+ PMU_68K_V1, /* Unused/deprecated */
PMU_68K_V2, /* 68K PMU, version 2 */
};
--
2.16.4
^ permalink raw reply related
* [PATCH v3 11/12] macintosh/via-pmu: Clean up interrupt statistics
From: Finn Thain @ 2018-06-13 10:38 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Michael Schmitz, linuxppc-dev, linux-m68k, linux-kernel
In-Reply-To: <cover.1528885172.git.fthain@telegraphics.com.au>
Replace an open-coded ffs() with the function call.
Simplify an if-else cascade using a switch statement.
Correct a typo and an indentation issue.
Tested-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org>
---
drivers/macintosh/via-pmu.c | 39 ++++++++++++++++++++++-----------------
1 file changed, 22 insertions(+), 17 deletions(-)
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 38d7dd0bdb28..730c10f7fbb7 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -1392,7 +1392,8 @@ pmu_resume(void)
static void
pmu_handle_data(unsigned char *data, int len)
{
- unsigned char ints, pirq;
+ unsigned char ints;
+ int idx;
int i = 0;
asleep = 0;
@@ -1414,25 +1415,24 @@ pmu_handle_data(unsigned char *data, int len)
ints &= ~(PMU_INT_ADB_AUTO | PMU_INT_AUTO_SRQ_POLL);
next:
-
if (ints == 0) {
if (i > pmu_irq_stats[10])
pmu_irq_stats[10] = i;
return;
}
-
- for (pirq = 0; pirq < 8; pirq++)
- if (ints & (1 << pirq))
- break;
- pmu_irq_stats[pirq]++;
i++;
- ints &= ~(1 << pirq);
+
+ idx = ffs(ints) - 1;
+ ints &= ~BIT(idx);
+
+ pmu_irq_stats[idx]++;
/* Note: for some reason, we get an interrupt with len=1,
* data[0]==0 after each normal ADB interrupt, at least
* on the Pismo. Still investigating... --BenH
*/
- if ((1 << pirq) & PMU_INT_ADB) {
+ switch (BIT(idx)) {
+ case PMU_INT_ADB:
if ((data[0] & PMU_INT_ADB_AUTO) == 0) {
struct adb_request *req = req_awaiting_reply;
if (req == 0) {
@@ -1470,25 +1470,28 @@ pmu_handle_data(unsigned char *data, int len)
adb_input(data+1, len-1, 1);
#endif /* CONFIG_ADB */
}
- }
+ break;
+
/* Sound/brightness button pressed */
- else if ((1 << pirq) & PMU_INT_SNDBRT) {
+ case PMU_INT_SNDBRT:
#ifdef CONFIG_PMAC_BACKLIGHT
if (len == 3)
pmac_backlight_set_legacy_brightness_pmu(data[1] >> 4);
#endif
- }
+ break;
+
/* Tick interrupt */
- else if ((1 << pirq) & PMU_INT_TICK) {
- /* Environement or tick interrupt, query batteries */
+ case PMU_INT_TICK:
+ /* Environment or tick interrupt, query batteries */
if (pmu_battery_count) {
if ((--query_batt_timer) == 0) {
query_battery_state();
query_batt_timer = BATTERY_POLLING_COUNT;
}
}
- }
- else if ((1 << pirq) & PMU_INT_ENVIRONMENT) {
+ break;
+
+ case PMU_INT_ENVIRONMENT:
if (pmu_battery_count)
query_battery_state();
pmu_pass_intr(data, len);
@@ -1498,7 +1501,9 @@ pmu_handle_data(unsigned char *data, int len)
via_pmu_event(PMU_EVT_POWER, !!(data[1]&8));
via_pmu_event(PMU_EVT_LID, data[1]&1);
}
- } else {
+ break;
+
+ default:
pmu_pass_intr(data, len);
}
goto next;
--
2.16.4
^ permalink raw reply related
* [PATCH v3 04/12] macintosh/via-pmu: Enhance state machine with new 'uninitialized' state
From: Finn Thain @ 2018-06-13 10:38 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Michael Schmitz, linuxppc-dev, linux-m68k, linux-kernel
In-Reply-To: <cover.1528885172.git.fthain@telegraphics.com.au>
On 68k Macs, the via/vias pointer can't be used to determine whether
the PMU driver has been initialized. For portability, add a new state
to indicate that via_find_pmu() succeeded.
After via_find_pmu() executes, testing vias == NULL is equivalent to
testing via == NULL. Replace these tests with pmu_state == uninitialized
which is simpler and more consistent. No functional change.
Tested-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
---
drivers/macintosh/via-pmu.c | 44 ++++++++++++++++++++++----------------------
1 file changed, 22 insertions(+), 22 deletions(-)
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 4c1bae5380c2..c4c324fb5fa6 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -114,6 +114,7 @@ static volatile unsigned char __iomem *via;
#define CB1_INT 0x10 /* transition on CB1 input */
static volatile enum pmu_state {
+ uninitialized = 0,
idle,
sending,
intack,
@@ -274,7 +275,7 @@ int __init find_via_pmu(void)
u64 taddr;
const u32 *reg;
- if (via != 0)
+ if (pmu_state != uninitialized)
return 1;
vias = of_find_node_by_name(NULL, "via-pmu");
if (vias == NULL)
@@ -369,20 +370,19 @@ int __init find_via_pmu(void)
fail:
of_node_put(vias);
vias = NULL;
+ pmu_state = uninitialized;
return 0;
}
#ifdef CONFIG_ADB
static int pmu_probe(void)
{
- return vias == NULL? -ENODEV: 0;
+ return pmu_state == uninitialized ? -ENODEV : 0;
}
static int pmu_init(void)
{
- if (vias == NULL)
- return -ENODEV;
- return 0;
+ return pmu_state == uninitialized ? -ENODEV : 0;
}
#endif /* CONFIG_ADB */
@@ -397,7 +397,7 @@ static int __init via_pmu_start(void)
{
unsigned int irq;
- if (vias == NULL)
+ if (pmu_state == uninitialized)
return -ENODEV;
batt_req.complete = 1;
@@ -463,7 +463,7 @@ arch_initcall(via_pmu_start);
*/
static int __init via_pmu_dev_init(void)
{
- if (vias == NULL)
+ if (pmu_state == uninitialized)
return -ENODEV;
#ifdef CONFIG_PMAC_BACKLIGHT
@@ -966,7 +966,7 @@ static int pmu_send_request(struct adb_request *req, int sync)
{
int i, ret;
- if ((vias == NULL) || (!pmu_fully_inited)) {
+ if (pmu_state == uninitialized || !pmu_fully_inited) {
req->complete = 1;
return -ENXIO;
}
@@ -1060,7 +1060,7 @@ static int __pmu_adb_autopoll(int devs)
static int pmu_adb_autopoll(int devs)
{
- if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb)
+ if (pmu_state == uninitialized || !pmu_fully_inited || !pmu_has_adb)
return -ENXIO;
adb_dev_map = devs;
@@ -1073,7 +1073,7 @@ static int pmu_adb_reset_bus(void)
struct adb_request req;
int save_autopoll = adb_dev_map;
- if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb)
+ if (pmu_state == uninitialized || !pmu_fully_inited || !pmu_has_adb)
return -ENXIO;
/* anyone got a better idea?? */
@@ -1109,7 +1109,7 @@ pmu_request(struct adb_request *req, void (*done)(struct adb_request *),
va_list list;
int i;
- if (vias == NULL)
+ if (pmu_state == uninitialized)
return -ENXIO;
if (nbytes < 0 || nbytes > 32) {
@@ -1134,7 +1134,7 @@ pmu_queue_request(struct adb_request *req)
unsigned long flags;
int nsend;
- if (via == NULL) {
+ if (pmu_state == uninitialized) {
req->complete = 1;
return -ENXIO;
}
@@ -1247,7 +1247,7 @@ pmu_start(void)
void
pmu_poll(void)
{
- if (!via)
+ if (pmu_state == uninitialized)
return;
if (disable_poll)
return;
@@ -1257,7 +1257,7 @@ pmu_poll(void)
void
pmu_poll_adb(void)
{
- if (!via)
+ if (pmu_state == uninitialized)
return;
if (disable_poll)
return;
@@ -1272,7 +1272,7 @@ pmu_poll_adb(void)
void
pmu_wait_complete(struct adb_request *req)
{
- if (!via)
+ if (pmu_state == uninitialized)
return;
while((pmu_state != idle && pmu_state != locked) || !req->complete)
via_pmu_interrupt(0, NULL);
@@ -1288,7 +1288,7 @@ pmu_suspend(void)
{
unsigned long flags;
- if (!via)
+ if (pmu_state == uninitialized)
return;
spin_lock_irqsave(&pmu_lock, flags);
@@ -1319,7 +1319,7 @@ pmu_resume(void)
{
unsigned long flags;
- if (!via || (pmu_suspended < 1))
+ if (pmu_state == uninitialized || pmu_suspended < 1)
return;
spin_lock_irqsave(&pmu_lock, flags);
@@ -1681,7 +1681,7 @@ pmu_enable_irled(int on)
{
struct adb_request req;
- if (vias == NULL)
+ if (pmu_state == uninitialized)
return ;
if (pmu_kind == PMU_KEYLARGO_BASED)
return ;
@@ -1696,7 +1696,7 @@ pmu_restart(void)
{
struct adb_request req;
- if (via == NULL)
+ if (pmu_state == uninitialized)
return;
local_irq_disable();
@@ -1721,7 +1721,7 @@ pmu_shutdown(void)
{
struct adb_request req;
- if (via == NULL)
+ if (pmu_state == uninitialized)
return;
local_irq_disable();
@@ -1749,7 +1749,7 @@ pmu_shutdown(void)
int
pmu_present(void)
{
- return via != 0;
+ return pmu_state != uninitialized;
}
#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
@@ -2415,7 +2415,7 @@ static struct miscdevice pmu_device = {
static int pmu_device_init(void)
{
- if (!via)
+ if (pmu_state == uninitialized)
return 0;
if (misc_register(&pmu_device) < 0)
printk(KERN_ERR "via-pmu: cannot register misc device.\n");
--
2.16.4
^ permalink raw reply related
* [PATCH v3 01/12] macintosh/via-pmu: Fix section mismatch warning
From: Finn Thain @ 2018-06-13 10:38 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Michael Schmitz, linuxppc-dev, linux-m68k, linux-kernel
In-Reply-To: <cover.1528885172.git.fthain@telegraphics.com.au>
The pmu_init() function has the __init qualifier, but the ops struct
that holds a pointer to it does not. This causes a build warning.
The driver works fine because the pointer is only dereferenced early.
The function is so small that there's negligible benefit from using
the __init qualifier. Remove it to fix the warning, consistent with
the other ADB drivers.
Tested-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org>
---
drivers/macintosh/via-pmu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 433dbeddfcf9..fd3c5640d586 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -378,7 +378,7 @@ static int pmu_probe(void)
return vias == NULL? -ENODEV: 0;
}
-static int __init pmu_init(void)
+static int pmu_init(void)
{
if (vias == NULL)
return -ENODEV;
--
2.16.4
^ permalink raw reply related
* [PATCH v3 03/12] macintosh/via-pmu: Don't clear shift register interrupt flag twice
From: Finn Thain @ 2018-06-13 10:38 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Michael Schmitz, linuxppc-dev, linux-m68k, linux-kernel
In-Reply-To: <cover.1528885172.git.fthain@telegraphics.com.au>
The shift register interrupt flag gets cleared in via_pmu_interrupt()
and once again in pmu_sr_intr(). Fix this theoretical race condition.
Tested-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org>
---
drivers/macintosh/via-pmu.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 74065ea410bd..4c1bae5380c2 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -1458,7 +1458,6 @@ pmu_sr_intr(void)
if (in_8(&via[B]) & TREQ) {
printk(KERN_ERR "PMU: spurious SR intr (%x)\n", in_8(&via[B]));
- out_8(&via[IFR], SR_INT);
return NULL;
}
/* The ack may not yet be low when we get the interrupt */
--
2.16.4
^ permalink raw reply related
* [PATCH v3 00/12] macintosh: Resolve various PMU driver problems
From: Finn Thain @ 2018-06-13 10:38 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Michael Schmitz, linuxppc-dev, linux-m68k, linux-kernel
This series of patches has the following aims.
1) Eliminate duplicated code. Linux presently has two drivers for
the 68HC05-based PMU devices found in Macs: via-pmu and via-pmu68k.
There's no value in having separate PMU drivers for each architecture.
2) Avoid further work on via-pmu68k that's not needed for via-pmu.
3) Fix some bugs in the via-pmu driver.
4) Enable the /dev/pmu and /proc/pmu/* userspace APIs on m68k Macs
by adopting via-pmu.
5) Improve stability on early 100-series PowerBooks by loading no PMU
driver at all. Neither via-pmu nor via-pmu68k supports the early
M50753-based PMU device found in these models.
6) Eliminate duplicated RTC accessors for PMU and Cuda. Presently these
can be found under both arch/m68k and arch/powerpc.
7) Assist the out-of-tree NuBus PowerMac port to support PMU designs
shared with the m68k Mac port (e.g. PowerBooks 190 and 5300).
This patch series has been regression tested on various PowerBooks
(190, 520, 3400, Pismo G3) and PowerMacs (Beige G3, G5). These patches
did not affect userland utilities. (Note that there is a userland-
visible change to the contents of /proc/pmu/interrupts.)
Changed since v1:
1) Added blank lines after 'break' statements in patch 10.
2) Improved patch description for patch 3.
3) Added reviewed-by tags.
4) Split patch 8 to make code review easier.
Changed since v2:
1) Added reviewed-by tag.
2) Retained PMU_68K_V1 and PMU_68K_V2 symbols.
Finn Thain (12):
macintosh/via-pmu: Fix section mismatch warning
macintosh/via-pmu: Add missing mmio accessors
macintosh/via-pmu: Don't clear shift register interrupt flag twice
macintosh/via-pmu: Enhance state machine with new 'uninitialized'
state
macintosh/via-pmu: Replace via pointer with via1 and via2 pointers
macintosh/via-pmu: Add support for m68k PowerBooks
macintosh/via-pmu: Make CONFIG_PPC_PMAC Kconfig deps explicit
macintosh/via-pmu68k: Don't load driver on unsupported hardware
macintosh/via-pmu: Replace via-pmu68k driver with via-pmu driver
macintosh: Use common code to access RTC
macintosh/via-pmu: Clean up interrupt statistics
macintosh/via-pmu: Disambiguate interrupt statistics
arch/m68k/configs/mac_defconfig | 2 +-
arch/m68k/configs/multi_defconfig | 2 +-
arch/m68k/mac/config.c | 2 +-
arch/m68k/mac/misc.c | 118 +----
arch/powerpc/platforms/powermac/time.c | 74 +--
drivers/macintosh/Kconfig | 19 +-
drivers/macintosh/Makefile | 1 -
drivers/macintosh/adb.c | 2 +-
drivers/macintosh/via-cuda.c | 34 ++
drivers/macintosh/via-pmu.c | 378 ++++++++++-----
drivers/macintosh/via-pmu68k.c | 850 ---------------------------------
include/linux/cuda.h | 3 +
include/linux/pmu.h | 3 +
include/uapi/linux/pmu.h | 4 +-
14 files changed, 313 insertions(+), 1179 deletions(-)
delete mode 100644 drivers/macintosh/via-pmu68k.c
--
2.16.4
^ permalink raw reply
* [PATCH v3 02/12] macintosh/via-pmu: Add missing mmio accessors
From: Finn Thain @ 2018-06-13 10:38 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Michael Schmitz, linuxppc-dev, linux-m68k, linux-kernel
In-Reply-To: <cover.1528885172.git.fthain@telegraphics.com.au>
Add missing in_8() accessors to init_pmu() and pmu_sr_intr().
This fixes several sparse warnings:
drivers/macintosh/via-pmu.c:536:29: warning: dereference of noderef expression
drivers/macintosh/via-pmu.c:537:33: warning: dereference of noderef expression
drivers/macintosh/via-pmu.c:1455:17: warning: dereference of noderef expression
drivers/macintosh/via-pmu.c:1456:69: warning: dereference of noderef expression
Tested-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org>
---
drivers/macintosh/via-pmu.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index fd3c5640d586..74065ea410bd 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -532,8 +532,9 @@ init_pmu(void)
int timeout;
struct adb_request req;
- out_8(&via[B], via[B] | TREQ); /* negate TREQ */
- out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */
+ /* Negate TREQ. Set TACK to input and TREQ to output. */
+ out_8(&via[B], in_8(&via[B]) | TREQ);
+ out_8(&via[DIRB], (in_8(&via[DIRB]) | TREQ) & ~TACK);
pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
timeout = 100000;
@@ -1455,8 +1456,8 @@ pmu_sr_intr(void)
struct adb_request *req;
int bite = 0;
- if (via[B] & TREQ) {
- printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]);
+ if (in_8(&via[B]) & TREQ) {
+ printk(KERN_ERR "PMU: spurious SR intr (%x)\n", in_8(&via[B]));
out_8(&via[IFR], SR_INT);
return NULL;
}
--
2.16.4
^ permalink raw reply related
* Re: [RFC PATCH 03/23] genirq: Introduce IRQF_DELIVER_AS_NMI
From: Julien Thierry @ 2018-06-13 10:25 UTC (permalink / raw)
To: Thomas Gleixner
Cc: Peter Zijlstra, Ricardo Neri, Ingo Molnar, H. Peter Anvin,
Andi Kleen, Ashok Raj, Borislav Petkov, Tony Luck,
Ravi V. Shankar, x86, sparclinux, linuxppc-dev, linux-kernel,
Jacob Pan, Daniel Lezcano, Andrew Morton,
Levin, Alexander (Sasha Levin), Randy Dunlap, Masami Hiramatsu,
Marc Zyngier, Bartosz Golaszewski, Doug Berger, Palmer Dabbelt,
iommu
In-Reply-To: <alpine.DEB.2.21.1806131149410.2280@nanos.tec.linutronix.de>
On 13/06/18 10:57, Thomas Gleixner wrote:
> On Wed, 13 Jun 2018, Julien Thierry wrote:
>> On 13/06/18 10:20, Thomas Gleixner wrote:
>>> Adding NMI delivery support at low level architecture irq chip level is
>>> perfectly fine, but the exposure of that needs to be restricted very
>>> much. Adding it to the generic interrupt control interfaces is not going to
>>> happen. That's doomed to begin with and a complete abuse of the interface
>>> as the handler can not ever be used for that.
>>>
>>
>> Understood, however the need would be to provide a way for a driver to request
>> an interrupt to be delivered as an NMI (if irqchip supports it).
>
> s/driver/specialized code written by people who know what they are doing/
>
>> But from your response this would be out of the question (in the
>> interrupt/irq/irqchip definitions).
>
> Adding some magic to the irq chip is fine, because that's where the low
> level integration needs to be done, but exposing it through the generic
> interrupt subsystem is a NONO for obvious reasons.
>
>> Or somehow the concerned irqchip informs the arch it supports NMI delivery and
>> it is up to the interested drivers to query the arch whether NMI delivery is
>> supported by the system?
>
> Yes, we need some infrastructure for that, but that needs to be separate
> and with very limited exposure.
>
Right, makes sense. I'll check with Marc how such an infrastructure
should be introduced.
Thanks,
--
Julien Thierry
^ permalink raw reply
* Re: [RFC PATCH 03/23] genirq: Introduce IRQF_DELIVER_AS_NMI
From: Marc Zyngier @ 2018-06-13 10:06 UTC (permalink / raw)
To: Thomas Gleixner, Julien Thierry
Cc: Peter Zijlstra, Ricardo Neri, Ingo Molnar, H. Peter Anvin,
Andi Kleen, Ashok Raj, Borislav Petkov, Tony Luck,
Ravi V. Shankar, x86, sparclinux, linuxppc-dev, linux-kernel,
Jacob Pan, Daniel Lezcano, Andrew Morton,
Levin, Alexander (Sasha Levin), Randy Dunlap, Masami Hiramatsu,
Bartosz Golaszewski, Doug Berger, Palmer Dabbelt, iommu
In-Reply-To: <alpine.DEB.2.21.1806131104570.2280@nanos.tec.linutronix.de>
On 13/06/18 10:20, Thomas Gleixner wrote:
> On Wed, 13 Jun 2018, Julien Thierry wrote:
>> On 13/06/18 09:34, Peter Zijlstra wrote:
>>> On Tue, Jun 12, 2018 at 05:57:23PM -0700, Ricardo Neri wrote:
>>>> diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
>>>> index 5426627..dbc5e02 100644
>>>> --- a/include/linux/interrupt.h
>>>> +++ b/include/linux/interrupt.h
>>>> @@ -61,6 +61,8 @@
>>>> * interrupt handler after suspending interrupts. For
>>>> system
>>>> * wakeup devices users need to implement wakeup
>>>> detection in
>>>> * their interrupt handlers.
>>>> + * IRQF_DELIVER_AS_NMI - Configure interrupt to be delivered as
>>>> non-maskable, if
>>>> + * supported by the chip.
>>>> */
>>>
>>> NAK on the first 6 patches. You really _REALLY_ don't want to expose
>>> NMIs to this level.
>>>
>>
>> I've been working on something similar on arm64 side, and effectively the one
>> thing that might be common to arm64 and intel is the interface to set an
>> interrupt as NMI. So I guess it would be nice to agree on the right approach
>> for this.
>>
>> The way I did it was by introducing a new irq_state and let the irqchip driver
>> handle most of the work (if it supports that state):
>>
>> https://lkml.org/lkml/2018/5/25/181
>>
>> This has not been ACKed nor NAKed. So I am just asking whether this is a more
>> suitable approach, and if not, is there any suggestions on how to do this?
>
> I really didn't pay attention to that as it's burried in the GIC/ARM series
> which is usually Marc's playground.
I'm working my way through it ATM now that I have some brain cycles back.
> Adding NMI delivery support at low level architecture irq chip level is
> perfectly fine, but the exposure of that needs to be restricted very
> much. Adding it to the generic interrupt control interfaces is not going to
> happen. That's doomed to begin with and a complete abuse of the interface
> as the handler can not ever be used for that.
I can only agree with that. Allowing random driver to use request_irq()
to make anything an NMI ultimately turns it into a complete mess ("hey,
NMI is *faster*, let's use that"), and a potential source of horrible
deadlocks.
What I'd find more palatable is a way for an irqchip to be able to
prioritize some interrupts based on a set of architecturally-defined
requirements, and a separate NMI requesting/handling framework that is
separate from the IRQ API, as the overall requirements are likely to
completely different.
It shouldn't have to be nearly as complex as the IRQ API, and require
much stricter requirements in terms of what you can do there (flow
handling should definitely be different).
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* [PATCH] powerpc/64s/radix: Fix MADV_[FREE|DONTNEED] TLB flush miss problem with THP
From: Nicholas Piggin @ 2018-06-13 9:58 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nicholas Piggin, Aneesh Kumar K . V
The patch 99baac21e4 ("mm: fix MADV_[FREE|DONTNEED] TLB flush miss
problem") added a force flush mode to the mmu_gather flush, which
unconditionally flushes the entire address range being invalidated
(even if actual ptes only covered a smaller range), to solve a problem
with concurrent threads invalidating the same PTEs causing them to
miss TLBs that need flushing.
This does not work with powerpc that invalidates mmu_gather batches
according to page size. Have powerpc flush all possible page sizes in
the range if it encounters the concurrency condition.
Hash does not have a problem because it invalidates TLBs inside the
page table locks.
Reported-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
Since RFC:
- Account for hugetlb pages that can be mixed with the tlb_flush
range.
arch/powerpc/mm/tlb-radix.c | 85 ++++++++++++++++++++++++++++---------
1 file changed, 66 insertions(+), 19 deletions(-)
diff --git a/arch/powerpc/mm/tlb-radix.c b/arch/powerpc/mm/tlb-radix.c
index 67a6e86d3e7e..9dbccda651d7 100644
--- a/arch/powerpc/mm/tlb-radix.c
+++ b/arch/powerpc/mm/tlb-radix.c
@@ -689,22 +689,17 @@ EXPORT_SYMBOL(radix__flush_tlb_kernel_range);
static unsigned long tlb_single_page_flush_ceiling __read_mostly = 33;
static unsigned long tlb_local_single_page_flush_ceiling __read_mostly = POWER9_TLB_SETS_RADIX * 2;
-void radix__flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
- unsigned long end)
+static inline void __radix__flush_tlb_range(struct mm_struct *mm,
+ unsigned long start, unsigned long end,
+ bool flush_all_sizes)
{
- struct mm_struct *mm = vma->vm_mm;
unsigned long pid;
unsigned int page_shift = mmu_psize_defs[mmu_virtual_psize].shift;
unsigned long page_size = 1UL << page_shift;
unsigned long nr_pages = (end - start) >> page_shift;
bool local, full;
-#ifdef CONFIG_HUGETLB_PAGE
- if (is_vm_hugetlb_page(vma))
- return radix__flush_hugetlb_tlb_range(vma, start, end);
-#endif
-
pid = mm->context.id;
if (unlikely(pid == MMU_NO_CONTEXT))
return;
@@ -738,18 +733,27 @@ void radix__flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
_tlbie_pid(pid, RIC_FLUSH_TLB);
}
} else {
- bool hflush = false;
+ bool hflush = flush_all_sizes;
+ bool gflush = flush_all_sizes;
unsigned long hstart, hend;
+ unsigned long gstart, gend;
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
- hstart = (start + HPAGE_PMD_SIZE - 1) >> HPAGE_PMD_SHIFT;
- hend = end >> HPAGE_PMD_SHIFT;
- if (hstart < hend) {
- hstart <<= HPAGE_PMD_SHIFT;
- hend <<= HPAGE_PMD_SHIFT;
+ if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
hflush = true;
+
+ if (hflush) {
+ hstart = (start + HPAGE_PMD_SIZE - 1) & HPAGE_PMD_MASK;
+ hend = end & HPAGE_PMD_MASK;
+ if (hstart == hend)
+ hflush = false;
+ }
+
+ if (gflush) {
+ gstart = (start + HPAGE_PUD_SIZE - 1) & HPAGE_PUD_MASK;
+ gend = end & HPAGE_PUD_MASK;
+ if (gstart == gend)
+ gflush = false;
}
-#endif
asm volatile("ptesync": : :"memory");
if (local) {
@@ -757,18 +761,36 @@ void radix__flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
if (hflush)
__tlbiel_va_range(hstart, hend, pid,
HPAGE_PMD_SIZE, MMU_PAGE_2M);
+ if (gflush)
+ __tlbiel_va_range(gstart, gend, pid,
+ HPAGE_PUD_SIZE, MMU_PAGE_1G);
asm volatile("ptesync": : :"memory");
} else {
__tlbie_va_range(start, end, pid, page_size, mmu_virtual_psize);
if (hflush)
__tlbie_va_range(hstart, hend, pid,
HPAGE_PMD_SIZE, MMU_PAGE_2M);
+ if (gflush)
+ __tlbie_va_range(gstart, gend, pid,
+ HPAGE_PUD_SIZE, MMU_PAGE_1G);
fixup_tlbie();
asm volatile("eieio; tlbsync; ptesync": : :"memory");
}
}
preempt_enable();
}
+
+void radix__flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+
+{
+#ifdef CONFIG_HUGETLB_PAGE
+ if (is_vm_hugetlb_page(vma))
+ return radix__flush_hugetlb_tlb_range(vma, start, end);
+#endif
+
+ __radix__flush_tlb_range(vma->vm_mm, start, end, false);
+}
EXPORT_SYMBOL(radix__flush_tlb_range);
static int radix_get_mmu_psize(int page_size)
@@ -837,6 +859,8 @@ void radix__tlb_flush(struct mmu_gather *tlb)
int psize = 0;
struct mm_struct *mm = tlb->mm;
int page_size = tlb->page_size;
+ unsigned long start = tlb->start;
+ unsigned long end = tlb->end;
/*
* if page size is not something we understand, do a full mm flush
@@ -847,15 +871,38 @@ void radix__tlb_flush(struct mmu_gather *tlb)
*/
if (tlb->fullmm) {
__flush_all_mm(mm, true);
+#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_HUGETLB_PAGE)
+ } else if (mm_tlb_flush_pending(mm)) {
+ /*
+ * If there is a concurrent invalidation that is clearing ptes,
+ * then it's possible this invalidation will miss one of those
+ * cleared ptes and miss flushing the TLB. If this invalidate
+ * returns before the other one flushes TLBs, that can result
+ * in it returning while there are still valid TLBs inside the
+ * range to be invalidated.
+ *
+ * See mm/memory.c:tlb_finish_mmu() for more details.
+ *
+ * The solution to this is ensure the entire range is always
+ * flushed here. The problem for powerpc is that the flushes
+ * are page size specific, so this "forced flush" would not
+ * do the right thing if there are a mix of page sizes in
+ * the range to be invalidated. So use __flush_tlb_range
+ * which invalidates all possible page sizes in the range.
+ *
+ * PWC flush probably is not be required because the core code
+ * shouldn't free page tables in this path, but accounting
+ * for the possibility makes us a bit more robust.
+ */
+ WARN_ON_ONCE(tlb->need_flush_all);
+ __radix__flush_tlb_range(mm, start, end, true);
+#endif
} else if ( (psize = radix_get_mmu_psize(page_size)) == -1) {
if (!tlb->need_flush_all)
radix__flush_tlb_mm(mm);
else
radix__flush_all_mm(mm);
} else {
- unsigned long start = tlb->start;
- unsigned long end = tlb->end;
-
if (!tlb->need_flush_all)
radix__flush_tlb_range_psize(mm, start, end, psize);
else
--
2.17.0
^ permalink raw reply related
* Re: [RFC PATCH 03/23] genirq: Introduce IRQF_DELIVER_AS_NMI
From: Thomas Gleixner @ 2018-06-13 9:57 UTC (permalink / raw)
To: Julien Thierry
Cc: Peter Zijlstra, Ricardo Neri, Ingo Molnar, H. Peter Anvin,
Andi Kleen, Ashok Raj, Borislav Petkov, Tony Luck,
Ravi V. Shankar, x86, sparclinux, linuxppc-dev, linux-kernel,
Jacob Pan, Daniel Lezcano, Andrew Morton,
Levin, Alexander (Sasha Levin), Randy Dunlap, Masami Hiramatsu,
Marc Zyngier, Bartosz Golaszewski, Doug Berger, Palmer Dabbelt,
iommu
In-Reply-To: <344b838e-81e3-97d8-f90d-315fed7879c1@arm.com>
On Wed, 13 Jun 2018, Julien Thierry wrote:
> On 13/06/18 10:20, Thomas Gleixner wrote:
> > Adding NMI delivery support at low level architecture irq chip level is
> > perfectly fine, but the exposure of that needs to be restricted very
> > much. Adding it to the generic interrupt control interfaces is not going to
> > happen. That's doomed to begin with and a complete abuse of the interface
> > as the handler can not ever be used for that.
> >
>
> Understood, however the need would be to provide a way for a driver to request
> an interrupt to be delivered as an NMI (if irqchip supports it).
s/driver/specialized code written by people who know what they are doing/
> But from your response this would be out of the question (in the
> interrupt/irq/irqchip definitions).
Adding some magic to the irq chip is fine, because that's where the low
level integration needs to be done, but exposing it through the generic
interrupt subsystem is a NONO for obvious reasons.
> Or somehow the concerned irqchip informs the arch it supports NMI delivery and
> it is up to the interested drivers to query the arch whether NMI delivery is
> supported by the system?
Yes, we need some infrastructure for that, but that needs to be separate
and with very limited exposure.
Thanks,
tglx
^ permalink raw reply
* Re: [RFC PATCH 03/23] genirq: Introduce IRQF_DELIVER_AS_NMI
From: Julien Thierry @ 2018-06-13 9:49 UTC (permalink / raw)
To: Thomas Gleixner
Cc: Peter Zijlstra, Ricardo Neri, Ingo Molnar, H. Peter Anvin,
Andi Kleen, Ashok Raj, Borislav Petkov, Tony Luck,
Ravi V. Shankar, x86, sparclinux, linuxppc-dev, linux-kernel,
Jacob Pan, Daniel Lezcano, Andrew Morton,
Levin, Alexander (Sasha Levin), Randy Dunlap, Masami Hiramatsu,
Marc Zyngier, Bartosz Golaszewski, Doug Berger, Palmer Dabbelt,
iommu
In-Reply-To: <344b838e-81e3-97d8-f90d-315fed7879c1@arm.com>
On 13/06/18 10:36, Julien Thierry wrote:
>
>
> On 13/06/18 10:20, Thomas Gleixner wrote:
>> On Wed, 13 Jun 2018, Julien Thierry wrote:
>>> On 13/06/18 09:34, Peter Zijlstra wrote:
>>>> On Tue, Jun 12, 2018 at 05:57:23PM -0700, Ricardo Neri wrote:
>>>>> diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
>>>>> index 5426627..dbc5e02 100644
>>>>> --- a/include/linux/interrupt.h
>>>>> +++ b/include/linux/interrupt.h
>>>>> @@ -61,6 +61,8 @@
>>>>> * interrupt handler after suspending interrupts.
>>>>> For
>>>>> system
>>>>> * wakeup devices users need to implement wakeup
>>>>> detection in
>>>>> * their interrupt handlers.
>>>>> + * IRQF_DELIVER_AS_NMI - Configure interrupt to be delivered as
>>>>> non-maskable, if
>>>>> + * supported by the chip.
>>>>> */
>>>>
>>>> NAK on the first 6 patches. You really _REALLY_ don't want to expose
>>>> NMIs to this level.
>>>>
>>>
>>> I've been working on something similar on arm64 side, and effectively
>>> the one
>>> thing that might be common to arm64 and intel is the interface to set an
>>> interrupt as NMI. So I guess it would be nice to agree on the right
>>> approach
>>> for this.
>>>
>>> The way I did it was by introducing a new irq_state and let the
>>> irqchip driver
>>> handle most of the work (if it supports that state):
>>>
>>> https://lkml.org/lkml/2018/5/25/181
>>>
>>> This has not been ACKed nor NAKed. So I am just asking whether this
>>> is a more
>>> suitable approach, and if not, is there any suggestions on how to do
>>> this?
>>
>> I really didn't pay attention to that as it's burried in the GIC/ARM
>> series
>> which is usually Marc's playground.
>>
>> Adding NMI delivery support at low level architecture irq chip level is
>> perfectly fine, but the exposure of that needs to be restricted very
>> much. Adding it to the generic interrupt control interfaces is not
>> going to
>> happen. That's doomed to begin with and a complete abuse of the interface
>> as the handler can not ever be used for that.
>>
>
> Understood, however the need would be to provide a way for a driver to
> request an interrupt to be delivered as an NMI (if irqchip supports it).
>
> But from your response this would be out of the question (in the
> interrupt/irq/irqchip definitions).
>
> Or somehow the concerned irqchip informs the arch it supports NMI
> delivery and it is up to the interested drivers to query the arch
> whether NMI delivery is supported by the system?
Actually scratch that last part, it is also missing a way for the driver
to actually communicate to the irqchip that its interrupt should be
treated as an NMI, so it wouldn't work...
--
Julien Thierry
^ permalink raw reply
* Re: [RFC PATCH 20/23] watchdog/hardlockup/hpet: Rotate interrupt among all monitored CPUs
From: Thomas Gleixner @ 2018-06-13 9:48 UTC (permalink / raw)
To: Ricardo Neri
Cc: Ingo Molnar, H. Peter Anvin, Andi Kleen, Ashok Raj,
Borislav Petkov, Tony Luck, Ravi V. Shankar, x86, sparclinux,
linuxppc-dev, linux-kernel, Jacob Pan, Rafael J. Wysocki,
Don Zickus, Nicholas Piggin, Michael Ellerman,
Frederic Weisbecker, Alexei Starovoitov, Babu Moger,
Mathieu Desnoyers, Masami Hiramatsu, Peter Zijlstra,
Andrew Morton, Philippe Ombredanne, Colin Ian King,
Byungchul Park, Paul E. McKenney, Luis R. Rodriguez, Waiman Long,
Josh Poimboeuf, Randy Dunlap, Davidlohr Bueso, Christoffer Dall,
Marc Zyngier, Kai-Heng Feng, Konrad Rzeszutek Wilk,
David Rientjes, iommu
In-Reply-To: <1528851463-21140-21-git-send-email-ricardo.neri-calderon@linux.intel.com>
On Tue, 12 Jun 2018, Ricardo Neri wrote:
> + /* There are no CPUs to monitor. */
> + if (!cpumask_weight(&hdata->monitored_mask))
> + return NMI_HANDLED;
> +
> inspect_for_hardlockups(regs);
>
> + /*
> + * Target a new CPU. Keep trying until we find a monitored CPU. CPUs
> + * are addded and removed to this mask at cpu_up() and cpu_down(),
> + * respectively. Thus, the interrupt should be able to be moved to
> + * the next monitored CPU.
> + */
> + spin_lock(&hld_data->lock);
Yuck. Taking a spinlock from NMI ...
> + for_each_cpu_wrap(cpu, &hdata->monitored_mask, smp_processor_id() + 1) {
> + if (!irq_set_affinity(hld_data->irq, cpumask_of(cpu)))
> + break;
... and then calling into generic interrupt code which will take even more
locks is completely broken.
Guess what happens when the NMI hits a section where one of those locks is
held? Then you need another watchdog to decode the lockup you just ran into.
Thanks,
tglx
^ permalink raw reply
* Re: [RFC PATCH 17/23] watchdog/hardlockup/hpet: Convert the timer's interrupt to NMI
From: Thomas Gleixner @ 2018-06-13 9:40 UTC (permalink / raw)
To: Ricardo Neri
Cc: Ingo Molnar, H. Peter Anvin, Andi Kleen, Ashok Raj,
Borislav Petkov, Tony Luck, Ravi V. Shankar, x86, sparclinux,
linuxppc-dev, linux-kernel, Jacob Pan, Rafael J. Wysocki,
Don Zickus, Nicholas Piggin, Michael Ellerman,
Frederic Weisbecker, Alexei Starovoitov, Babu Moger,
Mathieu Desnoyers, Masami Hiramatsu, Peter Zijlstra,
Andrew Morton, Philippe Ombredanne, Colin Ian King,
Byungchul Park, Paul E. McKenney, Luis R. Rodriguez, Waiman Long,
Josh Poimboeuf, Randy Dunlap, Davidlohr Bueso, Christoffer Dall,
Marc Zyngier, Kai-Heng Feng, Konrad Rzeszutek Wilk,
David Rientjes, iommu
In-Reply-To: <1528851463-21140-18-git-send-email-ricardo.neri-calderon@linux.intel.com>
On Tue, 12 Jun 2018, Ricardo Neri wrote:
> @@ -183,6 +184,8 @@ static irqreturn_t hardlockup_detector_irq_handler(int irq, void *data)
> if (!(hdata->flags & HPET_DEV_PERI_CAP))
> kick_timer(hdata);
>
> + pr_err("This interrupt should not have happened. Ensure delivery mode is NMI.\n");
Eeew.
> /**
> + * hardlockup_detector_nmi_handler() - NMI Interrupt handler
> + * @val: Attribute associated with the NMI. Not used.
> + * @regs: Register values as seen when the NMI was asserted
> + *
> + * When an NMI is issued, look for hardlockups. If the timer is not periodic,
> + * kick it. The interrupt is always handled when if delivered via the
> + * Front-Side Bus.
> + *
> + * Returns:
> + *
> + * NMI_DONE if the HPET timer did not cause the interrupt. NMI_HANDLED
> + * otherwise.
> + */
> +static int hardlockup_detector_nmi_handler(unsigned int val,
> + struct pt_regs *regs)
> +{
> + struct hpet_hld_data *hdata = hld_data;
> + unsigned int use_fsb;
> +
> + /*
> + * If FSB delivery mode is used, the timer interrupt is programmed as
> + * edge-triggered and there is no need to check the ISR register.
> + */
> + use_fsb = hdata->flags & HPET_DEV_FSB_CAP;
> +
> + if (!use_fsb && !is_hpet_wdt_interrupt(hdata))
> + return NMI_DONE;
So for 'use_fsb == True' every single NMI will fall through into the
watchdog code below.
> + inspect_for_hardlockups(regs);
> +
> + if (!(hdata->flags & HPET_DEV_PERI_CAP))
> + kick_timer(hdata);
And in case that the HPET does not support periodic mode this reprogramms
the timer on every NMI which means that while perf is running the watchdog
will never ever detect anything.
Aside of that, reading TWO HPET registers for every NMI is insane. HPET
access is horribly slow, so any high frequency perf monitoring will take a
massive performance hit.
Thanks,
tglx
^ permalink raw reply
* Re: [RFC PATCH 03/23] genirq: Introduce IRQF_DELIVER_AS_NMI
From: Julien Thierry @ 2018-06-13 9:36 UTC (permalink / raw)
To: Thomas Gleixner
Cc: Peter Zijlstra, Ricardo Neri, Ingo Molnar, H. Peter Anvin,
Andi Kleen, Ashok Raj, Borislav Petkov, Tony Luck,
Ravi V. Shankar, x86, sparclinux, linuxppc-dev, linux-kernel,
Jacob Pan, Daniel Lezcano, Andrew Morton,
Levin, Alexander (Sasha Levin), Randy Dunlap, Masami Hiramatsu,
Marc Zyngier, Bartosz Golaszewski, Doug Berger, Palmer Dabbelt,
iommu
In-Reply-To: <alpine.DEB.2.21.1806131104570.2280@nanos.tec.linutronix.de>
On 13/06/18 10:20, Thomas Gleixner wrote:
> On Wed, 13 Jun 2018, Julien Thierry wrote:
>> On 13/06/18 09:34, Peter Zijlstra wrote:
>>> On Tue, Jun 12, 2018 at 05:57:23PM -0700, Ricardo Neri wrote:
>>>> diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
>>>> index 5426627..dbc5e02 100644
>>>> --- a/include/linux/interrupt.h
>>>> +++ b/include/linux/interrupt.h
>>>> @@ -61,6 +61,8 @@
>>>> * interrupt handler after suspending interrupts. For
>>>> system
>>>> * wakeup devices users need to implement wakeup
>>>> detection in
>>>> * their interrupt handlers.
>>>> + * IRQF_DELIVER_AS_NMI - Configure interrupt to be delivered as
>>>> non-maskable, if
>>>> + * supported by the chip.
>>>> */
>>>
>>> NAK on the first 6 patches. You really _REALLY_ don't want to expose
>>> NMIs to this level.
>>>
>>
>> I've been working on something similar on arm64 side, and effectively the one
>> thing that might be common to arm64 and intel is the interface to set an
>> interrupt as NMI. So I guess it would be nice to agree on the right approach
>> for this.
>>
>> The way I did it was by introducing a new irq_state and let the irqchip driver
>> handle most of the work (if it supports that state):
>>
>> https://lkml.org/lkml/2018/5/25/181
>>
>> This has not been ACKed nor NAKed. So I am just asking whether this is a more
>> suitable approach, and if not, is there any suggestions on how to do this?
>
> I really didn't pay attention to that as it's burried in the GIC/ARM series
> which is usually Marc's playground.
>
> Adding NMI delivery support at low level architecture irq chip level is
> perfectly fine, but the exposure of that needs to be restricted very
> much. Adding it to the generic interrupt control interfaces is not going to
> happen. That's doomed to begin with and a complete abuse of the interface
> as the handler can not ever be used for that.
>
Understood, however the need would be to provide a way for a driver to
request an interrupt to be delivered as an NMI (if irqchip supports it).
But from your response this would be out of the question (in the
interrupt/irq/irqchip definitions).
Or somehow the concerned irqchip informs the arch it supports NMI
delivery and it is up to the interested drivers to query the arch
whether NMI delivery is supported by the system?
Thanks,
--
Julien Thierry
^ permalink raw reply
* Re: [RFC PATCH 03/23] genirq: Introduce IRQF_DELIVER_AS_NMI
From: Thomas Gleixner @ 2018-06-13 9:20 UTC (permalink / raw)
To: Julien Thierry
Cc: Peter Zijlstra, Ricardo Neri, Ingo Molnar, H. Peter Anvin,
Andi Kleen, Ashok Raj, Borislav Petkov, Tony Luck,
Ravi V. Shankar, x86, sparclinux, linuxppc-dev, linux-kernel,
Jacob Pan, Daniel Lezcano, Andrew Morton,
Levin, Alexander (Sasha Levin), Randy Dunlap, Masami Hiramatsu,
Marc Zyngier, Bartosz Golaszewski, Doug Berger, Palmer Dabbelt,
iommu
In-Reply-To: <26687332-ab8f-7f6d-909a-f0918dbfea86@arm.com>
On Wed, 13 Jun 2018, Julien Thierry wrote:
> On 13/06/18 09:34, Peter Zijlstra wrote:
> > On Tue, Jun 12, 2018 at 05:57:23PM -0700, Ricardo Neri wrote:
> > > diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
> > > index 5426627..dbc5e02 100644
> > > --- a/include/linux/interrupt.h
> > > +++ b/include/linux/interrupt.h
> > > @@ -61,6 +61,8 @@
> > > * interrupt handler after suspending interrupts. For
> > > system
> > > * wakeup devices users need to implement wakeup
> > > detection in
> > > * their interrupt handlers.
> > > + * IRQF_DELIVER_AS_NMI - Configure interrupt to be delivered as
> > > non-maskable, if
> > > + * supported by the chip.
> > > */
> >
> > NAK on the first 6 patches. You really _REALLY_ don't want to expose
> > NMIs to this level.
> >
>
> I've been working on something similar on arm64 side, and effectively the one
> thing that might be common to arm64 and intel is the interface to set an
> interrupt as NMI. So I guess it would be nice to agree on the right approach
> for this.
>
> The way I did it was by introducing a new irq_state and let the irqchip driver
> handle most of the work (if it supports that state):
>
> https://lkml.org/lkml/2018/5/25/181
>
> This has not been ACKed nor NAKed. So I am just asking whether this is a more
> suitable approach, and if not, is there any suggestions on how to do this?
I really didn't pay attention to that as it's burried in the GIC/ARM series
which is usually Marc's playground.
Adding NMI delivery support at low level architecture irq chip level is
perfectly fine, but the exposure of that needs to be restricted very
much. Adding it to the generic interrupt control interfaces is not going to
happen. That's doomed to begin with and a complete abuse of the interface
as the handler can not ever be used for that.
Thanks,
tglx
^ permalink raw reply
* Re: [RFC PATCH 12/23] kernel/watchdog: Introduce a struct for NMI watchdog operations
From: Thomas Gleixner @ 2018-06-13 9:26 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Nicholas Piggin, Ricardo Neri, Ingo Molnar, H. Peter Anvin,
Andi Kleen, Ashok Raj, Borislav Petkov, Tony Luck,
Ravi V. Shankar, x86, sparclinux, linuxppc-dev, linux-kernel,
Jacob Pan, Don Zickus, Michael Ellerman, Frederic Weisbecker,
Babu Moger, David S. Miller, Benjamin Herrenschmidt,
Paul Mackerras, Mathieu Desnoyers, Masami Hiramatsu,
Andrew Morton, Philippe Ombredanne, Colin Ian King,
Luis R. Rodriguez, iommu
In-Reply-To: <20180613084219.GT12258@hirez.programming.kicks-ass.net>
On Wed, 13 Jun 2018, Peter Zijlstra wrote:
> On Wed, Jun 13, 2018 at 05:41:41PM +1000, Nicholas Piggin wrote:
> > On Tue, 12 Jun 2018 17:57:32 -0700
> > Ricardo Neri <ricardo.neri-calderon@linux.intel.com> wrote:
> >
> > > Instead of exposing individual functions for the operations of the NMI
> > > watchdog, define a common interface that can be used across multiple
> > > implementations.
> > >
> > > The struct nmi_watchdog_ops is defined for such operations. These initial
> > > definitions include the enable, disable, start, stop, and cleanup
> > > operations.
> > >
> > > Only a single NMI watchdog can be used in the system. The operations of
> > > this NMI watchdog are accessed via the new variable nmi_wd_ops. This
> > > variable is set to point the operations of the first NMI watchdog that
> > > initializes successfully. Even though at this moment, the only available
> > > NMI watchdog is the perf-based hardlockup detector. More implementations
> > > can be added in the future.
> >
> > Cool, this looks pretty nice at a quick glance. sparc and powerpc at
> > least have their own NMI watchdogs, it would be good to have those
> > converted as well.
>
> Yeah, agreed, this looks like half a patch.
Though I'm not seeing the advantage of it. That kind of NMI watchdogs are
low level architecture details so having yet another 'ops' data structure
with a gazillion of callbacks, checks and indirections does not provide
value over the currently available weak stubs.
> > Is hpet a cross platform thing, or just x86? We should avoid
> > proliferation of files under kernel/ I think, so with these watchdog
> > driver structs then maybe implementations could go in drivers/ or
> > arch/
>
> HPET is mostly an x86 thing (altough it can be found elsewhere), but the
On ia64 and I doubt that anyone wants to take on the task of underwater
welding it to Itanic.
> whole thing relies on the x86 NMI mechanism and is thus firmly arch/
> material (like the sparc and ppc thing).
Right. Trying to make this 'generic' is not really solving anything.
Thanks,
tglx
^ permalink raw reply
* Re: [RFC PATCH 17/23] watchdog/hardlockup/hpet: Convert the timer's interrupt to NMI
From: Peter Zijlstra @ 2018-06-13 9:07 UTC (permalink / raw)
To: Ricardo Neri
Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Andi Kleen,
Ashok Raj, Borislav Petkov, Tony Luck, Ravi V. Shankar, x86,
sparclinux, linuxppc-dev, linux-kernel, Jacob Pan,
Rafael J. Wysocki, Don Zickus, Nicholas Piggin, Michael Ellerman,
Frederic Weisbecker, Alexei Starovoitov, Babu Moger,
Mathieu Desnoyers, Masami Hiramatsu, Andrew Morton,
Philippe Ombredanne, Colin Ian King, Byungchul Park,
Paul E. McKenney, Luis R. Rodriguez, Waiman Long, Josh Poimboeuf,
Randy Dunlap, Davidlohr Bueso, Christoffer Dall, Marc Zyngier,
Kai-Heng Feng, Konrad Rzeszutek Wilk, David Rientjes, iommu
In-Reply-To: <1528851463-21140-18-git-send-email-ricardo.neri-calderon@linux.intel.com>
On Tue, Jun 12, 2018 at 05:57:37PM -0700, Ricardo Neri wrote:
+static bool is_hpet_wdt_interrupt(struct hpet_hld_data *hdata)
+{
+ unsigned long this_isr;
+ unsigned int lvl_trig;
+
+ this_isr = hpet_readl(HPET_STATUS) & BIT(hdata->num);
+
+ lvl_trig = hpet_readl(HPET_Tn_CFG(hdata->num)) & HPET_TN_LEVEL;
+
+ if (lvl_trig && this_isr)
+ return true;
+
+ return false;
+}
> +static int hardlockup_detector_nmi_handler(unsigned int val,
> + struct pt_regs *regs)
> +{
> + struct hpet_hld_data *hdata = hld_data;
> + unsigned int use_fsb;
> +
> + /*
> + * If FSB delivery mode is used, the timer interrupt is programmed as
> + * edge-triggered and there is no need to check the ISR register.
> + */
> + use_fsb = hdata->flags & HPET_DEV_FSB_CAP;
Please do explain.. That FSB thing basically means MSI. But there's only
a single NMI vector. How do we know this NMI came from the HPET?
> +
> + if (!use_fsb && !is_hpet_wdt_interrupt(hdata))
So you add _2_ HPET reads for every single NMI that gets triggered...
and IIRC HPET reads are _sllooooowwwwww_.
> + return NMI_DONE;
> +
> + inspect_for_hardlockups(regs);
> +
> + if (!(hdata->flags & HPET_DEV_PERI_CAP))
> + kick_timer(hdata);
> +
> + /* Acknowledge interrupt if in level-triggered mode */
> + if (!use_fsb)
> + hpet_writel(BIT(hdata->num), HPET_STATUS);
> +
> + return NMI_HANDLED;
So if I read this right, when in FSB/MSI mode, we'll basically _always_
claim every single NMI as handled?
That's broken.
> +}
^ permalink raw reply
* Re: [RFC PATCH 03/23] genirq: Introduce IRQF_DELIVER_AS_NMI
From: Julien Thierry @ 2018-06-13 8:59 UTC (permalink / raw)
To: Peter Zijlstra, Ricardo Neri
Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Andi Kleen,
Ashok Raj, Borislav Petkov, Tony Luck, Ravi V. Shankar, x86,
sparclinux, linuxppc-dev, linux-kernel, Jacob Pan, Daniel Lezcano,
Andrew Morton, Levin, Alexander (Sasha Levin), Randy Dunlap,
Masami Hiramatsu, Marc Zyngier, Bartosz Golaszewski, Doug Berger,
Palmer Dabbelt, iommu
In-Reply-To: <20180613083419.GS12258@hirez.programming.kicks-ass.net>
Hi Peter, Ricardo,
On 13/06/18 09:34, Peter Zijlstra wrote:
> On Tue, Jun 12, 2018 at 05:57:23PM -0700, Ricardo Neri wrote:
>> diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
>> index 5426627..dbc5e02 100644
>> --- a/include/linux/interrupt.h
>> +++ b/include/linux/interrupt.h
>> @@ -61,6 +61,8 @@
>> * interrupt handler after suspending interrupts. For system
>> * wakeup devices users need to implement wakeup detection in
>> * their interrupt handlers.
>> + * IRQF_DELIVER_AS_NMI - Configure interrupt to be delivered as non-maskable, if
>> + * supported by the chip.
>> */
>
> NAK on the first 6 patches. You really _REALLY_ don't want to expose
> NMIs to this level.
>
I've been working on something similar on arm64 side, and effectively
the one thing that might be common to arm64 and intel is the interface
to set an interrupt as NMI. So I guess it would be nice to agree on the
right approach for this.
The way I did it was by introducing a new irq_state and let the irqchip
driver handle most of the work (if it supports that state):
https://lkml.org/lkml/2018/5/25/181
This has not been ACKed nor NAKed. So I am just asking whether this is a
more suitable approach, and if not, is there any suggestions on how to
do this?
Thanks,
--
Julien Thierry
^ permalink raw reply
* Re: [RFC PATCH 14/23] watchdog/hardlockup: Decouple the hardlockup detector from perf
From: Peter Zijlstra @ 2018-06-13 8:43 UTC (permalink / raw)
To: Ricardo Neri
Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Andi Kleen,
Ashok Raj, Borislav Petkov, Tony Luck, Ravi V. Shankar, x86,
sparclinux, linuxppc-dev, linux-kernel, Jacob Pan, Don Zickus,
Nicholas Piggin, Michael Ellerman, Frederic Weisbecker,
Babu Moger, David S. Miller, Benjamin Herrenschmidt,
Paul Mackerras, Mathieu Desnoyers, Masami Hiramatsu,
Andrew Morton, Philippe Ombredanne, Colin Ian King,
Luis R. Rodriguez, iommu
In-Reply-To: <1528851463-21140-15-git-send-email-ricardo.neri-calderon@linux.intel.com>
On Tue, Jun 12, 2018 at 05:57:34PM -0700, Ricardo Neri wrote:
> The current default implementation of the hardlockup detector assumes that
> it is implemented using perf events.
The sparc and powerpc things are very much not using perf.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox