13e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt/*
23e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt * RackMac vu-meter driver
33e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt *
43e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt * (c) Copyright 2006 Benjamin Herrenschmidt, IBM Corp.
53e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt *                    <benh@kernel.crashing.org>
63e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt *
73e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt * Released under the term of the GNU GPL v2.
83e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt *
93e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt * Support the CPU-meter LEDs of the Xserve G5
103e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt *
113e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt * TODO: Implement PWM to do variable intensity and provide userland
123e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt * interface for fun. Also, the CPU-meter could be made nicer by being
133e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt * a bit less "immediate" but giving instead a more average load over
143e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt * time. Patches welcome :-)
153e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt *
163e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt */
173e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#undef DEBUG
183e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
193e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#include <linux/types.h>
203e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#include <linux/kernel.h>
215a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
223e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#include <linux/device.h>
233e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#include <linux/interrupt.h>
243e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#include <linux/module.h>
253e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#include <linux/pci.h>
263e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#include <linux/dma-mapping.h>
273e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#include <linux/kernel_stat.h>
283e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
293e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#include <asm/io.h>
303e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#include <asm/prom.h>
313e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#include <asm/machdep.h>
323e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#include <asm/pmac_feature.h>
333e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#include <asm/dbdma.h>
343e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#include <asm/macio.h>
353e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#include <asm/keylargo.h>
363e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
373e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt/* Number of samples in a sample buffer */
383e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#define SAMPLE_COUNT		256
393e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
403e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt/* CPU meter sampling rate in ms */
413e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#define CPU_SAMPLING_RATE	250
423e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
433e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstruct rackmeter_dma {
443e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct dbdma_cmd	cmd[4]			____cacheline_aligned;
453e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	u32			mark			____cacheline_aligned;
463e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	u32			buf1[SAMPLE_COUNT]	____cacheline_aligned;
473e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	u32			buf2[SAMPLE_COUNT]	____cacheline_aligned;
483e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt} ____cacheline_aligned;
493e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
503e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstruct rackmeter_cpu {
516d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howells	struct delayed_work	sniffer;
526d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howells	struct rackmeter	*rm;
533e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	cputime64_t		prev_wall;
543e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	cputime64_t		prev_idle;
553e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	int			zero;
563e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt} ____cacheline_aligned;
573e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
583e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstruct rackmeter {
593e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct macio_dev		*mdev;
603e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	unsigned int			irq;
613e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct device_node		*i2s;
623e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	u8				*ubuf;
633e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct dbdma_regs __iomem	*dma_regs;
643e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	void __iomem			*i2s_regs;
653e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	dma_addr_t			dma_buf_p;
663e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct rackmeter_dma		*dma_buf_v;
673e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	int				stale_irq;
683e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct rackmeter_cpu		cpu[2];
693e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	int				paused;
703e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct mutex			sem;
713e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt};
723e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
733e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt/* To be set as a tunable */
743e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstatic int rackmeter_ignore_nice;
753e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
763e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt/* This GPIO is whacked by the OS X driver when initializing */
773e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#define RACKMETER_MAGIC_GPIO	0x78
783e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
793e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt/* This is copied from cpufreq_ondemand, maybe we should put it in
803e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt * a common header somewhere
813e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt */
823e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstatic inline cputime64_t get_cpu_idle_time(unsigned int cpu)
833e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt{
843292beb340c76884427faa1f5d6085719477d889Glauber Costa	u64 retval;
853e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
863292beb340c76884427faa1f5d6085719477d889Glauber Costa	retval = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE] +
873292beb340c76884427faa1f5d6085719477d889Glauber Costa		 kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT];
883e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
893e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (rackmeter_ignore_nice)
903292beb340c76884427faa1f5d6085719477d889Glauber Costa		retval += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE];
913e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
923e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	return retval;
933e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt}
943e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
953e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstatic void rackmeter_setup_i2s(struct rackmeter *rm)
963e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt{
973e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct macio_chip *macio = rm->mdev->bus->chip;
983e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
993e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* First whack magic GPIO */
1003e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, RACKMETER_MAGIC_GPIO, 5);
1013e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1023e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1033e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Call feature code to enable the sound channel and the proper
1043e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 * clock sources
1053e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 */
1063e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, rm->i2s, 0, 1);
1073e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1083e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Power i2s and stop i2s clock. We whack MacIO FCRs directly for now.
1093e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 * This is a bit racy, thus we should add new platform functions to
1103e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 * handle that. snd-aoa needs that too
1113e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 */
1123e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_ENABLE);
1133e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	MACIO_BIC(KEYLARGO_FCR1, KL1_I2S0_CLK_ENABLE_BIT);
1143e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	(void)MACIO_IN32(KEYLARGO_FCR1);
1153e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	udelay(10);
1163e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1173e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Then setup i2s. For now, we use the same magic value that
1183e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 * the OS X driver seems to use. We might want to play around
1193e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 * with the clock divisors later
1203e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 */
1213e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	out_le32(rm->i2s_regs + 0x10, 0x01fa0000);
1223e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	(void)in_le32(rm->i2s_regs + 0x10);
1233e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	udelay(10);
1243e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1253e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Fully restart i2s*/
1263e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_CELL_ENABLE |
1273e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		  KL1_I2S0_CLK_ENABLE_BIT);
1283e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	(void)MACIO_IN32(KEYLARGO_FCR1);
1293e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	udelay(10);
1303e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt}
1313e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1323e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstatic void rackmeter_set_default_pattern(struct rackmeter *rm)
1333e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt{
1343e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	int i;
1353e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1363e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	for (i = 0; i < 16; i++) {
1373e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		if (i < 8)
1383e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt			rm->ubuf[i] = (i & 1) * 255;
1393e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		else
1403e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt			rm->ubuf[i] = ((~i) & 1) * 255;
1413e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
1423e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt}
1433e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1443e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstatic void rackmeter_do_pause(struct rackmeter *rm, int pause)
1453e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt{
1463e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct rackmeter_dma *rdma = rm->dma_buf_v;
1473e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1483e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	pr_debug("rackmeter: %s\n", pause ? "paused" : "started");
1493e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1503e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rm->paused = pause;
1513e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (pause) {
1523e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		DBDMA_DO_STOP(rm->dma_regs);
1533e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		return;
1543e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
1553e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	memset(rdma->buf1, 0, SAMPLE_COUNT & sizeof(u32));
1563e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	memset(rdma->buf2, 0, SAMPLE_COUNT & sizeof(u32));
1573e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1583e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rm->dma_buf_v->mark = 0;
1593e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1603e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	mb();
1613e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	out_le32(&rm->dma_regs->cmdptr_hi, 0);
1623e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	out_le32(&rm->dma_regs->cmdptr, rm->dma_buf_p);
1633e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	out_le32(&rm->dma_regs->control, (RUN << 16) | RUN);
1643e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt}
1653e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1663e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstatic void rackmeter_setup_dbdma(struct rackmeter *rm)
1673e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt{
1683e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct rackmeter_dma *db = rm->dma_buf_v;
1693e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct dbdma_cmd *cmd = db->cmd;
1703e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1713e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Make sure dbdma is reset */
1723e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	DBDMA_DO_RESET(rm->dma_regs);
1733e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
174193d0732920fd09825501136f3a01e9c28a700e6Al Viro	pr_debug("rackmeter: mark offset=0x%zx\n",
1753e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		 offsetof(struct rackmeter_dma, mark));
176193d0732920fd09825501136f3a01e9c28a700e6Al Viro	pr_debug("rackmeter: buf1 offset=0x%zx\n",
1773e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		 offsetof(struct rackmeter_dma, buf1));
178193d0732920fd09825501136f3a01e9c28a700e6Al Viro	pr_debug("rackmeter: buf2 offset=0x%zx\n",
1793e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		 offsetof(struct rackmeter_dma, buf2));
1803e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1813e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Prepare 4 dbdma commands for the 2 buffers */
1823e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	memset(cmd, 0, 4 * sizeof(struct dbdma_cmd));
1833e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	st_le16(&cmd->req_count, 4);
1843e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	st_le16(&cmd->command, STORE_WORD | INTR_ALWAYS | KEY_SYSTEM);
1853e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	st_le32(&cmd->phy_addr, rm->dma_buf_p +
1863e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		offsetof(struct rackmeter_dma, mark));
1873e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	st_le32(&cmd->cmd_dep, 0x02000000);
1883e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	cmd++;
1893e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1903e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	st_le16(&cmd->req_count, SAMPLE_COUNT * 4);
1913e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	st_le16(&cmd->command, OUTPUT_MORE);
1923e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	st_le32(&cmd->phy_addr, rm->dma_buf_p +
1933e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		offsetof(struct rackmeter_dma, buf1));
1943e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	cmd++;
1953e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
1963e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	st_le16(&cmd->req_count, 4);
1973e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	st_le16(&cmd->command, STORE_WORD | INTR_ALWAYS | KEY_SYSTEM);
1983e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	st_le32(&cmd->phy_addr, rm->dma_buf_p +
1993e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		offsetof(struct rackmeter_dma, mark));
2003e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	st_le32(&cmd->cmd_dep, 0x01000000);
2013e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	cmd++;
2023e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
2033e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	st_le16(&cmd->req_count, SAMPLE_COUNT * 4);
2043e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	st_le16(&cmd->command, OUTPUT_MORE | BR_ALWAYS);
2053e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	st_le32(&cmd->phy_addr, rm->dma_buf_p +
2063e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		offsetof(struct rackmeter_dma, buf2));
2073e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	st_le32(&cmd->cmd_dep, rm->dma_buf_p);
2083e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
2093e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rackmeter_do_pause(rm, 0);
2103e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt}
2113e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
2126d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howellsstatic void rackmeter_do_timer(struct work_struct *work)
2133e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt{
2146d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howells	struct rackmeter_cpu *rcpu =
2156d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howells		container_of(work, struct rackmeter_cpu, sniffer.work);
2166d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howells	struct rackmeter *rm = rcpu->rm;
2173e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	unsigned int cpu = smp_processor_id();
2183e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	cputime64_t cur_jiffies, total_idle_ticks;
2193e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	unsigned int total_ticks, idle_ticks;
2203e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	int i, offset, load, cumm, pause;
2213e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
2223e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	cur_jiffies = jiffies64_to_cputime64(get_jiffies_64());
223648616343cdbe904c585a6c12e323d3b3c72e46fMartin Schwidefsky	total_ticks = (unsigned int) (cur_jiffies - rcpu->prev_wall);
2243e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rcpu->prev_wall = cur_jiffies;
2253e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
2263e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	total_idle_ticks = get_cpu_idle_time(cpu);
227648616343cdbe904c585a6c12e323d3b3c72e46fMartin Schwidefsky	idle_ticks = (unsigned int) (total_idle_ticks - rcpu->prev_idle);
2283e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rcpu->prev_idle = total_idle_ticks;
2293e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
2303e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* We do a very dumb calculation to update the LEDs for now,
2313e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 * we'll do better once we have actual PWM implemented
2323e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 */
2333e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	load = (9 * (total_ticks - idle_ticks)) / total_ticks;
2343e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
2353e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	offset = cpu << 3;
2363e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	cumm = 0;
2373e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	for (i = 0; i < 8; i++) {
2383e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		u8 ub = (load > i) ? 0xff : 0;
2393e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		rm->ubuf[i + offset] = ub;
2403e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		cumm |= ub;
2413e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
2423e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rcpu->zero = (cumm == 0);
2433e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
2443e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Now check if LEDs are all 0, we can stop DMA */
2453e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	pause = (rm->cpu[0].zero && rm->cpu[1].zero);
2463e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (pause != rm->paused) {
2473e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		mutex_lock(&rm->sem);
2483e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		pause = (rm->cpu[0].zero && rm->cpu[1].zero);
2493e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		rackmeter_do_pause(rm, pause);
2503e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		mutex_unlock(&rm->sem);
2513e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
2523e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	schedule_delayed_work_on(cpu, &rcpu->sniffer,
2533e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt				 msecs_to_jiffies(CPU_SAMPLING_RATE));
2543e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt}
2553e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
2563e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstatic void __devinit rackmeter_init_cpu_sniffer(struct rackmeter *rm)
2573e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt{
2583e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	unsigned int cpu;
2593e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
2603e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* This driver works only with 1 or 2 CPUs numbered 0 and 1,
2613e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 * but that's really all we have on Apple Xserve. It doesn't
2623e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 * play very nice with CPU hotplug neither but we don't do that
2633e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 * on those machines yet
2643e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 */
2653e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
2666d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howells	rm->cpu[0].rm = rm;
2676d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howells	INIT_DELAYED_WORK(&rm->cpu[0].sniffer, rackmeter_do_timer);
2686d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howells	rm->cpu[1].rm = rm;
2696d5aefb8eaa38e44b5b8cf60c812aceafc02d924David Howells	INIT_DELAYED_WORK(&rm->cpu[1].sniffer, rackmeter_do_timer);
2703e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
2713e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	for_each_online_cpu(cpu) {
2723e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		struct rackmeter_cpu *rcpu;
2733e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
2743e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		if (cpu > 1)
2753e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt			continue;
276a419aef8b858a2bdb98df60336063d28df4b272fJoe Perches		rcpu = &rm->cpu[cpu];
2773e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		rcpu->prev_idle = get_cpu_idle_time(cpu);
2783e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		rcpu->prev_wall = jiffies64_to_cputime64(get_jiffies_64());
2793e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		schedule_delayed_work_on(cpu, &rm->cpu[cpu].sniffer,
2803e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt					 msecs_to_jiffies(CPU_SAMPLING_RATE));
2813e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
2823e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt}
2833e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
284e1f4dea454c8e643644114757080680e1959d410Grant Likelystatic void rackmeter_stop_cpu_sniffer(struct rackmeter *rm)
2853e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt{
286afe2c511fb2d75f1515081ff1be15bd79cfe722dTejun Heo	cancel_delayed_work_sync(&rm->cpu[0].sniffer);
287afe2c511fb2d75f1515081ff1be15bd79cfe722dTejun Heo	cancel_delayed_work_sync(&rm->cpu[1].sniffer);
2883e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt}
2893e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
29031421a6f6ea88236cb17b6a24aa21e66a6138d4cAl Virostatic int __devinit rackmeter_setup(struct rackmeter *rm)
2913e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt{
2923e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	pr_debug("rackmeter: setting up i2s..\n");
2933e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rackmeter_setup_i2s(rm);
2943e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
2953e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	pr_debug("rackmeter: setting up default pattern..\n");
2963e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rackmeter_set_default_pattern(rm);
2973e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
2983e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	pr_debug("rackmeter: setting up dbdma..\n");
2993e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rackmeter_setup_dbdma(rm);
3003e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3013e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	pr_debug("rackmeter: start CPU measurements..\n");
3023e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rackmeter_init_cpu_sniffer(rm);
3033e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3043e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	printk(KERN_INFO "RackMeter initialized\n");
3053e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3063e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	return 0;
3073e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt}
3083e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3093e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt/*  XXX FIXME: No PWM yet, this is 0/1 */
3103e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstatic u32 rackmeter_calc_sample(struct rackmeter *rm, unsigned int index)
3113e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt{
3123e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	int led;
3133e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	u32 sample = 0;
3143e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3153e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	for (led = 0; led < 16; led++) {
3163e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		sample >>= 1;
3173e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		sample |= ((rm->ubuf[led] >= 0x80) << 15);
3183e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
3193e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	return (sample << 17) | (sample >> 15);
3203e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt}
3213e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3223e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstatic irqreturn_t rackmeter_irq(int irq, void *arg)
3233e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt{
3243e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct rackmeter *rm = arg;
3253e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct rackmeter_dma *db = rm->dma_buf_v;
3263e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	unsigned int mark, i;
3273e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	u32 *buf;
3283e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3293e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Flush PCI buffers with an MMIO read. Maybe we could actually
3303e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 * check the status one day ... in case things go wrong, though
3313e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 * this never happened to me
3323e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 */
3333e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	(void)in_le32(&rm->dma_regs->status);
3343e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3353e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Make sure the CPU gets us in order */
3363e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rmb();
3373e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3383e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Read mark */
3393e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	mark = db->mark;
3403e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (mark != 1 && mark != 2) {
3413e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		printk(KERN_WARNING "rackmeter: Incorrect DMA mark 0x%08x\n",
3423e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		       mark);
3433e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		/* We allow for 3 errors like that (stale DBDMA irqs) */
3443e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		if (++rm->stale_irq > 3) {
3453e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt			printk(KERN_ERR "rackmeter: Too many errors,"
3463e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt			       " stopping DMA\n");
3473e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt			DBDMA_DO_RESET(rm->dma_regs);
3483e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		}
3493e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		return IRQ_HANDLED;
3503e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
3513e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3523e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Next buffer we need to fill is mark value */
3533e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	buf = mark == 1 ? db->buf1 : db->buf2;
3543e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3553e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Fill it now. This routine converts the 8 bits depth sample array
3563e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 * into the PWM bitmap for each LED.
3573e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	 */
3583e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	for (i = 0; i < SAMPLE_COUNT; i++)
3593e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		buf[i] = rackmeter_calc_sample(rm, i);
3603e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3613e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3623e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	return IRQ_HANDLED;
3633e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt}
3643e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3653e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstatic int __devinit rackmeter_probe(struct macio_dev* mdev,
3663e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt				     const struct of_device_id *match)
3673e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt{
3683e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct device_node *i2s = NULL, *np = NULL;
3693e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct rackmeter *rm = NULL;
3703e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct resource ri2s, rdma;
3713e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	int rc = -ENODEV;
3723e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3733e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	pr_debug("rackmeter_probe()\n");
3743e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3753e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Get i2s-a node */
37661c7a080a5a061c976988fd4b844dfb468dda255Grant Likely	while ((i2s = of_get_next_child(mdev->ofdev.dev.of_node, i2s)) != NULL)
3773e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	       if (strcmp(i2s->name, "i2s-a") == 0)
3783e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		       break;
3793e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (i2s == NULL) {
3803e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		pr_debug("  i2s-a child not found\n");
3813e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		goto bail;
3823e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
3833e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Get lightshow or virtual sound */
3843e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	while ((np = of_get_next_child(i2s, np)) != NULL) {
3853e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	       if (strcmp(np->name, "lightshow") == 0)
3863e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		       break;
3873e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	       if ((strcmp(np->name, "sound") == 0) &&
38801b2726dd11ef198ac6cf8f88974b4427d40ffdbStephen Rothwell		   of_get_property(np, "virtual", NULL) != NULL)
3893e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		       break;
3903e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
3913e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (np == NULL) {
3923e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		pr_debug("  lightshow or sound+virtual child not found\n");
3933e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		goto bail;
3943e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
3953e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
3963e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Create and initialize our instance data */
3973e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rm = kzalloc(sizeof(struct rackmeter), GFP_KERNEL);
3983e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (rm == NULL) {
3993e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		printk(KERN_ERR "rackmeter: failed to allocate memory !\n");
4003e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		rc = -ENOMEM;
4013e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		goto bail_release;
4023e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
4033e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rm->mdev = mdev;
4043e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rm->i2s = i2s;
4053e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	mutex_init(&rm->sem);
4063e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	dev_set_drvdata(&mdev->ofdev.dev, rm);
4073e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Check resources availability. We need at least resource 0 and 1 */
4083e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#if 0 /* Use that when i2s-a is finally an mdev per-se */
4093e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (macio_resource_count(mdev) < 2 || macio_irq_count(mdev) < 2) {
4103e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		printk(KERN_ERR
4113e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		       "rackmeter: found match but lacks resources: %s"
4123e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		       " (%d resources, %d interrupts)\n",
4133e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		       mdev->ofdev.node->full_name);
4143e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		rc = -ENXIO;
4153e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		goto bail_free;
4163e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
4173e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (macio_request_resources(mdev, "rackmeter")) {
4183e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		printk(KERN_ERR
4193e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		       "rackmeter: failed to request resources: %s\n",
4203e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		       mdev->ofdev.node->full_name);
4213e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		rc = -EBUSY;
4223e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		goto bail_free;
4233e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
4243e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rm->irq = macio_irq(mdev, 1);
4253e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#else
4263e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rm->irq = irq_of_parse_and_map(i2s, 1);
4273e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (rm->irq == NO_IRQ ||
4283e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	    of_address_to_resource(i2s, 0, &ri2s) ||
4293e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	    of_address_to_resource(i2s, 1, &rdma)) {
4303e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		printk(KERN_ERR
4313e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		       "rackmeter: found match but lacks resources: %s",
43261c7a080a5a061c976988fd4b844dfb468dda255Grant Likely		       mdev->ofdev.dev.of_node->full_name);
4333e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		rc = -ENXIO;
4343e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		goto bail_free;
4353e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
4363e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#endif
4373e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
4383e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	pr_debug("  i2s @0x%08x\n", (unsigned int)ri2s.start);
4393e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	pr_debug("  dma @0x%08x\n", (unsigned int)rdma.start);
4403e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	pr_debug("  irq %d\n", rm->irq);
4413e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
4423e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rm->ubuf = (u8 *)__get_free_page(GFP_KERNEL);
4433e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (rm->ubuf == NULL) {
4443e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		printk(KERN_ERR
4453e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		       "rackmeter: failed to allocate samples page !\n");
4463e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		rc = -ENOMEM;
4473e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		goto bail_release;
4483e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
4493e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
4503e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rm->dma_buf_v = dma_alloc_coherent(&macio_get_pci_dev(mdev)->dev,
4513e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt					   sizeof(struct rackmeter_dma),
4523e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt					   &rm->dma_buf_p, GFP_KERNEL);
4533e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (rm->dma_buf_v == NULL) {
4543e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		printk(KERN_ERR
4553e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		       "rackmeter: failed to allocate dma buffer !\n");
4563e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		rc = -ENOMEM;
4573e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		goto bail_free_samples;
4583e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
4593e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#if 0
4603e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rm->i2s_regs = ioremap(macio_resource_start(mdev, 0), 0x1000);
4613e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#else
4623e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rm->i2s_regs = ioremap(ri2s.start, 0x1000);
4633e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#endif
4643e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (rm->i2s_regs == NULL) {
4653e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		printk(KERN_ERR
4663e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		       "rackmeter: failed to map i2s registers !\n");
4673e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		rc = -ENXIO;
4683e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		goto bail_free_dma;
4693e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
4703e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#if 0
4713e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rm->dma_regs = ioremap(macio_resource_start(mdev, 1), 0x100);
4723e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#else
4733e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rm->dma_regs = ioremap(rdma.start, 0x100);
4743e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#endif
4753e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (rm->dma_regs == NULL) {
4763e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		printk(KERN_ERR
4773e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		       "rackmeter: failed to map dma registers !\n");
4783e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		rc = -ENXIO;
4793e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		goto bail_unmap_i2s;
4803e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
4813e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
4823e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rc = rackmeter_setup(rm);
4833e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (rc) {
4843e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		printk(KERN_ERR
4853e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		       "rackmeter: failed to initialize !\n");
4863e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		rc = -ENXIO;
4873e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		goto bail_unmap_dma;
4883e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
4893e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
4903e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rc = request_irq(rm->irq, rackmeter_irq, 0, "rackmeter", rm);
4913e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (rc != 0) {
4923e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		printk(KERN_ERR
4933e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		       "rackmeter: failed to request interrupt !\n");
4943e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		goto bail_stop_dma;
4953e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	}
4963e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	of_node_put(np);
4973e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	return 0;
4983e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
4993e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt bail_stop_dma:
5003e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	DBDMA_DO_RESET(rm->dma_regs);
5013e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt bail_unmap_dma:
5023e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	iounmap(rm->dma_regs);
5033e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt bail_unmap_i2s:
5043e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	iounmap(rm->i2s_regs);
5053e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt bail_free_dma:
5063e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	dma_free_coherent(&macio_get_pci_dev(mdev)->dev,
5073e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt			  sizeof(struct rackmeter_dma),
5083e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt			  rm->dma_buf_v, rm->dma_buf_p);
5093e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt bail_free_samples:
5103e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	free_page((unsigned long)rm->ubuf);
5113e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt bail_release:
5123e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#if 0
5133e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	macio_release_resources(mdev);
5143e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#endif
5153e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt bail_free:
5163e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	kfree(rm);
5173e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt bail:
5183e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	of_node_put(i2s);
5193e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	of_node_put(np);
5203e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	dev_set_drvdata(&mdev->ofdev.dev, NULL);
5213e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	return rc;
5223e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt}
5233e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5243e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstatic int __devexit rackmeter_remove(struct macio_dev* mdev)
5253e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt{
5263e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct rackmeter *rm = dev_get_drvdata(&mdev->ofdev.dev);
5273e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5283e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Stop CPU sniffer timer & work queues */
5293e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rackmeter_stop_cpu_sniffer(rm);
5303e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5313e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Clear reference to private data */
5323e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	dev_set_drvdata(&mdev->ofdev.dev, NULL);
5333e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5343e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Stop/reset dbdma */
5353e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	DBDMA_DO_RESET(rm->dma_regs);
5363e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5373e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Release the IRQ */
5383e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	free_irq(rm->irq, rm);
5393e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5403e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Unmap registers */
5413e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	iounmap(rm->dma_regs);
5423e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	iounmap(rm->i2s_regs);
5433e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5443e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Free DMA */
5453e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	dma_free_coherent(&macio_get_pci_dev(mdev)->dev,
5463e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt			  sizeof(struct rackmeter_dma),
5473e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt			  rm->dma_buf_v, rm->dma_buf_p);
5483e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5493e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Free samples */
5503e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	free_page((unsigned long)rm->ubuf);
5513e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5523e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#if 0
5533e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Release resources */
5543e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	macio_release_resources(mdev);
5553e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt#endif
5563e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5573e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Get rid of me */
5583e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	kfree(rm);
5593e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5603e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	return 0;
5613e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt}
5623e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5633e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstatic int rackmeter_shutdown(struct macio_dev* mdev)
5643e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt{
5653e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	struct rackmeter *rm = dev_get_drvdata(&mdev->ofdev.dev);
5663e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5673e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	if (rm == NULL)
5683e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt		return -ENODEV;
5693e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5703e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Stop CPU sniffer timer & work queues */
5713e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	rackmeter_stop_cpu_sniffer(rm);
5723e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5733e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	/* Stop/reset dbdma */
5743e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	DBDMA_DO_RESET(rm->dma_regs);
5753e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5763e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	return 0;
5773e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt}
5783e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5793e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstatic struct of_device_id rackmeter_match[] = {
5803e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	{ .name = "i2s" },
5813e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	{ }
5823e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt};
5833e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
58431421a6f6ea88236cb17b6a24aa21e66a6138d4cAl Virostatic struct macio_driver rackmeter_driver = {
585c2cdf6aba0dfcfb54be646ab630c1bccd180e890Benjamin Herrenschmidt	.driver = {
586c2cdf6aba0dfcfb54be646ab630c1bccd180e890Benjamin Herrenschmidt		.name = "rackmeter",
587c2cdf6aba0dfcfb54be646ab630c1bccd180e890Benjamin Herrenschmidt		.owner = THIS_MODULE,
588c2cdf6aba0dfcfb54be646ab630c1bccd180e890Benjamin Herrenschmidt		.of_match_table = rackmeter_match,
589c2cdf6aba0dfcfb54be646ab630c1bccd180e890Benjamin Herrenschmidt	},
5903e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	.probe = rackmeter_probe,
59131421a6f6ea88236cb17b6a24aa21e66a6138d4cAl Viro	.remove = __devexit_p(rackmeter_remove),
5923e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	.shutdown = rackmeter_shutdown,
5933e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt};
5943e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5953e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
5963e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstatic int __init rackmeter_init(void)
5973e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt{
5983e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	pr_debug("rackmeter_init()\n");
5993e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
60031421a6f6ea88236cb17b6a24aa21e66a6138d4cAl Viro	return macio_register_driver(&rackmeter_driver);
6013e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt}
6023e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
6033e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtstatic void __exit rackmeter_exit(void)
6043e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt{
6053e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt	pr_debug("rackmeter_exit()\n");
6063e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
60731421a6f6ea88236cb17b6a24aa21e66a6138d4cAl Viro	macio_unregister_driver(&rackmeter_driver);
6083e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt}
6093e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
6103e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtmodule_init(rackmeter_init);
6113e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidtmodule_exit(rackmeter_exit);
6123e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
6133e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin Herrenschmidt
6143e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin HerrenschmidtMODULE_LICENSE("GPL");
6153e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin HerrenschmidtMODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
6163e00a5aec3d6af687e37f4e7482f5c7ecdcabd0bBenjamin HerrenschmidtMODULE_DESCRIPTION("RackMeter: Support vu-meter on XServe front panel");
617