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