aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_vnodeops.h
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2008-10-30 03:27:48 -0400
committerLachlan McIlroy <lachlan@redback.melbourne.sgi.com>2008-10-30 03:27:48 -0400
commitea5a3dc8356bf1cf27bab9a5a0da5dfbbb82013d (patch)
tree30af54170d0cb3b06c2ac21bc31bc57fc5eb4d43 /fs/xfs/xfs_vnodeops.h
parent7ee49acfe54883f16d28d9486b789431a5804d18 (diff)
[XFS] kill sys_cred
capable_cred has been unused for a while so we can kill it and sys_cred. That also means the cred argument to xfs_setattr and xfs_change_file_space can be removed now. SGI-PV: 988918 SGI-Modid: xfs-linux-melb:xfs-kern:32412a Signed-off-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Tim Shimmin <tes@sgi.com> Signed-off-by: David Chinner <david@fromorbit.com> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_vnodeops.h')
-rw-r--r--fs/xfs/xfs_vnodeops.h6
1 files changed, 2 insertions, 4 deletions
diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h
index e932a96bec54..b1ae8e3f4043 100644
--- a/fs/xfs/xfs_vnodeops.h
+++ b/fs/xfs/xfs_vnodeops.h
@@ -15,8 +15,7 @@ struct xfs_iomap;
15 15
16 16
17int xfs_open(struct xfs_inode *ip); 17int xfs_open(struct xfs_inode *ip);
18int xfs_setattr(struct xfs_inode *ip, struct iattr *vap, int flags, 18int xfs_setattr(struct xfs_inode *ip, struct iattr *vap, int flags);
19 struct cred *credp);
20#define XFS_ATTR_DMI 0x01 /* invocation from a DMI function */ 19#define XFS_ATTR_DMI 0x01 /* invocation from a DMI function */
21#define XFS_ATTR_NONBLOCK 0x02 /* return EAGAIN if operation would block */ 20#define XFS_ATTR_NONBLOCK 0x02 /* return EAGAIN if operation would block */
22#define XFS_ATTR_NOLOCK 0x04 /* Don't grab any conflicting locks */ 21#define XFS_ATTR_NOLOCK 0x04 /* Don't grab any conflicting locks */
@@ -44,8 +43,7 @@ int xfs_inode_flush(struct xfs_inode *ip, int flags);
44int xfs_set_dmattrs(struct xfs_inode *ip, u_int evmask, u_int16_t state); 43int xfs_set_dmattrs(struct xfs_inode *ip, u_int evmask, u_int16_t state);
45int xfs_reclaim(struct xfs_inode *ip); 44int xfs_reclaim(struct xfs_inode *ip);
46int xfs_change_file_space(struct xfs_inode *ip, int cmd, 45int xfs_change_file_space(struct xfs_inode *ip, int cmd,
47 xfs_flock64_t *bf, xfs_off_t offset, 46 xfs_flock64_t *bf, xfs_off_t offset, int attr_flags);
48 struct cred *credp, int attr_flags);
49int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name, 47int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name,
50 struct xfs_inode *src_ip, struct xfs_inode *target_dp, 48 struct xfs_inode *src_ip, struct xfs_inode *target_dp,
51 struct xfs_name *target_name, struct xfs_inode *target_ip); 49 struct xfs_name *target_name, struct xfs_inode *target_ip);
>515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
/*
 * Windfarm PowerMac thermal control.
 * Control loops for machines with SMU and PPC970MP processors.
 *
 * Copyright (C) 2005 Paul Mackerras, IBM Corp. <paulus@samba.org>
 * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
 *
 * Use and redistribute under the terms of the GNU GPL v2.
 */
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <asm/prom.h>
#include <asm/smu.h>

#include "windfarm.h"
#include "windfarm_pid.h"

#define VERSION "0.2"

#define DEBUG
#undef LOTSA_DEBUG

#ifdef DEBUG
#define DBG(args...)	printk(args)
#else
#define DBG(args...)	do { } while(0)
#endif

#ifdef LOTSA_DEBUG
#define DBG_LOTS(args...)	printk(args)
#else
#define DBG_LOTS(args...)	do { } while(0)
#endif

/* define this to force CPU overtemp to 60 degree, useful for testing
 * the overtemp code
 */
#undef HACKED_OVERTEMP

/* We currently only handle 2 chips, 4 cores... */
#define NR_CHIPS	2
#define NR_CORES	4
#define NR_CPU_FANS	3 * NR_CHIPS

/* Controls and sensors */
static struct wf_sensor *sens_cpu_temp[NR_CORES];
static struct wf_sensor *sens_cpu_power[NR_CORES];
static struct wf_sensor *hd_temp;
static struct wf_sensor *slots_power;
static struct wf_sensor *u4_temp;

static struct wf_control *cpu_fans[NR_CPU_FANS];
static char *cpu_fan_names[NR_CPU_FANS] = {
	"cpu-rear-fan-0",
	"cpu-rear-fan-1",
	"cpu-front-fan-0",
	"cpu-front-fan-1",
	"cpu-pump-0",
	"cpu-pump-1",
};
static struct wf_control *cpufreq_clamp;

/* Second pump isn't required (and isn't actually present) */
#define CPU_FANS_REQD		(NR_CPU_FANS - 2)
#define FIRST_PUMP		4
#define LAST_PUMP		5

/* We keep a temperature history for average calculation of 180s */
#define CPU_TEMP_HIST_SIZE	180

/* Scale factor for fan speed, *100 */
static int cpu_fan_scale[NR_CPU_FANS] = {
	100,
	100,
	97,		/* inlet fans run at 97% of exhaust fan */
	97,
	100,		/* updated later */
	100,		/* updated later */
};

static struct wf_control *backside_fan;
static struct wf_control *slots_fan;
static struct wf_control *drive_bay_fan;

/* PID loop state */
static struct wf_cpu_pid_state cpu_pid[NR_CORES];
static u32 cpu_thist[CPU_TEMP_HIST_SIZE];
static int cpu_thist_pt;
static s64 cpu_thist_total;
static s32 cpu_all_tmax = 100 << 16;
static int cpu_last_target;
static struct wf_pid_state backside_pid;
static int backside_tick;
static struct wf_pid_state slots_pid;
static int slots_started;
static struct wf_pid_state drive_bay_pid;
static int drive_bay_tick;

static int nr_cores;
static int have_all_controls;
static int have_all_sensors;
static int started;

static int failure_state;
#define FAILURE_SENSOR		1
#define FAILURE_FAN		2
#define FAILURE_PERM		4
#define FAILURE_LOW_OVERTEMP	8
#define FAILURE_HIGH_OVERTEMP	16

/* Overtemp values */
#define LOW_OVER_AVERAGE	0
#define LOW_OVER_IMMEDIATE	(10 << 16)
#define LOW_OVER_CLEAR		((-10) << 16)
#define HIGH_OVER_IMMEDIATE	(14 << 16)
#define HIGH_OVER_AVERAGE	(10 << 16)
#define HIGH_OVER_IMMEDIATE	(14 << 16)


/* Implementation... */
static int create_cpu_loop(int cpu)
{
	int chip = cpu / 2;
	int core = cpu & 1;
	struct smu_sdbp_header *hdr;
	struct smu_sdbp_cpupiddata *piddata;
	struct wf_cpu_pid_param pid;
	struct wf_control *main_fan = cpu_fans[0];
	s32 tmax;
	int fmin;

	/* Get PID params from the appropriate SAT */
	hdr = smu_sat_get_sdb_partition(chip, 0xC8 + core, NULL);
	if (hdr == NULL) {
		printk(KERN_WARNING"windfarm: can't get CPU PID fan config\n");
		return -EINVAL;
	}
	piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];

	/* Get FVT params to get Tmax; if not found, assume default */
	hdr = smu_sat_get_sdb_partition(chip, 0xC4 + core, NULL);
	if (hdr) {
		struct smu_sdbp_fvt *fvt = (struct smu_sdbp_fvt *)&hdr[1];
		tmax = fvt->maxtemp << 16;
	} else
		tmax = 95 << 16;	/* default to 95 degrees C */

	/* We keep a global tmax for overtemp calculations */
	if (tmax < cpu_all_tmax)
		cpu_all_tmax = tmax;

	/*
	 * Darwin has a minimum fan speed of 1000 rpm for the 4-way and
	 * 515 for the 2-way.  That appears to be overkill, so for now,
	 * impose a minimum of 750 or 515.
	 */
	fmin = (nr_cores > 2) ? 750 : 515;

	/* Initialize PID loop */
	pid.interval = 1;	/* seconds */
	pid.history_len = piddata->history_len;
	pid.gd = piddata->gd;
	pid.gp = piddata->gp;
	pid.gr = piddata->gr / piddata->history_len;
	pid.pmaxadj = (piddata->max_power << 16) - (piddata->power_adj << 8);
	pid.ttarget = tmax - (piddata->target_temp_delta << 16);
	pid.tmax = tmax;
	pid.min = main_fan->ops->get_min(main_fan);
	pid.max = main_fan->ops->get_max(main_fan);
	if (pid.min < fmin)
		pid.min = fmin;

	wf_cpu_pid_init(&cpu_pid[cpu], &pid);
	return 0;
}

static void cpu_max_all_fans(void)
{
	int i;

	/* We max all CPU fans in case of a sensor error. We also do the
	 * cpufreq clamping now, even if it's supposedly done later by the
	 * generic code anyway, we do it earlier here to react faster
	 */
	if (cpufreq_clamp)
		wf_control_set_max(cpufreq_clamp);
	for (i = 0; i < NR_CPU_FANS; ++i)
		if (cpu_fans[i])
			wf_control_set_max(cpu_fans[i]);
}

static int cpu_check_overtemp(s32 temp)
{
	int new_state = 0;
	s32 t_avg, t_old;

	/* First check for immediate overtemps */
	if (temp >= (cpu_all_tmax + LOW_OVER_IMMEDIATE)) {
		new_state |= FAILURE_LOW_OVERTEMP;
		if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
			printk(KERN_ERR "windfarm: Overtemp due to immediate CPU"
			       " temperature !\n");
	}
	if (temp >= (cpu_all_tmax + HIGH_OVER_IMMEDIATE)) {
		new_state |= FAILURE_HIGH_OVERTEMP;
		if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
			printk(KERN_ERR "windfarm: Critical overtemp due to"
			       " immediate CPU temperature !\n");
	}

	/* We calculate a history of max temperatures and use that for the
	 * overtemp management
	 */
	t_old = cpu_thist[cpu_thist_pt];
	cpu_thist[cpu_thist_pt] = temp;
	cpu_thist_pt = (cpu_thist_pt + 1) % CPU_TEMP_HIST_SIZE;
	cpu_thist_total -= t_old;
	cpu_thist_total += temp;
	t_avg = cpu_thist_total / CPU_TEMP_HIST_SIZE;

	DBG_LOTS("t_avg = %d.%03d (out: %d.%03d, in: %d.%03d)\n",
		 FIX32TOPRINT(t_avg), FIX32TOPRINT(t_old), FIX32TOPRINT(temp));

	/* Now check for average overtemps */
	if (t_avg >= (cpu_all_tmax + LOW_OVER_AVERAGE)) {
		new_state |= FAILURE_LOW_OVERTEMP;
		if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
			printk(KERN_ERR "windfarm: Overtemp due to average CPU"
			       " temperature !\n");
	}
	if (t_avg >= (cpu_all_tmax + HIGH_OVER_AVERAGE)) {
		new_state |= FAILURE_HIGH_OVERTEMP;
		if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
			printk(KERN_ERR "windfarm: Critical overtemp due to"
			       " average CPU temperature !\n");
	}

	/* Now handle overtemp conditions. We don't currently use the windfarm
	 * overtemp handling core as it's not fully suited to the needs of those
	 * new machine. This will be fixed later.
	 */
	if (new_state) {
		/* High overtemp -> immediate shutdown */
		if (new_state & FAILURE_HIGH_OVERTEMP)
			machine_power_off();
		if ((failure_state & new_state) != new_state)
			cpu_max_all_fans();
		failure_state |= new_state;
	} else if ((failure_state & FAILURE_LOW_OVERTEMP) &&
		   (temp < (cpu_all_tmax + LOW_OVER_CLEAR))) {
		printk(KERN_ERR "windfarm: Overtemp condition cleared !\n");
		failure_state &= ~FAILURE_LOW_OVERTEMP;
	}

	return failure_state & (FAILURE_LOW_OVERTEMP | FAILURE_HIGH_OVERTEMP);
}

static void cpu_fans_tick(void)
{
	int err, cpu;
	s32 greatest_delta = 0;
	s32 temp, power, t_max = 0;
	int i, t, target = 0;
	struct wf_sensor *sr;
	struct wf_control *ct;
	struct wf_cpu_pid_state *sp;

	DBG_LOTS(KERN_DEBUG);
	for (cpu = 0; cpu < nr_cores; ++cpu) {
		/* Get CPU core temperature */
		sr = sens_cpu_temp[cpu];
		err = sr->ops->get_value(sr, &temp);
		if (err) {
			DBG("\n");
			printk(KERN_WARNING "windfarm: CPU %d temperature "
			       "sensor error %d\n", cpu, err);
			failure_state |= FAILURE_SENSOR;
			cpu_max_all_fans();
			return;
		}

		/* Keep track of highest temp */
		t_max = max(t_max, temp);

		/* Get CPU power */
		sr = sens_cpu_power[cpu];
		err = sr->ops->get_value(sr, &power);
		if (err) {
			DBG("\n");
			printk(KERN_WARNING "windfarm: CPU %d power "
			       "sensor error %d\n", cpu, err);
			failure_state |= FAILURE_SENSOR;
			cpu_max_all_fans();
			return;
		}

		/* Run PID */
		sp = &cpu_pid[cpu];
		t = wf_cpu_pid_run(sp, power, temp);

		if (cpu == 0 || sp->last_delta > greatest_delta) {
			greatest_delta = sp->last_delta;
			target = t;
		}
		DBG_LOTS("[%d] P=%d.%.3d T=%d.%.3d ",
		    cpu, FIX32TOPRINT(power), FIX32TOPRINT(temp));
	}
	DBG_LOTS("fans = %d, t_max = %d.%03d\n", target, FIX32TOPRINT(t_max));

	/* Darwin limits decrease to 20 per iteration */
	if (target < (cpu_last_target - 20))
		target = cpu_last_target - 20;
	cpu_last_target = target;
	for (cpu = 0; cpu < nr_cores; ++cpu)
		cpu_pid[cpu].target = target;

	/* Handle possible overtemps */
	if (cpu_check_overtemp(t_max))
		return;

	/* Set fans */
	for (i = 0; i < NR_CPU_FANS; ++i) {
		ct = cpu_fans[i];
		if (ct == NULL)
			continue;
		err = ct->ops->set_value(ct, target * cpu_fan_scale[i] / 100);
		if (err) {
			printk(KERN_WARNING "windfarm: fan %s reports "
			       "error %d\n", ct->name, err);
			failure_state |= FAILURE_FAN;
			break;
		}
	}
}

/* Backside/U4 fan */
static struct wf_pid_param backside_param = {
	.interval	= 5,
	.history_len	= 2,
	.gd		= 48 << 20,
	.gp		= 5 << 20,
	.gr		= 0,
	.itarget	= 64 << 16,
	.additive	= 1,
};

static void backside_fan_tick(void)
{
	s32 temp;
	int speed;
	int err;

	if (!backside_fan || !u4_temp)
		return;
	if (!backside_tick) {
		/* first time; initialize things */
		printk(KERN_INFO "windfarm: Backside control loop started.\n");
		backside_param.min = backside_fan->ops->get_min(backside_fan);
		backside_param.max = backside_fan->ops->get_max(backside_fan);
		wf_pid_init(&backside_pid, &backside_param);
		backside_tick = 1;
	}
	if (--backside_tick > 0)
		return;
	backside_tick = backside_pid.param.interval;

	err = u4_temp->ops->get_value(u4_temp, &temp);
	if (err) {
		printk(KERN_WARNING "windfarm: U4 temp sensor error %d\n",
		       err);
		failure_state |= FAILURE_SENSOR;
		wf_control_set_max(backside_fan);
		return;
	}
	speed = wf_pid_run(&backside_pid, temp);
	DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n",
		 FIX32TOPRINT(temp), speed);

	err = backside_fan->ops->set_value(backside_fan, speed);
	if (err) {
		printk(KERN_WARNING "windfarm: backside fan error %d\n", err);
		failure_state |= FAILURE_FAN;
	}
}

/* Drive bay fan */
static struct wf_pid_param drive_bay_prm = {
	.interval	= 5,
	.history_len	= 2,
	.gd		= 30 << 20,
	.gp		= 5 << 20,
	.gr		= 0,
	.itarget	= 40 << 16,
	.additive	= 1,
};

static void drive_bay_fan_tick(void)
{
	s32 temp;
	int speed;
	int err;

	if (!drive_bay_fan || !hd_temp)
		return;
	if (!drive_bay_tick) {
		/* first time; initialize things */
		printk(KERN_INFO "windfarm: Drive bay control loop started.\n");
		drive_bay_prm.min = drive_bay_fan->ops->get_min(drive_bay_fan);
		drive_bay_prm.max = drive_bay_fan->ops->get_max(drive_bay_fan);
		wf_pid_init(&drive_bay_pid, &drive_bay_prm);
		drive_bay_tick = 1;