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