2c162f9b41722 (Thomas Gleixner 2019-06-03 07:45:02 +0200 1) // SPDX-License-Identifier: GPL-2.0-only
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 3) * PowerMac G5 SMU driver
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 4) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 5) * Copyright 2004 J. Mayer <l_indien@magic.fr>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 6) * Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 7) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 8)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 9) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 10) * TODO:
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 11) * - maybe add timeout to commands ?
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 12) * - blocking version of time functions
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 13) * - polling version of i2c commands (including timer that works with
f18816ba20655 (Joe Perches 2008-02-03 17:18:02 +0200 14) * interrupts off)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 15) * - maybe avoid some data copies with i2c by directly using the smu cmd
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 16) * buffer and a lower level internal interface
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 17) * - understand SMU -> CPU events and implement reception of them via
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 18) * the userland interface
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 19) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 20)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 21) #include <linux/types.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 22) #include <linux/kernel.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 23) #include <linux/device.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 24) #include <linux/dmapool.h>
57c8a661d95df (Mike Rapoport 2018-10-30 15:09:49 -0700 25) #include <linux/memblock.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 26) #include <linux/vmalloc.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 27) #include <linux/highmem.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 28) #include <linux/jiffies.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 29) #include <linux/interrupt.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 30) #include <linux/rtc.h>
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 31) #include <linux/completion.h>
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 32) #include <linux/miscdevice.h>
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 33) #include <linux/delay.h>
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 34) #include <linux/poll.h>
14cc3e2b633bb (Ingo Molnar 2006-03-26 01:37:14 -0800 35) #include <linux/mutex.h>
ad9e05aef7c86 (Stephen Rothwell 2008-05-23 16:27:02 +1000 36) #include <linux/of_device.h>
5af5073004071 (Rob Herring 2013-09-17 14:28:33 -0500 37) #include <linux/of_irq.h>
ad9e05aef7c86 (Stephen Rothwell 2008-05-23 16:27:02 +1000 38) #include <linux/of_platform.h>
5a0e3ad6af866 (Tejun Heo 2010-03-24 17:04:11 +0900 39) #include <linux/slab.h>
174cd4b1e5fbd (Ingo Molnar 2017-02-02 19:15:33 +0100 40) #include <linux/sched/signal.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 41)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 42) #include <asm/byteorder.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 43) #include <asm/io.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 44) #include <asm/prom.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 45) #include <asm/machdep.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 46) #include <asm/pmac_feature.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 47) #include <asm/smu.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 48) #include <asm/sections.h>
7c0f6ba682b9c (Linus Torvalds 2016-12-24 11:46:01 -0800 49) #include <linux/uaccess.h>
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 50)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 51) #define VERSION "0.7"
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 52) #define AUTHOR "(c) 2005 Benjamin Herrenschmidt, IBM Corp."
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 53)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 54) #undef DEBUG_SMU
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 55)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 56) #ifdef DEBUG_SMU
1beb6a7d6cbed (Benjamin Herrenschmidt 2005-12-14 13:10:10 +1100 57) #define DPRINTK(fmt, args...) do { printk(KERN_DEBUG fmt , ##args); } while (0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 58) #else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 59) #define DPRINTK(fmt, args...) do { } while (0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 60) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 61)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 62) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 63) * This is the command buffer passed to the SMU hardware
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 64) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 65) #define SMU_MAX_DATA 254
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 66)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 67) struct smu_cmd_buf {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 68) u8 cmd;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 69) u8 length;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 70) u8 data[SMU_MAX_DATA];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 71) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 72)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 73) struct smu_device {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 74) spinlock_t lock;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 75) struct device_node *of_node;
2dc1158137682 (Grant Likely 2010-08-06 09:25:50 -0600 76) struct platform_device *of_dev;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 77) int doorbell; /* doorbell gpio */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 78) u32 __iomem *db_buf; /* doorbell buffer */
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 79) struct device_node *db_node;
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 80) unsigned int db_irq;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 81) int msg;
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 82) struct device_node *msg_node;
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 83) unsigned int msg_irq;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 84) struct smu_cmd_buf *cmd_buf; /* command buffer virtual */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 85) u32 cmd_buf_abs; /* command buffer absolute */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 86) struct list_head cmd_list;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 87) struct smu_cmd *cmd_cur; /* pending command */
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 88) int broken_nap;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 89) struct list_head cmd_i2c_list;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 90) struct smu_i2c_cmd *cmd_i2c_cur; /* pending i2c command */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 91) struct timer_list i2c_timer;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 92) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 93)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 94) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 95) * I don't think there will ever be more than one SMU, so
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 96) * for now, just hard code that
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 97) */
d851b6e04ee97 (Arnd Bergmann 2010-06-02 14:28:52 +0200 98) static DEFINE_MUTEX(smu_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 99) static struct smu_device *smu;
14cc3e2b633bb (Ingo Molnar 2006-03-26 01:37:14 -0800 100) static DEFINE_MUTEX(smu_part_access);
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 101) static int smu_irq_inited;
91b6fad5cf16c (Benjamin Herrenschmidt 2016-07-05 15:03:50 +1000 102) static unsigned long smu_cmdbuf_abs;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 103)
0788f28575801 (Kees Cook 2017-10-21 13:43:53 -0700 104) static void smu_i2c_retry(struct timer_list *t);
730745a5c4509 (Benjamin Herrenschmidt 2006-01-07 11:30:44 +1100 105)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 106) /*
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 107) * SMU driver low level stuff
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 108) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 109)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 110) static void smu_start_cmd(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 111) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 112) unsigned long faddr, fend;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 113) struct smu_cmd *cmd;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 114)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 115) if (list_empty(&smu->cmd_list))
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 116) return;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 117)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 118) /* Fetch first command in queue */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 119) cmd = list_entry(smu->cmd_list.next, struct smu_cmd, link);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 120) smu->cmd_cur = cmd;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 121) list_del(&cmd->link);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 122)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 123) DPRINTK("SMU: starting cmd %x, %d bytes data\n", cmd->cmd,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 124) cmd->data_len);
ebd004e4edd56 (Andy Shevchenko 2013-04-22 03:02:19 +0000 125) DPRINTK("SMU: data buffer: %8ph\n", cmd->data_buf);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 126)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 127) /* Fill the SMU command buffer */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 128) smu->cmd_buf->cmd = cmd->cmd;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 129) smu->cmd_buf->length = cmd->data_len;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 130) memcpy(smu->cmd_buf->data, cmd->data_buf, cmd->data_len);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 131)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 132) /* Flush command and data to RAM */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 133) faddr = (unsigned long)smu->cmd_buf;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 134) fend = faddr + smu->cmd_buf->length + 2;
1cfb725fb1899 (Christophe Leroy 2019-05-14 09:05:13 +0000 135) flush_dcache_range(faddr, fend);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 136)
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 137)
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 138) /* We also disable NAP mode for the duration of the command
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 139) * on U3 based machines.
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 140) * This is slightly racy as it can be written back to 1 by a sysctl
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 141) * but that never happens in practice. There seem to be an issue with
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 142) * U3 based machines such as the iMac G5 where napping for the
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 143) * whole duration of the command prevents the SMU from fetching it
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 144) * from memory. This might be related to the strange i2c based
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 145) * mechanism the SMU uses to access memory.
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 146) */
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 147) if (smu->broken_nap)
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 148) powersave_nap = 0;
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 149)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 150) /* This isn't exactly a DMA mapping here, I suspect
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 151) * the SMU is actually communicating with us via i2c to the
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 152) * northbridge or the CPU to access RAM.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 153) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 154) writel(smu->cmd_buf_abs, smu->db_buf);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 155)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 156) /* Ring the SMU doorbell */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 157) pmac_do_feature_call(PMAC_FTR_WRITE_GPIO, NULL, smu->doorbell, 4);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 158) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 159)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 160)
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 161) static irqreturn_t smu_db_intr(int irq, void *arg)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 162) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 163) unsigned long flags;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 164) struct smu_cmd *cmd;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 165) void (*done)(struct smu_cmd *cmd, void *misc) = NULL;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 166) void *misc = NULL;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 167) u8 gpio;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 168) int rc = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 169)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 170) /* SMU completed the command, well, we hope, let's make sure
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 171) * of it
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 172) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 173) spin_lock_irqsave(&smu->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 174)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 175) gpio = pmac_do_feature_call(PMAC_FTR_READ_GPIO, NULL, smu->doorbell);
a44fe13eab664 (Benjamin Herrenschmidt 2005-09-30 08:25:17 +1000 176) if ((gpio & 7) != 7) {
a44fe13eab664 (Benjamin Herrenschmidt 2005-09-30 08:25:17 +1000 177) spin_unlock_irqrestore(&smu->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 178) return IRQ_HANDLED;
a44fe13eab664 (Benjamin Herrenschmidt 2005-09-30 08:25:17 +1000 179) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 180)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 181) cmd = smu->cmd_cur;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 182) smu->cmd_cur = NULL;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 183) if (cmd == NULL)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 184) goto bail;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 185)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 186) if (rc == 0) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 187) unsigned long faddr;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 188) int reply_len;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 189) u8 ack;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 190)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 191) /* CPU might have brought back the cache line, so we need
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 192) * to flush again before peeking at the SMU response. We
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 193) * flush the entire buffer for now as we haven't read the
efad798b9f013 (Paulius Zaleckas 2008-02-03 15:42:53 +0200 194) * reply length (it's only 2 cache lines anyway)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 195) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 196) faddr = (unsigned long)smu->cmd_buf;
1cfb725fb1899 (Christophe Leroy 2019-05-14 09:05:13 +0000 197) flush_dcache_range(faddr, faddr + 256);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 198)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 199) /* Now check ack */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 200) ack = (~cmd->cmd) & 0xff;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 201) if (ack != smu->cmd_buf->cmd) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 202) DPRINTK("SMU: incorrect ack, want %x got %x\n",
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 203) ack, smu->cmd_buf->cmd);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 204) rc = -EIO;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 205) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 206) reply_len = rc == 0 ? smu->cmd_buf->length : 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 207) DPRINTK("SMU: reply len: %d\n", reply_len);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 208) if (reply_len > cmd->reply_len) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 209) printk(KERN_WARNING "SMU: reply buffer too small,"
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 210) "got %d bytes for a %d bytes buffer\n",
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 211) reply_len, cmd->reply_len);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 212) reply_len = cmd->reply_len;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 213) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 214) cmd->reply_len = reply_len;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 215) if (cmd->reply_buf && reply_len)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 216) memcpy(cmd->reply_buf, smu->cmd_buf->data, reply_len);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 217) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 218)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 219) /* Now complete the command. Write status last in order as we lost
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 220) * ownership of the command structure as soon as it's no longer -1
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 221) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 222) done = cmd->done;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 223) misc = cmd->misc;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 224) mb();
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 225) cmd->status = rc;
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 226)
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 227) /* Re-enable NAP mode */
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 228) if (smu->broken_nap)
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 229) powersave_nap = 1;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 230) bail:
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 231) /* Start next command if any */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 232) smu_start_cmd();
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 233) spin_unlock_irqrestore(&smu->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 234)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 235) /* Call command completion handler if any */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 236) if (done)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 237) done(cmd, misc);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 238)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 239) /* It's an edge interrupt, nothing to do */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 240) return IRQ_HANDLED;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 241) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 242)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 243)
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 244) static irqreturn_t smu_msg_intr(int irq, void *arg)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 245) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 246) /* I don't quite know what to do with this one, we seem to never
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 247) * receive it, so I suspect we have to arm it someway in the SMU
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 248) * to start getting events that way.
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 249) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 250)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 251) printk(KERN_INFO "SMU: message interrupt !\n");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 252)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 253) /* It's an edge interrupt, nothing to do */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 254) return IRQ_HANDLED;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 255) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 256)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 257)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 258) /*
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 259) * Queued command management.
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 260) *
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 261) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 262)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 263) int smu_queue_cmd(struct smu_cmd *cmd)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 264) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 265) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 266)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 267) if (smu == NULL)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 268) return -ENODEV;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 269) if (cmd->data_len > SMU_MAX_DATA ||
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 270) cmd->reply_len > SMU_MAX_DATA)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 271) return -EINVAL;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 272)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 273) cmd->status = 1;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 274) spin_lock_irqsave(&smu->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 275) list_add_tail(&cmd->link, &smu->cmd_list);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 276) if (smu->cmd_cur == NULL)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 277) smu_start_cmd();
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 278) spin_unlock_irqrestore(&smu->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 279)
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 280) /* Workaround for early calls when irq isn't available */
ef24ba7091517 (Michael Ellerman 2016-09-06 21:53:24 +1000 281) if (!smu_irq_inited || !smu->db_irq)
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 282) smu_spinwait_cmd(cmd);
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 283)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 284) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 285) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 286) EXPORT_SYMBOL(smu_queue_cmd);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 287)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 288)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 289) int smu_queue_simple(struct smu_simple_cmd *scmd, u8 command,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 290) unsigned int data_len,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 291) void (*done)(struct smu_cmd *cmd, void *misc),
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 292) void *misc, ...)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 293) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 294) struct smu_cmd *cmd = &scmd->cmd;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 295) va_list list;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 296) int i;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 297)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 298) if (data_len > sizeof(scmd->buffer))
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 299) return -EINVAL;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 300)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 301) memset(scmd, 0, sizeof(*scmd));
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 302) cmd->cmd = command;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 303) cmd->data_len = data_len;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 304) cmd->data_buf = scmd->buffer;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 305) cmd->reply_len = sizeof(scmd->buffer);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 306) cmd->reply_buf = scmd->buffer;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 307) cmd->done = done;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 308) cmd->misc = misc;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 309)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 310) va_start(list, misc);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 311) for (i = 0; i < data_len; ++i)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 312) scmd->buffer[i] = (u8)va_arg(list, int);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 313) va_end(list);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 314)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 315) return smu_queue_cmd(cmd);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 316) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 317) EXPORT_SYMBOL(smu_queue_simple);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 318)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 319)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 320) void smu_poll(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 321) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 322) u8 gpio;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 323)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 324) if (smu == NULL)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 325) return;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 326)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 327) gpio = pmac_do_feature_call(PMAC_FTR_READ_GPIO, NULL, smu->doorbell);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 328) if ((gpio & 7) == 7)
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 329) smu_db_intr(smu->db_irq, smu);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 330) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 331) EXPORT_SYMBOL(smu_poll);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 332)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 333)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 334) void smu_done_complete(struct smu_cmd *cmd, void *misc)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 335) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 336) struct completion *comp = misc;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 337)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 338) complete(comp);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 339) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 340) EXPORT_SYMBOL(smu_done_complete);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 341)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 342)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 343) void smu_spinwait_cmd(struct smu_cmd *cmd)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 344) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 345) while(cmd->status == 1)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 346) smu_poll();
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 347) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 348) EXPORT_SYMBOL(smu_spinwait_cmd);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 349)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 350)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 351) /* RTC low level commands */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 352) static inline int bcd2hex (int n)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 353) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 354) return (((n & 0xf0) >> 4) * 10) + (n & 0xf);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 355) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 356)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 357)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 358) static inline int hex2bcd (int n)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 359) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 360) return ((n / 10) << 4) + (n % 10);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 361) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 362)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 363)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 364) static inline void smu_fill_set_rtc_cmd(struct smu_cmd_buf *cmd_buf,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 365) struct rtc_time *time)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 366) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 367) cmd_buf->cmd = 0x8e;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 368) cmd_buf->length = 8;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 369) cmd_buf->data[0] = 0x80;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 370) cmd_buf->data[1] = hex2bcd(time->tm_sec);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 371) cmd_buf->data[2] = hex2bcd(time->tm_min);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 372) cmd_buf->data[3] = hex2bcd(time->tm_hour);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 373) cmd_buf->data[4] = time->tm_wday;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 374) cmd_buf->data[5] = hex2bcd(time->tm_mday);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 375) cmd_buf->data[6] = hex2bcd(time->tm_mon) + 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 376) cmd_buf->data[7] = hex2bcd(time->tm_year - 100);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 377) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 378)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 379)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 380) int smu_get_rtc_time(struct rtc_time *time, int spinwait)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 381) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 382) struct smu_simple_cmd cmd;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 383) int rc;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 384)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 385) if (smu == NULL)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 386) return -ENODEV;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 387)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 388) memset(time, 0, sizeof(struct rtc_time));
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 389) rc = smu_queue_simple(&cmd, SMU_CMD_RTC_COMMAND, 1, NULL, NULL,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 390) SMU_CMD_RTC_GET_DATETIME);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 391) if (rc)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 392) return rc;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 393) smu_spinwait_simple(&cmd);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 394)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 395) time->tm_sec = bcd2hex(cmd.buffer[0]);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 396) time->tm_min = bcd2hex(cmd.buffer[1]);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 397) time->tm_hour = bcd2hex(cmd.buffer[2]);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 398) time->tm_wday = bcd2hex(cmd.buffer[3]);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 399) time->tm_mday = bcd2hex(cmd.buffer[4]);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 400) time->tm_mon = bcd2hex(cmd.buffer[5]) - 1;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 401) time->tm_year = bcd2hex(cmd.buffer[6]) + 100;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 402)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 403) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 404) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 405)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 406)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 407) int smu_set_rtc_time(struct rtc_time *time, int spinwait)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 408) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 409) struct smu_simple_cmd cmd;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 410) int rc;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 411)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 412) if (smu == NULL)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 413) return -ENODEV;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 414)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 415) rc = smu_queue_simple(&cmd, SMU_CMD_RTC_COMMAND, 8, NULL, NULL,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 416) SMU_CMD_RTC_SET_DATETIME,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 417) hex2bcd(time->tm_sec),
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 418) hex2bcd(time->tm_min),
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 419) hex2bcd(time->tm_hour),
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 420) time->tm_wday,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 421) hex2bcd(time->tm_mday),
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 422) hex2bcd(time->tm_mon) + 1,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 423) hex2bcd(time->tm_year - 100));
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 424) if (rc)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 425) return rc;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 426) smu_spinwait_simple(&cmd);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 427)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 428) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 429) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 430)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 431)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 432) void smu_shutdown(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 433) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 434) struct smu_simple_cmd cmd;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 435)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 436) if (smu == NULL)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 437) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 438)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 439) if (smu_queue_simple(&cmd, SMU_CMD_POWER_COMMAND, 9, NULL, NULL,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 440) 'S', 'H', 'U', 'T', 'D', 'O', 'W', 'N', 0))
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 441) return;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 442) smu_spinwait_simple(&cmd);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 443) for (;;)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 444) ;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 445) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 446)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 447)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 448) void smu_restart(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 449) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 450) struct smu_simple_cmd cmd;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 451)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 452) if (smu == NULL)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 453) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 454)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 455) if (smu_queue_simple(&cmd, SMU_CMD_POWER_COMMAND, 8, NULL, NULL,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 456) 'R', 'E', 'S', 'T', 'A', 'R', 'T', 0))
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 457) return;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 458) smu_spinwait_simple(&cmd);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 459) for (;;)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 460) ;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 461) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 462)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 463)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 464) int smu_present(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 465) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 466) return smu != NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 467) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 468) EXPORT_SYMBOL(smu_present);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 469)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 470)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 471) int __init smu_init (void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 472) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 473) struct device_node *np;
018a3d1db7cdb (Jeremy Kerr 2006-07-12 15:40:29 +1000 474) const u32 *data;
73f38fe1b563a (Julia Lawall 2008-06-24 04:14:52 +1000 475) int ret = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 476)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 477) np = of_find_node_by_type(NULL, "smu");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 478) if (np == NULL)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 479) return -ENODEV;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 480)
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 481) printk(KERN_INFO "SMU: Driver %s %s\n", VERSION, AUTHOR);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 482)
91b6fad5cf16c (Benjamin Herrenschmidt 2016-07-05 15:03:50 +1000 483) /*
91b6fad5cf16c (Benjamin Herrenschmidt 2016-07-05 15:03:50 +1000 484) * SMU based G5s need some memory below 2Gb. Thankfully this is
91b6fad5cf16c (Benjamin Herrenschmidt 2016-07-05 15:03:50 +1000 485) * called at a time where memblock is still available.
91b6fad5cf16c (Benjamin Herrenschmidt 2016-07-05 15:03:50 +1000 486) */
0ba9e6edd4c2e (Mike Rapoport 2019-03-11 23:29:35 -0700 487) smu_cmdbuf_abs = memblock_phys_alloc_range(4096, 4096, 0, 0x80000000UL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 488) if (smu_cmdbuf_abs == 0) {
91b6fad5cf16c (Benjamin Herrenschmidt 2016-07-05 15:03:50 +1000 489) printk(KERN_ERR "SMU: Command buffer allocation failed !\n");
73f38fe1b563a (Julia Lawall 2008-06-24 04:14:52 +1000 490) ret = -EINVAL;
73f38fe1b563a (Julia Lawall 2008-06-24 04:14:52 +1000 491) goto fail_np;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 492) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 493)
7e1c4e27928e5 (Mike Rapoport 2018-10-30 15:09:57 -0700 494) smu = memblock_alloc(sizeof(struct smu_device), SMP_CACHE_BYTES);
8a7f97b902f4f (Mike Rapoport 2019-03-11 23:30:31 -0700 495) if (!smu)
8a7f97b902f4f (Mike Rapoport 2019-03-11 23:30:31 -0700 496) panic("%s: Failed to allocate %zu bytes\n", __func__,
8a7f97b902f4f (Mike Rapoport 2019-03-11 23:30:31 -0700 497) sizeof(struct smu_device));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 498)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 499) spin_lock_init(&smu->lock);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 500) INIT_LIST_HEAD(&smu->cmd_list);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 501) INIT_LIST_HEAD(&smu->cmd_i2c_list);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 502) smu->of_node = np;
ef24ba7091517 (Michael Ellerman 2016-09-06 21:53:24 +1000 503) smu->db_irq = 0;
ef24ba7091517 (Michael Ellerman 2016-09-06 21:53:24 +1000 504) smu->msg_irq = 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 505)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 506) /* smu_cmdbuf_abs is in the low 2G of RAM, can be converted to a
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 507) * 32 bits value safely
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 508) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 509) smu->cmd_buf_abs = (u32)smu_cmdbuf_abs;
48817c58066fe (Michael Ellerman 2012-07-25 21:19:54 +0000 510) smu->cmd_buf = __va(smu_cmdbuf_abs);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 511)
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 512) smu->db_node = of_find_node_by_name(NULL, "smu-doorbell");
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 513) if (smu->db_node == NULL) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 514) printk(KERN_ERR "SMU: Can't find doorbell GPIO !\n");
73f38fe1b563a (Julia Lawall 2008-06-24 04:14:52 +1000 515) ret = -ENXIO;
73f38fe1b563a (Julia Lawall 2008-06-24 04:14:52 +1000 516) goto fail_bootmem;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 517) }
01b2726dd11ef (Stephen Rothwell 2007-04-27 13:41:15 +1000 518) data = of_get_property(smu->db_node, "reg", NULL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 519) if (data == NULL) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 520) printk(KERN_ERR "SMU: Can't find doorbell GPIO address !\n");
73f38fe1b563a (Julia Lawall 2008-06-24 04:14:52 +1000 521) ret = -ENXIO;
73f38fe1b563a (Julia Lawall 2008-06-24 04:14:52 +1000 522) goto fail_db_node;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 523) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 524)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 525) /* Current setup has one doorbell GPIO that does both doorbell
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 526) * and ack. GPIOs are at 0x50, best would be to find that out
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 527) * in the device-tree though.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 528) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 529) smu->doorbell = *data;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 530) if (smu->doorbell < 0x50)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 531) smu->doorbell += 0x50;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 532)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 533) /* Now look for the smu-interrupt GPIO */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 534) do {
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 535) smu->msg_node = of_find_node_by_name(NULL, "smu-interrupt");
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 536) if (smu->msg_node == NULL)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 537) break;
01b2726dd11ef (Stephen Rothwell 2007-04-27 13:41:15 +1000 538) data = of_get_property(smu->msg_node, "reg", NULL);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 539) if (data == NULL) {
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 540) of_node_put(smu->msg_node);
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 541) smu->msg_node = NULL;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 542) break;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 543) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 544) smu->msg = *data;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 545) if (smu->msg < 0x50)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 546) smu->msg += 0x50;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 547) } while(0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 548)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 549) /* Doorbell buffer is currently hard-coded, I didn't find a proper
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 550) * device-tree entry giving the address. Best would probably to use
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 551) * an offset for K2 base though, but let's do it that way for now.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 552) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 553) smu->db_buf = ioremap(0x8000860c, 0x1000);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 554) if (smu->db_buf == NULL) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 555) printk(KERN_ERR "SMU: Can't map doorbell buffer pointer !\n");
73f38fe1b563a (Julia Lawall 2008-06-24 04:14:52 +1000 556) ret = -ENXIO;
73f38fe1b563a (Julia Lawall 2008-06-24 04:14:52 +1000 557) goto fail_msg_node;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 558) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 559)
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 560) /* U3 has an issue with NAP mode when issuing SMU commands */
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 561) smu->broken_nap = pmac_get_uninorth_variant() < 4;
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 562) if (smu->broken_nap)
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 563) printk(KERN_INFO "SMU: using NAP mode workaround\n");
592a607bbc053 (Benjamin Herrenschmidt 2008-02-07 14:29:43 +1100 564)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 565) sys_ctrler = SYS_CTRLER_SMU;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 566) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 567)
73f38fe1b563a (Julia Lawall 2008-06-24 04:14:52 +1000 568) fail_msg_node:
4b7d8358819da (Markus Elfring 2015-02-04 21:32:27 +0100 569) of_node_put(smu->msg_node);
73f38fe1b563a (Julia Lawall 2008-06-24 04:14:52 +1000 570) fail_db_node:
73f38fe1b563a (Julia Lawall 2008-06-24 04:14:52 +1000 571) of_node_put(smu->db_node);
73f38fe1b563a (Julia Lawall 2008-06-24 04:14:52 +1000 572) fail_bootmem:
2013288f72388 (Mike Rapoport 2018-10-30 15:09:21 -0700 573) memblock_free(__pa(smu), sizeof(struct smu_device));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 574) smu = NULL;
73f38fe1b563a (Julia Lawall 2008-06-24 04:14:52 +1000 575) fail_np:
73f38fe1b563a (Julia Lawall 2008-06-24 04:14:52 +1000 576) of_node_put(np);
73f38fe1b563a (Julia Lawall 2008-06-24 04:14:52 +1000 577) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 578) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 579)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 580)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 581) static int smu_late_init(void)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 582) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 583) if (!smu)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 584) return 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 585)
0788f28575801 (Kees Cook 2017-10-21 13:43:53 -0700 586) timer_setup(&smu->i2c_timer, smu_i2c_retry, 0);
730745a5c4509 (Benjamin Herrenschmidt 2006-01-07 11:30:44 +1100 587)
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 588) if (smu->db_node) {
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 589) smu->db_irq = irq_of_parse_and_map(smu->db_node, 0);
ef24ba7091517 (Michael Ellerman 2016-09-06 21:53:24 +1000 590) if (!smu->db_irq)
b6a945ae03fd3 (Rob Herring 2017-07-18 16:43:12 -0500 591) printk(KERN_ERR "smu: failed to map irq for node %pOF\n",
b6a945ae03fd3 (Rob Herring 2017-07-18 16:43:12 -0500 592) smu->db_node);
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 593) }
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 594) if (smu->msg_node) {
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 595) smu->msg_irq = irq_of_parse_and_map(smu->msg_node, 0);
ef24ba7091517 (Michael Ellerman 2016-09-06 21:53:24 +1000 596) if (!smu->msg_irq)
b6a945ae03fd3 (Rob Herring 2017-07-18 16:43:12 -0500 597) printk(KERN_ERR "smu: failed to map irq for node %pOF\n",
b6a945ae03fd3 (Rob Herring 2017-07-18 16:43:12 -0500 598) smu->msg_node);
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 599) }
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 600)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 601) /*
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 602) * Try to request the interrupts
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 603) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 604)
ef24ba7091517 (Michael Ellerman 2016-09-06 21:53:24 +1000 605) if (smu->db_irq) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 606) if (request_irq(smu->db_irq, smu_db_intr,
dace145374b8e (Thomas Gleixner 2006-07-01 19:29:38 -0700 607) IRQF_SHARED, "SMU doorbell", smu) < 0) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 608) printk(KERN_WARNING "SMU: can't "
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 609) "request interrupt %d\n",
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 610) smu->db_irq);
ef24ba7091517 (Michael Ellerman 2016-09-06 21:53:24 +1000 611) smu->db_irq = 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 612) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 613) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 614)
ef24ba7091517 (Michael Ellerman 2016-09-06 21:53:24 +1000 615) if (smu->msg_irq) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 616) if (request_irq(smu->msg_irq, smu_msg_intr,
dace145374b8e (Thomas Gleixner 2006-07-01 19:29:38 -0700 617) IRQF_SHARED, "SMU message", smu) < 0) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 618) printk(KERN_WARNING "SMU: can't "
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 619) "request interrupt %d\n",
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 620) smu->msg_irq);
ef24ba7091517 (Michael Ellerman 2016-09-06 21:53:24 +1000 621) smu->msg_irq = 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 622) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 623) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 624)
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 625) smu_irq_inited = 1;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 626) return 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 627) }
730745a5c4509 (Benjamin Herrenschmidt 2006-01-07 11:30:44 +1100 628) /* This has to be before arch_initcall as the low i2c stuff relies on the
730745a5c4509 (Benjamin Herrenschmidt 2006-01-07 11:30:44 +1100 629) * above having been done before we reach arch_initcalls
730745a5c4509 (Benjamin Herrenschmidt 2006-01-07 11:30:44 +1100 630) */
730745a5c4509 (Benjamin Herrenschmidt 2006-01-07 11:30:44 +1100 631) core_initcall(smu_late_init);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 632)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 633) /*
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 634) * sysfs visibility
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 635) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 636)
c4028958b6eca (David Howells 2006-11-22 14:57:56 +0000 637) static void smu_expose_childs(struct work_struct *unused)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 638) {
a28d3af2a26c8 (Benjamin Herrenschmidt 2006-01-07 11:35:26 +1100 639) struct device_node *np;
a28d3af2a26c8 (Benjamin Herrenschmidt 2006-01-07 11:35:26 +1100 640)
9c826d31a7381 (Qinglang Miao 2020-09-16 14:21:22 +0800 641) for_each_child_of_node(smu->of_node, np)
55b61fec22caa (Stephen Rothwell 2007-05-03 17:26:52 +1000 642) if (of_device_is_compatible(np, "smu-sensors"))
730745a5c4509 (Benjamin Herrenschmidt 2006-01-07 11:30:44 +1100 643) of_platform_device_create(np, "smu-sensors",
730745a5c4509 (Benjamin Herrenschmidt 2006-01-07 11:30:44 +1100 644) &smu->of_dev->dev);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 645) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 646)
c4028958b6eca (David Howells 2006-11-22 14:57:56 +0000 647) static DECLARE_WORK(smu_expose_childs_work, smu_expose_childs);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 648)
000061245a679 (Grant Likely 2011-02-22 19:59:54 -0700 649) static int smu_platform_probe(struct platform_device* dev)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 650) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 651) if (!smu)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 652) return -ENODEV;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 653) smu->of_dev = dev;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 654)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 655) /*
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 656) * Ok, we are matched, now expose all i2c busses. We have to defer
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 657) * that unfortunately or it would deadlock inside the device model
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 658) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 659) schedule_work(&smu_expose_childs_work);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 660)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 661) return 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 662) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 663)
46759a7c13264 (Márton Németh 2010-01-10 01:43:14 +0000 664) static const struct of_device_id smu_platform_match[] =
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 665) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 666) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 667) .type = "smu",
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 668) },
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 669) {},
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 670) };
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 671)
000061245a679 (Grant Likely 2011-02-22 19:59:54 -0700 672) static struct platform_driver smu_of_platform_driver =
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 673) {
4018294b53d1d (Grant Likely 2010-04-13 16:13:02 -0700 674) .driver = {
4018294b53d1d (Grant Likely 2010-04-13 16:13:02 -0700 675) .name = "smu",
4018294b53d1d (Grant Likely 2010-04-13 16:13:02 -0700 676) .of_match_table = smu_platform_match,
4018294b53d1d (Grant Likely 2010-04-13 16:13:02 -0700 677) },
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 678) .probe = smu_platform_probe,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 679) };
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 680)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 681) static int __init smu_init_sysfs(void)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 682) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 683) /*
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 684) * For now, we don't power manage machines with an SMU chip,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 685) * I'm a bit too far from figuring out how that works with those
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 686) * new chipsets, but that will come back and bite us
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 687) */
000061245a679 (Grant Likely 2011-02-22 19:59:54 -0700 688) platform_driver_register(&smu_of_platform_driver);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 689) return 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 690) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 691)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 692) device_initcall(smu_init_sysfs);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 693)
2dc1158137682 (Grant Likely 2010-08-06 09:25:50 -0600 694) struct platform_device *smu_get_ofdev(void)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 695) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 696) if (!smu)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 697) return NULL;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 698) return smu->of_dev;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 699) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 700)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 701) EXPORT_SYMBOL_GPL(smu_get_ofdev);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 702)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 703) /*
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 704) * i2c interface
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 705) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 706)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 707) static void smu_i2c_complete_command(struct smu_i2c_cmd *cmd, int fail)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 708) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 709) void (*done)(struct smu_i2c_cmd *cmd, void *misc) = cmd->done;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 710) void *misc = cmd->misc;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 711) unsigned long flags;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 712)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 713) /* Check for read case */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 714) if (!fail && cmd->read) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 715) if (cmd->pdata[0] < 1)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 716) fail = 1;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 717) else
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 718) memcpy(cmd->info.data, &cmd->pdata[1],
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 719) cmd->info.datalen);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 720) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 721)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 722) DPRINTK("SMU: completing, success: %d\n", !fail);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 723)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 724) /* Update status and mark no pending i2c command with lock
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 725) * held so nobody comes in while we dequeue an eventual
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 726) * pending next i2c command
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 727) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 728) spin_lock_irqsave(&smu->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 729) smu->cmd_i2c_cur = NULL;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 730) wmb();
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 731) cmd->status = fail ? -EIO : 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 732)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 733) /* Is there another i2c command waiting ? */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 734) if (!list_empty(&smu->cmd_i2c_list)) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 735) struct smu_i2c_cmd *newcmd;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 736)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 737) /* Fetch it, new current, remove from list */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 738) newcmd = list_entry(smu->cmd_i2c_list.next,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 739) struct smu_i2c_cmd, link);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 740) smu->cmd_i2c_cur = newcmd;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 741) list_del(&cmd->link);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 742)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 743) /* Queue with low level smu */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 744) list_add_tail(&cmd->scmd.link, &smu->cmd_list);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 745) if (smu->cmd_cur == NULL)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 746) smu_start_cmd();
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 747) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 748) spin_unlock_irqrestore(&smu->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 749)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 750) /* Call command completion handler if any */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 751) if (done)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 752) done(cmd, misc);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 753)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 754) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 755)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 756)
0788f28575801 (Kees Cook 2017-10-21 13:43:53 -0700 757) static void smu_i2c_retry(struct timer_list *unused)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 758) {
730745a5c4509 (Benjamin Herrenschmidt 2006-01-07 11:30:44 +1100 759) struct smu_i2c_cmd *cmd = smu->cmd_i2c_cur;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 760)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 761) DPRINTK("SMU: i2c failure, requeuing...\n");
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 762)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 763) /* requeue command simply by resetting reply_len */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 764) cmd->pdata[0] = 0xff;
730745a5c4509 (Benjamin Herrenschmidt 2006-01-07 11:30:44 +1100 765) cmd->scmd.reply_len = sizeof(cmd->pdata);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 766) smu_queue_cmd(&cmd->scmd);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 767) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 768)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 769)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 770) static void smu_i2c_low_completion(struct smu_cmd *scmd, void *misc)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 771) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 772) struct smu_i2c_cmd *cmd = misc;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 773) int fail = 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 774)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 775) DPRINTK("SMU: i2c compl. stage=%d status=%x pdata[0]=%x rlen: %x\n",
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 776) cmd->stage, scmd->status, cmd->pdata[0], scmd->reply_len);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 777)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 778) /* Check for possible status */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 779) if (scmd->status < 0)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 780) fail = 1;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 781) else if (cmd->read) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 782) if (cmd->stage == 0)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 783) fail = cmd->pdata[0] != 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 784) else
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 785) fail = cmd->pdata[0] >= 0x80;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 786) } else {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 787) fail = cmd->pdata[0] != 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 788) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 789)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 790) /* Handle failures by requeuing command, after 5ms interval
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 791) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 792) if (fail && --cmd->retries > 0) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 793) DPRINTK("SMU: i2c failure, starting timer...\n");
730745a5c4509 (Benjamin Herrenschmidt 2006-01-07 11:30:44 +1100 794) BUG_ON(cmd != smu->cmd_i2c_cur);
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 795) if (!smu_irq_inited) {
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 796) mdelay(5);
0788f28575801 (Kees Cook 2017-10-21 13:43:53 -0700 797) smu_i2c_retry(NULL);
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 798) return;
f620753b95845 (Benjamin Herrenschmidt 2006-07-10 04:44:44 -0700 799) }
730745a5c4509 (Benjamin Herrenschmidt 2006-01-07 11:30:44 +1100 800) mod_timer(&smu->i2c_timer, jiffies + msecs_to_jiffies(5));
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 801) return;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 802) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 803)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 804) /* If failure or stage 1, command is complete */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 805) if (fail || cmd->stage != 0) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 806) smu_i2c_complete_command(cmd, fail);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 807) return;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 808) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 809)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 810) DPRINTK("SMU: going to stage 1\n");
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 811)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 812) /* Ok, initial command complete, now poll status */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 813) scmd->reply_buf = cmd->pdata;
730745a5c4509 (Benjamin Herrenschmidt 2006-01-07 11:30:44 +1100 814) scmd->reply_len = sizeof(cmd->pdata);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 815) scmd->data_buf = cmd->pdata;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 816) scmd->data_len = 1;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 817) cmd->pdata[0] = 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 818) cmd->stage = 1;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 819) cmd->retries = 20;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 820) smu_queue_cmd(scmd);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 821) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 822)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 823)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 824) int smu_queue_i2c(struct smu_i2c_cmd *cmd)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 825) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 826) unsigned long flags;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 827)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 828) if (smu == NULL)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 829) return -ENODEV;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 830)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 831) /* Fill most fields of scmd */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 832) cmd->scmd.cmd = SMU_CMD_I2C_COMMAND;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 833) cmd->scmd.done = smu_i2c_low_completion;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 834) cmd->scmd.misc = cmd;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 835) cmd->scmd.reply_buf = cmd->pdata;
730745a5c4509 (Benjamin Herrenschmidt 2006-01-07 11:30:44 +1100 836) cmd->scmd.reply_len = sizeof(cmd->pdata);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 837) cmd->scmd.data_buf = (u8 *)(char *)&cmd->info;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 838) cmd->scmd.status = 1;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 839) cmd->stage = 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 840) cmd->pdata[0] = 0xff;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 841) cmd->retries = 20;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 842) cmd->status = 1;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 843)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 844) /* Check transfer type, sanitize some "info" fields
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 845) * based on transfer type and do more checking
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 846) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 847) cmd->info.caddr = cmd->info.devaddr;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 848) cmd->read = cmd->info.devaddr & 0x01;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 849) switch(cmd->info.type) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 850) case SMU_I2C_TRANSFER_SIMPLE:
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 851) memset(&cmd->info.sublen, 0, 4);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 852) break;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 853) case SMU_I2C_TRANSFER_COMBINED:
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 854) cmd->info.devaddr &= 0xfe;
df561f6688fef (Gustavo A. R. Silva 2020-08-23 17:36:59 -0500 855) fallthrough;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 856) case SMU_I2C_TRANSFER_STDSUB:
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 857) if (cmd->info.sublen > 3)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 858) return -EINVAL;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 859) break;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 860) default:
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 861) return -EINVAL;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 862) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 863)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 864) /* Finish setting up command based on transfer direction
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 865) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 866) if (cmd->read) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 867) if (cmd->info.datalen > SMU_I2C_READ_MAX)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 868) return -EINVAL;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 869) memset(cmd->info.data, 0xff, cmd->info.datalen);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 870) cmd->scmd.data_len = 9;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 871) } else {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 872) if (cmd->info.datalen > SMU_I2C_WRITE_MAX)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 873) return -EINVAL;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 874) cmd->scmd.data_len = 9 + cmd->info.datalen;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 875) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 876)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 877) DPRINTK("SMU: i2c enqueuing command\n");
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 878) DPRINTK("SMU: %s, len=%d bus=%x addr=%x sub0=%x type=%x\n",
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 879) cmd->read ? "read" : "write", cmd->info.datalen,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 880) cmd->info.bus, cmd->info.caddr,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 881) cmd->info.subaddr[0], cmd->info.type);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 882)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 883)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 884) /* Enqueue command in i2c list, and if empty, enqueue also in
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 885) * main command list
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 886) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 887) spin_lock_irqsave(&smu->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 888) if (smu->cmd_i2c_cur == NULL) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 889) smu->cmd_i2c_cur = cmd;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 890) list_add_tail(&cmd->scmd.link, &smu->cmd_list);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 891) if (smu->cmd_cur == NULL)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 892) smu_start_cmd();
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 893) } else
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 894) list_add_tail(&cmd->link, &smu->cmd_i2c_list);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 895) spin_unlock_irqrestore(&smu->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 896)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 897) return 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 898) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 899)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 900) /*
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 901) * Handling of "partitions"
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 902) */
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 903)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 904) static int smu_read_datablock(u8 *dest, unsigned int addr, unsigned int len)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 905) {
6e9a4738c9fad (Peter Zijlstra 2006-09-30 23:28:10 -0700 906) DECLARE_COMPLETION_ONSTACK(comp);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 907) unsigned int chunk;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 908) struct smu_cmd cmd;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 909) int rc;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 910) u8 params[8];
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 911)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 912) /* We currently use a chunk size of 0xe. We could check the
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 913) * SMU firmware version and use bigger sizes though
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 914) */
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 915) chunk = 0xe;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 916)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 917) while (len) {
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 918) unsigned int clen = min(len, chunk);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 919)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 920) cmd.cmd = SMU_CMD_MISC_ee_COMMAND;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 921) cmd.data_len = 7;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 922) cmd.data_buf = params;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 923) cmd.reply_len = chunk;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 924) cmd.reply_buf = dest;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 925) cmd.done = smu_done_complete;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 926) cmd.misc = ∁
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 927) params[0] = SMU_CMD_MISC_ee_GET_DATABLOCK_REC;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 928) params[1] = 0x4;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 929) *((u32 *)¶ms[2]) = addr;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 930) params[6] = clen;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 931)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 932) rc = smu_queue_cmd(&cmd);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 933) if (rc)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 934) return rc;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 935) wait_for_completion(&comp);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 936) if (cmd.status != 0)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 937) return rc;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 938) if (cmd.reply_len != clen) {
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 939) printk(KERN_DEBUG "SMU: short read in "
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 940) "smu_read_datablock, got: %d, want: %d\n",
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 941) cmd.reply_len, clen);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 942) return -EIO;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 943) }
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 944) len -= clen;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 945) addr += clen;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 946) dest += clen;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 947) }
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 948) return 0;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 949) }
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 950)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 951) static struct smu_sdbp_header *smu_create_sdb_partition(int id)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 952) {
6e9a4738c9fad (Peter Zijlstra 2006-09-30 23:28:10 -0700 953) DECLARE_COMPLETION_ONSTACK(comp);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 954) struct smu_simple_cmd cmd;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 955) unsigned int addr, len, tlen;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 956) struct smu_sdbp_header *hdr;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 957) struct property *prop;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 958)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 959) /* First query the partition info */
1beb6a7d6cbed (Benjamin Herrenschmidt 2005-12-14 13:10:10 +1100 960) DPRINTK("SMU: Query partition infos ... (irq=%d)\n", smu->db_irq);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 961) smu_queue_simple(&cmd, SMU_CMD_PARTITION_COMMAND, 2,
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 962) smu_done_complete, &comp,
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 963) SMU_CMD_PARTITION_LATEST, id);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 964) wait_for_completion(&comp);
1beb6a7d6cbed (Benjamin Herrenschmidt 2005-12-14 13:10:10 +1100 965) DPRINTK("SMU: done, status: %d, reply_len: %d\n",
1beb6a7d6cbed (Benjamin Herrenschmidt 2005-12-14 13:10:10 +1100 966) cmd.cmd.status, cmd.cmd.reply_len);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 967)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 968) /* Partition doesn't exist (or other error) */
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 969) if (cmd.cmd.status != 0 || cmd.cmd.reply_len != 6)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 970) return NULL;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 971)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 972) /* Fetch address and length from reply */
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 973) addr = *((u16 *)cmd.buffer);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 974) len = cmd.buffer[3] << 2;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 975) /* Calucluate total length to allocate, including the 17 bytes
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 976) * for "sdb-partition-XX" that we append at the end of the buffer
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 977) */
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 978) tlen = sizeof(struct property) + len + 18;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 979)
cd86128088554 (Robert P. J. Day 2006-12-13 00:34:52 -0800 980) prop = kzalloc(tlen, GFP_KERNEL);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 981) if (prop == NULL)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 982) return NULL;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 983) hdr = (struct smu_sdbp_header *)(prop + 1);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 984) prop->name = ((char *)prop) + tlen - 18;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 985) sprintf(prop->name, "sdb-partition-%02x", id);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 986) prop->length = len;
1a38147ed0737 (Stephen Rothwell 2007-04-03 10:58:52 +1000 987) prop->value = hdr;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 988) prop->next = NULL;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 989)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 990) /* Read the datablock */
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 991) if (smu_read_datablock((u8 *)hdr, addr, len)) {
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 992) printk(KERN_DEBUG "SMU: datablock read failed while reading "
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 993) "partition %02x !\n", id);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 994) goto failure;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 995) }
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 996)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 997) /* Got it, check a few things and create the property */
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 998) if (hdr->id != id) {
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 999) printk(KERN_DEBUG "SMU: Reading partition %02x and got "
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1000) "%02x !\n", id, hdr->id);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1001) goto failure;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1002) }
79d1c712958f9 (Nathan Fontenot 2012-10-02 16:58:46 +0000 1003) if (of_add_property(smu->of_node, prop)) {
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1004) printk(KERN_DEBUG "SMU: Failed creating sdb-partition-%02x "
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1005) "property !\n", id);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1006) goto failure;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1007) }
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1008)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1009) return hdr;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1010) failure:
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1011) kfree(prop);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1012) return NULL;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1013) }
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1014)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1015) /* Note: Only allowed to return error code in pointers (using ERR_PTR)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1016) * when interruptible is 1
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1017) */
3db8715ec9dc1 (Wang Wensheng 2020-09-14 12:26:15 +0000 1018) static const struct smu_sdbp_header *__smu_get_sdb_partition(int id,
018a3d1db7cdb (Jeremy Kerr 2006-07-12 15:40:29 +1000 1019) unsigned int *size, int interruptible)
4350147a816b9 (Benjamin Herrenschmidt 2005-11-07 14:27:33 +1100 1020) {
4350147a816b9 (Benjamin Herrenschmidt 2005-11-07 14:27:33 +1100 1021) char pname[32];
018a3d1db7cdb (Jeremy Kerr 2006-07-12 15:40:29 +1000 1022) const struct smu_sdbp_header *part;
4350147a816b9 (Benjamin Herrenschmidt 2005-11-07 14:27:33 +1100 1023)
4350147a816b9 (Benjamin Herrenschmidt 2005-11-07 14:27:33 +1100 1024) if (!smu)
4350147a816b9 (Benjamin Herrenschmidt 2005-11-07 14:27:33 +1100 1025) return NULL;
4350147a816b9 (Benjamin Herrenschmidt 2005-11-07 14:27:33 +1100 1026)
4350147a816b9 (Benjamin Herrenschmidt 2005-11-07 14:27:33 +1100 1027) sprintf(pname, "sdb-partition-%02x", id);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1028)
1beb6a7d6cbed (Benjamin Herrenschmidt 2005-12-14 13:10:10 +1100 1029) DPRINTK("smu_get_sdb_partition(%02x)\n", id);
1beb6a7d6cbed (Benjamin Herrenschmidt 2005-12-14 13:10:10 +1100 1030)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1031) if (interruptible) {
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1032) int rc;
14cc3e2b633bb (Ingo Molnar 2006-03-26 01:37:14 -0800 1033) rc = mutex_lock_interruptible(&smu_part_access);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1034) if (rc)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1035) return ERR_PTR(rc);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1036) } else
14cc3e2b633bb (Ingo Molnar 2006-03-26 01:37:14 -0800 1037) mutex_lock(&smu_part_access);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1038)
01b2726dd11ef (Stephen Rothwell 2007-04-27 13:41:15 +1000 1039) part = of_get_property(smu->of_node, pname, size);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1040) if (part == NULL) {
1beb6a7d6cbed (Benjamin Herrenschmidt 2005-12-14 13:10:10 +1100 1041) DPRINTK("trying to extract from SMU ...\n");
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1042) part = smu_create_sdb_partition(id);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1043) if (part != NULL && size)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1044) *size = part->len << 2;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1045) }
14cc3e2b633bb (Ingo Molnar 2006-03-26 01:37:14 -0800 1046) mutex_unlock(&smu_part_access);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1047) return part;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1048) }
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1049)
018a3d1db7cdb (Jeremy Kerr 2006-07-12 15:40:29 +1000 1050) const struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1051) {
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1052) return __smu_get_sdb_partition(id, size, 0);
4350147a816b9 (Benjamin Herrenschmidt 2005-11-07 14:27:33 +1100 1053) }
4350147a816b9 (Benjamin Herrenschmidt 2005-11-07 14:27:33 +1100 1054) EXPORT_SYMBOL(smu_get_sdb_partition);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1055)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1056)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1057) /*
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1058) * Userland driver interface
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1059) */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1060)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1061)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1062) static LIST_HEAD(smu_clist);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1063) static DEFINE_SPINLOCK(smu_clist_lock);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1064)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1065) enum smu_file_mode {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1066) smu_file_commands,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1067) smu_file_events,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1068) smu_file_closing
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1069) };
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1070)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1071) struct smu_private
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1072) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1073) struct list_head list;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1074) enum smu_file_mode mode;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1075) int busy;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1076) struct smu_cmd cmd;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1077) spinlock_t lock;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1078) wait_queue_head_t wait;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1079) u8 buffer[SMU_MAX_DATA];
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1080) };
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1081)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1082)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1083) static int smu_open(struct inode *inode, struct file *file)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1084) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1085) struct smu_private *pp;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1086) unsigned long flags;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1087)
dd00cc486ab1c (Yoann Padioleau 2007-07-19 01:49:03 -0700 1088) pp = kzalloc(sizeof(struct smu_private), GFP_KERNEL);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1089) if (pp == 0)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1090) return -ENOMEM;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1091) spin_lock_init(&pp->lock);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1092) pp->mode = smu_file_commands;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1093) init_waitqueue_head(&pp->wait);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1094)
d851b6e04ee97 (Arnd Bergmann 2010-06-02 14:28:52 +0200 1095) mutex_lock(&smu_mutex);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1096) spin_lock_irqsave(&smu_clist_lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1097) list_add(&pp->list, &smu_clist);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1098) spin_unlock_irqrestore(&smu_clist_lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1099) file->private_data = pp;
d851b6e04ee97 (Arnd Bergmann 2010-06-02 14:28:52 +0200 1100) mutex_unlock(&smu_mutex);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1101)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1102) return 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1103) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1104)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1105)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1106) static void smu_user_cmd_done(struct smu_cmd *cmd, void *misc)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1107) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1108) struct smu_private *pp = misc;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1109)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1110) wake_up_all(&pp->wait);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1111) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1112)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1113)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1114) static ssize_t smu_write(struct file *file, const char __user *buf,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1115) size_t count, loff_t *ppos)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1116) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1117) struct smu_private *pp = file->private_data;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1118) unsigned long flags;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1119) struct smu_user_cmd_hdr hdr;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1120) int rc = 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1121)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1122) if (pp->busy)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1123) return -EBUSY;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1124) else if (copy_from_user(&hdr, buf, sizeof(hdr)))
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1125) return -EFAULT;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1126) else if (hdr.cmdtype == SMU_CMDTYPE_WANTS_EVENTS) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1127) pp->mode = smu_file_events;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1128) return 0;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1129) } else if (hdr.cmdtype == SMU_CMDTYPE_GET_PARTITION) {
018a3d1db7cdb (Jeremy Kerr 2006-07-12 15:40:29 +1000 1130) const struct smu_sdbp_header *part;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1131) part = __smu_get_sdb_partition(hdr.cmd, NULL, 1);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1132) if (part == NULL)
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1133) return -EINVAL;
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1134) else if (IS_ERR(part))
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1135) return PTR_ERR(part);
183d020258dfd (Benjamin Herrenschmidt 2005-11-07 14:29:02 +1100 1136) return 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1137) } else if (hdr.cmdtype != SMU_CMDTYPE_SMU)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1138) return -EINVAL;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1139) else if (pp->mode != smu_file_commands)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1140) return -EBADFD;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1141) else if (hdr.data_len > SMU_MAX_DATA)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1142) return -EINVAL;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1143)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1144) spin_lock_irqsave(&pp->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1145) if (pp->busy) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1146) spin_unlock_irqrestore(&pp->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1147) return -EBUSY;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1148) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1149) pp->busy = 1;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1150) pp->cmd.status = 1;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1151) spin_unlock_irqrestore(&pp->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1152)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1153) if (copy_from_user(pp->buffer, buf + sizeof(hdr), hdr.data_len)) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1154) pp->busy = 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1155) return -EFAULT;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1156) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1157)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1158) pp->cmd.cmd = hdr.cmd;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1159) pp->cmd.data_len = hdr.data_len;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1160) pp->cmd.reply_len = SMU_MAX_DATA;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1161) pp->cmd.data_buf = pp->buffer;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1162) pp->cmd.reply_buf = pp->buffer;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1163) pp->cmd.done = smu_user_cmd_done;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1164) pp->cmd.misc = pp;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1165) rc = smu_queue_cmd(&pp->cmd);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1166) if (rc < 0)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1167) return rc;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1168) return count;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1169) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1170)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1171)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1172) static ssize_t smu_read_command(struct file *file, struct smu_private *pp,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1173) char __user *buf, size_t count)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1174) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1175) DECLARE_WAITQUEUE(wait, current);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1176) struct smu_user_reply_hdr hdr;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1177) unsigned long flags;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1178) int size, rc = 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1179)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1180) if (!pp->busy)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1181) return 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1182) if (count < sizeof(struct smu_user_reply_hdr))
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1183) return -EOVERFLOW;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1184) spin_lock_irqsave(&pp->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1185) if (pp->cmd.status == 1) {
86e4754ac8fde (Julia Lawall 2010-03-29 05:34:46 +0000 1186) if (file->f_flags & O_NONBLOCK) {
86e4754ac8fde (Julia Lawall 2010-03-29 05:34:46 +0000 1187) spin_unlock_irqrestore(&pp->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1188) return -EAGAIN;
86e4754ac8fde (Julia Lawall 2010-03-29 05:34:46 +0000 1189) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1190) add_wait_queue(&pp->wait, &wait);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1191) for (;;) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1192) set_current_state(TASK_INTERRUPTIBLE);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1193) rc = 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1194) if (pp->cmd.status != 1)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1195) break;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1196) rc = -ERESTARTSYS;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1197) if (signal_pending(current))
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1198) break;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1199) spin_unlock_irqrestore(&pp->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1200) schedule();
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1201) spin_lock_irqsave(&pp->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1202) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1203) set_current_state(TASK_RUNNING);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1204) remove_wait_queue(&pp->wait, &wait);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1205) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1206) spin_unlock_irqrestore(&pp->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1207) if (rc)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1208) return rc;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1209) if (pp->cmd.status != 0)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1210) pp->cmd.reply_len = 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1211) size = sizeof(hdr) + pp->cmd.reply_len;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1212) if (count < size)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1213) size = count;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1214) rc = size;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1215) hdr.status = pp->cmd.status;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1216) hdr.reply_len = pp->cmd.reply_len;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1217) if (copy_to_user(buf, &hdr, sizeof(hdr)))
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1218) return -EFAULT;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1219) size -= sizeof(hdr);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1220) if (size && copy_to_user(buf + sizeof(hdr), pp->buffer, size))
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1221) return -EFAULT;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1222) pp->busy = 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1223)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1224) return rc;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1225) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1226)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1227)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1228) static ssize_t smu_read_events(struct file *file, struct smu_private *pp,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1229) char __user *buf, size_t count)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1230) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1231) /* Not implemented */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1232) msleep_interruptible(1000);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1233) return 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1234) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1235)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1236)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1237) static ssize_t smu_read(struct file *file, char __user *buf,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1238) size_t count, loff_t *ppos)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1239) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1240) struct smu_private *pp = file->private_data;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1241)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1242) if (pp->mode == smu_file_commands)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1243) return smu_read_command(file, pp, buf, count);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1244) if (pp->mode == smu_file_events)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1245) return smu_read_events(file, pp, buf, count);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1246)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1247) return -EBADFD;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1248) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1249)
afc9a42b7464f (Al Viro 2017-07-03 06:39:46 -0400 1250) static __poll_t smu_fpoll(struct file *file, poll_table *wait)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1251) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1252) struct smu_private *pp = file->private_data;
afc9a42b7464f (Al Viro 2017-07-03 06:39:46 -0400 1253) __poll_t mask = 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1254) unsigned long flags;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1255)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1256) if (pp == 0)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1257) return 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1258)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1259) if (pp->mode == smu_file_commands) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1260) poll_wait(file, &pp->wait, wait);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1261)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1262) spin_lock_irqsave(&pp->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1263) if (pp->busy && pp->cmd.status != 1)
a9a08845e9acb (Linus Torvalds 2018-02-11 14:34:03 -0800 1264) mask |= EPOLLIN;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1265) spin_unlock_irqrestore(&pp->lock, flags);
2055fb41ea6bf (Rasmus Villemoes 2014-06-20 21:44:27 +0200 1266) }
2055fb41ea6bf (Rasmus Villemoes 2014-06-20 21:44:27 +0200 1267) if (pp->mode == smu_file_events) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1268) /* Not yet implemented */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1269) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1270) return mask;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1271) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1272)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1273) static int smu_release(struct inode *inode, struct file *file)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1274) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1275) struct smu_private *pp = file->private_data;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1276) unsigned long flags;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1277) unsigned int busy;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1278)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1279) if (pp == 0)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1280) return 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1281)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1282) file->private_data = NULL;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1283)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1284) /* Mark file as closing to avoid races with new request */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1285) spin_lock_irqsave(&pp->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1286) pp->mode = smu_file_closing;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1287) busy = pp->busy;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1288)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1289) /* Wait for any pending request to complete */
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1290) if (busy && pp->cmd.status == 1) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1291) DECLARE_WAITQUEUE(wait, current);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1292)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1293) add_wait_queue(&pp->wait, &wait);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1294) for (;;) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1295) set_current_state(TASK_UNINTERRUPTIBLE);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1296) if (pp->cmd.status != 1)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1297) break;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1298) spin_unlock_irqrestore(&pp->lock, flags);
94256dd680f83 (Andrew Morton 2007-04-16 22:53:25 -0700 1299) schedule();
94256dd680f83 (Andrew Morton 2007-04-16 22:53:25 -0700 1300) spin_lock_irqsave(&pp->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1301) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1302) set_current_state(TASK_RUNNING);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1303) remove_wait_queue(&pp->wait, &wait);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1304) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1305) spin_unlock_irqrestore(&pp->lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1306)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1307) spin_lock_irqsave(&smu_clist_lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1308) list_del(&pp->list);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1309) spin_unlock_irqrestore(&smu_clist_lock, flags);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1310) kfree(pp);
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1311)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1312) return 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1313) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1314)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1315)
fa027c2a0a0d6 (Arjan van de Ven 2007-02-12 00:55:33 -0800 1316) static const struct file_operations smu_device_fops = {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1317) .llseek = no_llseek,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1318) .read = smu_read,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1319) .write = smu_write,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1320) .poll = smu_fpoll,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1321) .open = smu_open,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1322) .release = smu_release,
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1323) };
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1324)
6b67f62cf655c (Stephen Rothwell 2005-09-27 14:09:39 +1000 1325) static struct miscdevice pmu_device = {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1326) MISC_DYNAMIC_MINOR, "smu", &smu_device_fops
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1327) };
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1328)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1329) static int smu_device_init(void)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1330) {
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1331) if (!smu)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1332) return -ENODEV;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1333) if (misc_register(&pmu_device) < 0)
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1334) printk(KERN_ERR "via-pmu: cannot register misc device.\n");
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1335) return 0;
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1336) }
0365ba7fb1fa9 (Benjamin Herrenschmidt 2005-09-22 21:44:06 -0700 1337) device_initcall(smu_device_init);