* Re: [PATCH] powerpc: Better machine descriptions and kill magic numbers
From: Olof Johansson @ 2006-01-15 0:42 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list, linuxppc64-dev
In-Reply-To: <1137272686.4855.17.camel@localhost.localdomain>
On Sun, Jan 15, 2006 at 08:04:46AM +1100, Benjamin Herrenschmidt wrote:
>
> > Because of this, I suggest keeping the mach_ part in the syntax, i.e,
> > to use:
> >
> > machine_is(mach_powermac) instead, and not do preprocessor mangling of
> > the label name. The same would go for define_machine().
> >
> > It would seem to make some sense to keep the platform types looking
> > like defines (i.e. MACH_POWERMAC instead of mach_powermac) to keep it
> > consistent with the CPU and firmware feature testing, but the way it's
> > implemented that doesn't make much sense. That's a bit of a shame.
>
> I'm not sure about these ... I'm definitely not fan of going uppercase (and
> it makes no sense vs. the implementation as it's not macros). I also don't
Yeah, that's what I meant with doesn't make sense in this case. I was
just thinking out loud.
> get your problem with grep... the "mach_" construct is totally invisible,
> so people wouldn't grep for it, but for "powermac" alone.
>
> Or do you mean a grep on "powermac" might return too many things unrelated ?
>
> It should be easy enough in this case to grep for machine_is(powermac) instead
> then, after all, that's the only possible use...
One drawback is that source navigation tools like tags and cscope probably
won't find it, and the base strings are quite generic (powermac, cbe/cell,
etc). A stringbased grep will, sure.
> > In the probe loop, ppc_md is copied over for each probe, that seems
> > wasteful.
>
> I changed that from the old way indeed to allow the probe() function to
> override things in ppc_md.
>
> > Shouldn't the probe routines use and modify their own
> > machdep_calls instead of ppc_md, so the copying can be done only once,
> > after a match is found?
>
> I don't like modifying their own machdep calls because the name of the
> structure is hidden. In general, I prefer that things continue to only
> access ppc_md. and not their own machine structure that goes away. That
> means that the code "patching" it can be moved away etc... without
> special case instead of having a special case in probe() that has to
> reference the machine specific copy...
Ok.
> I doubt the memcpy per machine at boot will cause any kind of
> significant performance issue ...
Yeah, that's why I said it seemed wasteful, not that it'd be a
performance issue.
^ permalink raw reply
* [PATCH 001/001] subsystem: Themperature monitoring for ibook 2.2
From: Cedric Pradalier @ 2006-01-15 1:43 UTC (permalink / raw)
To: linuxppc-dev
From: Cedric Pradalier <cedric.pradalier@free.fr>
This driver provides some thermostat monitoring for ibook2,
equipped with a adm103x fan control chip. It also provides
and sysfs access to the adm103x fan control parameters. For
instance
#cat /sys/device/temperature/info?
T:51*C S:56*C R:10*C <-- sensor 0
T:48*C S:76*C R:10*C <-- sensor 1
#echo "56 10" > /sys/device/temperature/info0
make the fan starts at 56 degrees and accelerate
progressively till max at 66 degrees (56 + 10), on the
sensor 0.
The drivers also provides a ioctl access to the fan
parameters. This can be enabled/disabled at compile time.
major/minor number are 63 200, in the experimental range.
Developer's Certificate of Origin
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
Signed-off-by: Cedric Pradalier <cedric.pradalier@free.fr>
---
diff -Naurp -X linux-2.6.15/Documentation/dontdiff linux-2.6.15/Documentation/therm_adm103x.txt linux-2.6.15-adm/Documentation/therm_adm103x.txt
--- linux-2.6.15/Documentation/therm_adm103x.txt 1970-01-01 10:00:00.000000000 +1000
+++ linux-2.6.15-adm/Documentation/therm_adm103x.txt 2006-01-15 11:27:58.000000000 +1000
@@ -0,0 +1,94 @@
+
+Therm ADM103X Version 1.2.3
+--------------------------------------------------------------
+Authors...: Cedric Pradalier (cedric.pradalier@free.fr)
+
+
+Description
+--------------------------------------------------------------
+ This driver provides some thermostat monitoring for ibook2, equipped
+ with a adm1030 or adm1031 fan control chip. It also provides a sysfs
+ access to the adm103x fan control parameters. For instance
+ * #cat /sys/device/temperature/info?
+ * T:51*C S:56*C R:10*C <-- sensor 0
+ * T:48*C S:76*C R:10*C <-- sensor 1
+ * #echo "56 10" > /sys/device/temperature/info0
+ make the fan starts at 56 degrees and accelerate progressively till max
+ at 66 degrees (56 + 10), on the sensor 0.
+
+ Reading /sys/device/temperatures/minpwm0 shows the minimum speed of the fan.
+ Writing an integer value between 0 and 100 set this value. Low speed make
+ lower noise, but high speed lower temperature faster... Default is 33%.
+ * #echo "45" > /sys/device/temperature/minpwm0
+
+ You can also access the driver with ioctl commands. You need to include
+ /usr/include/linux/therm_adm103x.h in sources. Then, nearly all commands
+ expect a struct IOC_Adm103x argument.
+
+ typedef struct _IOC_Adm103x_ {
+ unsigned char id; /* sensor or fan id */
+ unsigned char mintemp; /* fan starting temp (deg)*/
+ unsigned char rangetemp; /* fan speeding range (deg)*/
+ unsigned char minpwm; /* min fan speed (percent)*/
+ signed long int millitemp; /* current temp (millideg)*/
+ unsigned char hysteresis;/* current histeresis (deg)*/
+ unsigned char reg; /* accessed register */
+ unsigned char value; /* value get/set into reg */
+ } IOC_Adm103x;
+
+ Nine commands are available :
+
+ ADM103X_IOC_GETTEMP
+ Argument : struct IOC_Adm103x * arg.
+ Action : put temperature in milli-degrees in arg->millitemp
+
+ ADM103X_IOC_GETLIMITS
+ Argument : struct IOC_Adm103x * arg.
+ Action : read fan starting temperature and fan speeding range and
+ write them in arg->mintemp and arg->rangetemp.
+ arg->id is used to select which sensor is concerned.
+
+ ADM103X_IOC_SETLIMITS
+ Argument : struct IOC_Adm103x * arg.
+ Action : set fan starting temperature and fan speeding range
+ from arg->mintemp and arg->rangetemp.
+ arg->id is used to select which sensor is concerned.
+
+ ADM103X_IOC_GETMINPWM
+ Argument : struct IOC_Adm103x * arg.
+ Action : read fan minimal speed and write it in arg->minpwm
+ arg->id is used to select which fan is concerned.
+
+ ADM103X_IOC_SETMINPWM
+ Argument : struct IOC_Adm103x * arg.
+ Action : set fan minimal speed and from arg->minpwm
+ arg->id is used to select which fan is concerned.
+
+ ADM103X_IOC_CHECK_IF_FAN_IS_NEEDED
+ Argument : None
+ Action : Compare current temperature to current limits minus hysteresis
+ and switch the fan off is needed.
+
+ ADM103X_IOC_SETHYSTERESIS
+ Argument : struct IOC_Adm103x * arg.
+ Action : Set hysteresis for the ADM103X_IOC_CHECK_IF_FAN_IS_NEEDED
+ command. Default value is 2 degrees.
+
+ ADM103X_IOC_GETHYSTERESIS
+ Argument : struct IOC_Adm103x * arg.
+ Action : Get hysteresis for the ADM103X_IOC_CHECK_IF_FAN_IS_NEEDED
+ command. Value is written in arg->hysteresis. arg->id is used
+ to select which sensor is concerned.
+
+ ADM103X_IOC_GETREGISTER
+ Argument : struct IOC_Adm103x * arg.
+ Action : Read a chip register. Register is selected with arg->reg and
+ written in arg->value.
+
+Copyright
+--------------------------------------------------------------
+From my point of view this is freeware - I don't know what
+others think but...
+Read the COPYING file for the complete GNU license.
+
+
diff -Naurp -X linux-2.6.15/Documentation/dontdiff linux-2.6.15/drivers/macintosh/Kconfig linux-2.6.15-adm/drivers/macintosh/Kconfig
--- linux-2.6.15/drivers/macintosh/Kconfig 2006-01-03 13:21:10.000000000 +1000
+++ linux-2.6.15-adm/drivers/macintosh/Kconfig 2006-01-12 21:26:22.000000000 +1000
@@ -154,6 +154,20 @@ config THERM_WINDTUNNEL
This driver provides some thermostat and fan control for the desktop
G4 "Windtunnel"
+config THERM_ADM103X
+ tristate "Support for thermal monitoring on ibook2"
+ depends on I2C && I2C_KEYWEST && PPC_PMAC && !PPC_PMAC64
+ help
+ This driver provides some thermostat monitoring for ibook2, equipped
+ with a adm103x fan control chip. It also provides and sysfs
+ access to the adm103x fan control parameters. For instance
+ #cat /sys/device/temperature/info?
+ T:51*C S:56*C R:10*C <-- sensor 0
+ T:48*C S:76*C R:10*C <-- sensor 1
+ #echo "56 10" > /sys/device/temperature/info0
+ make the fan starts at 56 degrees and accelerate progressively till max
+ at 66 degrees (56 + 10), on the sensor 0.
+
config THERM_ADT746X
tristate "Support for thermal mgmnt on laptops with ADT 746x chipset"
depends on I2C && I2C_KEYWEST && PPC_PMAC && !PPC_PMAC64
diff -Naurp -X linux-2.6.15/Documentation/dontdiff linux-2.6.15/drivers/macintosh/Makefile linux-2.6.15-adm/drivers/macintosh/Makefile
--- linux-2.6.15/drivers/macintosh/Makefile 2006-01-03 13:21:10.000000000 +1000
+++ linux-2.6.15-adm/drivers/macintosh/Makefile 2006-01-12 21:26:22.000000000 +1000
@@ -25,6 +25,7 @@ obj-$(CONFIG_ADB_MACIO) += macio-adb.o
obj-$(CONFIG_THERM_PM72) += therm_pm72.o
obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o
+obj-$(CONFIG_THERM_ADM103X) += therm_adm103x.o
obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o
obj-$(CONFIG_WINDFARM) += windfarm_core.o
obj-$(CONFIG_WINDFARM_PM81) += windfarm_smu_controls.o \
diff -Naurp -X linux-2.6.15/Documentation/dontdiff linux-2.6.15/drivers/macintosh/therm_adm103x.c linux-2.6.15-adm/drivers/macintosh/therm_adm103x.c
--- linux-2.6.15/drivers/macintosh/therm_adm103x.c 1970-01-01 10:00:00.000000000 +1000
+++ linux-2.6.15-adm/drivers/macintosh/therm_adm103x.c 2006-01-15 11:38:36.000000000 +1000
@@ -0,0 +1,895 @@
+/*
+ * Device driver for the i2c thermostat found on some iBook G3 (for intance
+ * ibook 2.2) : Namely the adm1030 or adm1031 chip.
+ *
+ * Copyright (C) 2003, 2004 Cedric Pradalier, Colin Leroy,
+ * Rasmus Rohde, Benjamin Herrenschmidt
+ *
+ * Documentation from
+ * http://www.analog.com/UploadedFiles/Data_Sheets/27250527ADM1031_a.pdf
+ * http://www.analog.com/UploadedFiles/Data_Sheets/878926113ADM1030_a.pdf
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/wait.h>
+#include <linux/miscdevice.h>
+#include <linux/syscalls.h>
+#include <linux/poll.h>
+#include <linux/devfs_fs_kernel.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sections.h>
+#include <asm/of_device.h>
+#include <asm/uaccess.h>
+
+
+#define ADM103X_USE_IOCTL
+
+
+#ifdef ADM103X_USE_IOCTL
+#include "linux/therm_adm103x.h"
+#endif
+
+
+/* Choose for display which caracter to use. The degree symbol is */
+/* not supported in all fonts. */
+#define DEGREE_CHARACTER '*'
+
+/* ADM Part */
+static uint8_t ADM_LIMIT_REG[3] = { 0x24, 0x25, 0x26 }; /* local, remote, remote */
+static uint8_t ADM_OFFSET_REG[3] = { 0x0D, 0x0E, 0x0F }; /* local, remote, remote */
+static uint8_t ADM_TEMP_REG[3] = { 0x0a, 0x0b, 0x0c }; /* local, remote, remote */
+#define ADM_RESOL_REG 0x06
+#define ADM_MINPWM_REG 0x22
+
+/* Regs marked with 1 are used on adm1030 and adm1031
+ * regs marked with 2 are used only on adm1031 */
+static uint8_t ADM_USED_REG[0x40] =
+{
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+/*0*/ 1,1,1,1,0,0,1,0,1,2,1,1,2,1,1,2,
+/*1*/ 1,2,0,0,1,1,1,0,1,1,1,0,2,2,2,0,
+/*2*/ 1,2,1,1,1,1,2,0,0,0,0,0,0,0,0,0,
+/*3*/ 0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1
+};
+
+#define DRIVER_NAME "adm103x"
+#define DRIVER_VERSION "2004 May 25"
+#define DRIVER_DESC "Driver for ADM103x thermostat in iBook G3"
+#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
+MODULE_AUTHOR ("Cedric Pradalier <cedric.pradalier@free.fr>");
+MODULE_DESCRIPTION (DRIVER_INFO);
+MODULE_LICENSE ("GPL");
+MODULE_VERSION ("1:2.3");
+
+static int debug = 0;
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "If != 0, activates debug output. If > 1, activates monitoring thread.");
+#define DPRINTK if (debug) printk
+
+
+#ifdef ADM103X_USE_IOCTL
+static int useioctl = 0;
+MODULE_PARM(useioctl, "i");
+MODULE_PARM_DESC(useioctl, "if non-zero, activates ioctl interface in /dev/adm103x (10,200)");
+#endif
+
+struct thermostat
+{
+ struct i2c_client clt;
+ uint8_t startfan[3];
+ uint8_t ranges[3];
+ uint8_t regtoread;
+ uint8_t hysteresis[3];
+};
+
+static enum { ADM1030, ADM1031 } therm_type;
+static int therm_bus, therm_address;
+static struct of_device *of_dev;
+static struct thermostat *thermostat;
+
+static pid_t monitor_thread_id;
+static int monitor_running;
+static struct completion monitor_task_compl;
+
+static int attach_one_thermostat (struct i2c_adapter *adapter, int addr,
+ int busno);
+
+/** Encoding of limit in adm103x registers :
+ * Bits 7:3 : min : fan starting temperature divided by 4
+ * Bits 2:0 : range :temperature at which fan motors is running at full speed
+ * |
+ * max| oooooooooooo
+ * | oo
+ *fan | ooo
+ *speed | ooo
+ * | ooo
+ * | oo
+ * min| o
+ * | o
+ * | o<----range--->| Temperature
+ * 0+ooooooooo--------------|--------> in Celcius
+ * min
+ *
+ * */
+static void
+adm_reg2minrange (uint8_t reg, uint8_t * min, uint8_t * range)
+{
+ *min = (reg & 0xF8) >> 1;
+ if ((reg&0x07)>4)
+ printk (KERN_INFO "adm103x: invalid limit temp register %02x\n", reg);
+ *range = 5 * (1<<(reg&0x07));
+}
+
+static uint8_t
+adm_minrange2reg (uint8_t min, uint8_t range)
+{
+ /* Rounding to nearest 4 degree */
+ if (min & 0x2) min += 4;
+ min = (min & 0xFC) << 1;
+ switch (range) {
+ case 5: return min;
+ case 10: return min | 0x01;
+ case 20: return min | 0x02;
+ case 40: return min | 0x03;
+ case 80: return min | 0x04;
+ default:
+ printk (KERN_INFO "adm103x: invalid limit temp range %d-%d\n", min, range);
+ return min;
+ }
+}
+
+static char *
+therm_name (int therm_type)
+{
+ switch (therm_type) {
+ case ADM1030:
+ return "adm1030";
+ case ADM1031:
+ return "adm1031";
+ }
+ return "unknown";
+}
+
+/*****************************************************
+ *
+ * I2C Bus Management
+ *
+ *****************************************************/
+static int
+write_reg (struct thermostat *th, int reg, uint8_t data)
+{
+ uint8_t tmp[2];
+ int rc;
+
+ tmp[0] = reg;
+ tmp[1] = data;
+ rc = i2c_master_send (&th->clt, (const char *) tmp, 2);
+ if (rc < 0)
+ return rc;
+ if (rc != 2)
+ return -ENODEV;
+ return 0;
+}
+
+static int
+read_reg (struct thermostat *th, int reg)
+{
+ uint8_t reg_addr, data;
+ int rc;
+
+ reg_addr = (uint8_t) reg;
+ rc = i2c_master_send (&th->clt, (const char*)®_addr, 1);
+ if (rc < 0)
+ return rc;
+ if (rc != 1)
+ return -ENODEV;
+ rc = i2c_master_recv (&th->clt, (char *) &data, 1);
+ if (rc < 0)
+ return rc;
+ return data;
+}
+
+static int
+attach_thermostat (struct i2c_adapter *adapter)
+{
+ unsigned long bus_no;
+ DPRINTK (KERN_INFO "adm103x: attach_thermostat\n");
+
+
+ if (strncmp (adapter->name, "uni-n", 5))
+ return -ENODEV;
+ bus_no = simple_strtoul (adapter->name + 6, NULL, 10);
+ if (bus_no != therm_bus)
+ return -ENODEV;
+ return attach_one_thermostat (adapter, therm_address, bus_no);
+}
+
+static int
+detach_thermostat (struct i2c_adapter *adapter)
+{
+ struct thermostat *th;
+ DPRINTK (KERN_INFO "adm103x: deattach_thermostat\n");
+
+ if (thermostat == NULL)
+ return 0;
+
+ th = thermostat;
+
+ if (debug>1) {
+ if (monitor_running) {
+ monitor_running = 0;
+ wait_for_completion (&monitor_task_compl);
+ }
+ }
+
+ i2c_detach_client (&th->clt);
+
+ thermostat = NULL;
+
+ kfree (th);
+
+ return 0;
+}
+
+static struct i2c_driver thermostat_driver = {
+ .name = "Apple Thermostat ADM103x",
+ .id = 0xDEAD1030,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = &attach_thermostat,
+ .detach_adapter = &detach_thermostat
+};
+
+static int
+monitor_task (void *arg)
+{
+ /**
+ * Monitoring thread. Only useful in debug. Otherwise, you can
+ * access chip state in sysfs
+ * **/
+ struct thermostat *th = arg;
+ uint8_t temps[3], start[3], range[3];
+ uint8_t nbsensor, reg;
+ int i;
+ start[2] = range[2] = temps[2] = 0;
+
+ lock_kernel ();
+ daemonize ("kfand");
+ unlock_kernel ();
+ strcpy (current->comm, "thermostat");
+ monitor_running = 1;
+
+ while (monitor_running) {
+ set_task_state (current, TASK_UNINTERRUPTIBLE);
+ schedule_timeout (1 * HZ);
+
+ /* Read status */
+ /* local : chip */
+ /* remote 1: CPU ? */
+ /* remote 2: GPU ? */
+ nbsensor = (therm_type == ADM1030) ? 2 : 3;
+ for (i = 0; i < nbsensor; i++) {
+ temps[i] = read_reg (th, ADM_TEMP_REG[i]);
+ reg = read_reg (th, ADM_LIMIT_REG[i]);
+ adm_reg2minrange (reg, &start[i], &range[i]);
+ }
+
+ printk (KERN_INFO "adm103x: Temperature infos: %d,%d,%d%cC\n",
+ temps[0], temps[1], temps[2],DEGREE_CHARACTER);
+ printk (KERN_INFO "adm103x: FanCtrl infos: %d,%d,%d%cC\n",
+ start[0], start[1], start[2],DEGREE_CHARACTER);
+ printk (KERN_INFO "adm103x: FanCtrl infos: %d,%d,%d%cC\n",
+ range[0], range[1], range[2],DEGREE_CHARACTER);
+ }
+
+ complete_and_exit (&monitor_task_compl, 0);
+ return 0;
+}
+
+
+static int attach_one_thermostat (struct i2c_adapter *adapter, int addr, int busno)
+{
+ struct thermostat *th;
+ int rc;
+ int i;
+ uint8_t reg;
+
+ DPRINTK (KERN_INFO "adm103x: attach_one_thermostat\n");
+ if (thermostat)
+ return 0;
+ th = (struct thermostat *) kmalloc (sizeof (struct thermostat), GFP_KERNEL);
+ if (!th)
+ return -ENOMEM;
+ memset (th, 0, sizeof (*th));
+ th->clt.addr = addr;
+ th->clt.adapter = adapter;
+ th->clt.driver = &thermostat_driver;
+ /*th->clt.id = 0xDEAD1030;*/
+ strcpy (th->clt.name, "thermostat");
+
+ rc = read_reg (th, 0);
+ if (rc < 0) {
+ printk (KERN_ERR
+ "adm103x: Thermostat failed to read config from bus %d !\n",
+ busno);
+ kfree (th);
+ return -ENODEV;
+ }
+
+ printk (KERN_INFO "adm103x: %s initializing\n", therm_name (therm_type));
+
+ /* Initializing thermostat structure from chip registers */
+ for (i = 0; i < ((therm_type == ADM1030) ? 2 : 3); i++) {
+ uint8_t min, range, off;
+ reg = read_reg (th, ADM_LIMIT_REG[i]);
+ off = read_reg (th, ADM_OFFSET_REG[i]);
+ adm_reg2minrange (reg, &min, &range);
+ printk (KERN_INFO "adm103x: %s initializing %d:%d+%d%cC\n",
+ therm_name (therm_type), i,
+ (off&0x80)?(min+(off&0x0F)):(min-(off&0x0F)), range,
+ DEGREE_CHARACTER);
+ th->startfan[i] = min;
+ th->ranges[i] = range;
+ th->hysteresis[i] = 2;
+ }
+ th->regtoread = 0;
+ /* activate automatic control and set analog speed input */
+ reg = read_reg (th, 0x00);
+ write_reg (th, 0x00, reg | 0x84);
+
+ thermostat = th;
+
+ if (i2c_attach_client (&th->clt)) {
+ printk ("adm103x: Thermostat failed to attach client !\n");
+ thermostat = NULL;
+ kfree (th);
+ return -ENODEV;
+ }
+
+ if (debug > 1) {
+ /* In debug we launch a monitoring thread which output
+ * chip state in syslog */
+ init_completion (&monitor_task_compl);
+
+ monitor_thread_id = kernel_thread (monitor_task, th,
+ SIGCHLD | CLONE_KERNEL);
+ }
+
+ return 0;
+}
+
+
+/*****************************************************
+ *
+ * ADM103X Data Manipulation
+ *
+ *****************************************************/
+
+
+
+static int set_limit (struct thermostat *th, int i, int min, int range)
+{
+ int error;
+ uint8_t offset = min % 4;
+ uint8_t limit = adm_minrange2reg ((offset==0)?min:(min-offset+4), range);
+ th->startfan[i] = min;
+ th->ranges[i] = range;
+ printk (KERN_INFO "adm103x: Setting FanCtrl infos: %d : %d+%d%cC\n",
+ i, th->startfan[i], th->ranges[i],DEGREE_CHARACTER);
+ error = write_reg (th, ADM_OFFSET_REG[i], (offset==0)?0x00:(4-offset));
+ if (error) return error;
+ error = write_reg (th, ADM_LIMIT_REG[i], limit);
+ return error;
+}
+
+static int get_limit (struct thermostat *th, int i, uint8_t * min, uint8_t * range)
+{
+ uint8_t lim;
+ uint8_t o = read_reg(th, ADM_OFFSET_REG[i]);
+ uint8_t l = read_reg(th, ADM_LIMIT_REG[i]);
+ adm_reg2minrange(l,&lim,range);
+ *min = (o&0x80)?(lim+(o&0x0F)):(lim-(o&0x0F));
+ return 0;
+}
+
+static int get_temp(struct thermostat * th, int i, int32_t * millitemp)
+{
+ uint16_t resol=0;
+ uint8_t o = read_reg(th, ADM_OFFSET_REG[i]);
+ uint8_t t = read_reg(th, ADM_TEMP_REG[i]);
+ uint8_t p = read_reg(th, ADM_RESOL_REG);
+ switch(i){
+ case 0: resol = ((((uint16_t)p)&0xC0)>>6)*250; break;
+ case 1: resol = (((uint16_t)p)&0x07)*125; break;
+ case 2: resol = ((((uint16_t)p)&0x38)>>3)*125; break;
+ }
+ t = (o&0x80)?(t+(o&0x0F)):(t-(o&0x0F));
+ *millitemp = (((int32_t)t)*1000)+resol;
+ return 0;
+}
+
+static uint8_t show_minPWM(struct thermostat * th, uint8_t index)
+{
+ static uint8_t s[16]={0,7,14,20, 27,33,40,47, 53,60,67,73, 80,87,93,100};
+ uint8_t minpwm = read_reg(th, ADM_MINPWM_REG);
+ uint8_t val=0;
+ switch (index) {
+ case 0 : val = s[minpwm&0x0F]; break;
+ case 1 : val = s[(minpwm&0xF0)>>4]; break;
+ }
+ return val;
+}
+
+static int set_minPWM(struct thermostat * th, int newpwm, uint8_t index)
+{
+ static uint8_t s[16]={0,7,14,20, 27,33,40,47, 53,60,67,73, 80,87,93,100};
+ uint8_t i,minpwm;
+ int d;
+ for (i=0;i<16;i++) {
+ d=s[i]-newpwm;
+ if ((d<=3)&&(d>-3))
+ break;
+ }
+ minpwm = read_reg(th, ADM_MINPWM_REG);
+ switch(index) {
+ case 0 : minpwm = (minpwm&0xF0) | i; break;
+ case 1 : minpwm = (minpwm&0x0F) | (i<<4); break;
+ }
+ return write_reg(th,ADM_MINPWM_REG,minpwm);
+}
+
+#ifdef ADM103X_USE_IOCTL
+static int checkIfFanIsNeeded(struct thermostat * th)
+{
+ int i,nbsensors;
+ uint8_t lim,rge;
+ int32_t millitemp;
+ uint8_t fanIsNeeded = 0;
+ nbsensors = (therm_type==ADM1030)?2:3;
+ DPRINTK (KERN_INFO "adm103x: check if fan is needed \n");
+ for (i=0;i<nbsensors;i++) {
+ get_limit(th,i,&lim,&rge);
+ get_temp(th,i,&millitemp);
+ DPRINTK (KERN_INFO "adm103x: sensor %d : %d.%d <? %d - %d \n",i,
+ millitemp/1000, millitemp%1000, lim,th->hysteresis[i] );
+ if (millitemp > 1000*((int32_t)lim - th->hysteresis[i]))
+ fanIsNeeded = 1;
+ }
+ if (!fanIsNeeded) {
+ uint8_t lim[3],rge[3];
+ DPRINTK (KERN_INFO "adm103x: fan is not needed \n");
+ for (i=0;i<nbsensors;i++) {
+ /* The following hack stop the fan is no-longer needed. */
+ /* Hard coded adm1030/1 hysteresis is 5 degrees. */
+ get_limit(th,i,&lim[i],&rge[i]);
+ set_limit(th,i,lim[i]+6,rge[i]);
+ }
+ set_task_state (current, TASK_UNINTERRUPTIBLE);
+ schedule_timeout (1 * HZ);
+ for (i=0;i<nbsensors;i++) {
+ set_limit(th,i,lim[i],rge[i]);
+ }
+ }
+ else
+ {
+ DPRINTK (KERN_INFO "adm103x: fan is needed \n");
+ }
+ return 0;
+}
+#endif
+
+
+/*****************************************************
+ *
+ * SYSFS Access
+ *
+ *****************************************************/
+
+
+/*
+ * Now, unfortunately, sysfs doesn't give us a nice void * we could
+ * pass around to the attribute functions, so we don't really have
+ * choice but implement a bunch of them...
+ *
+ */
+#define BUILD_SHOWPWM_FUNC(index) \
+static ssize_t show_minPWM##index(struct device *dev, struct device_attribute *attr, char *buf)\
+{ uint8_t minpwm = 0; \
+ minpwm = show_minPWM(thermostat,index); \
+ return sprintf(buf, "%3d%%\n", minpwm); }
+
+#define BUILD_SETPWM_FUNC(index) \
+static ssize_t set_minPWM##index(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)\
+{ \
+ int newpwm; \
+ if (sscanf (buf, "%d", &newpwm) != 1)\
+ return -EINVAL;\
+ if ((newpwm < 0) || (newpwm > 100))\
+ return -EINVAL;\
+ set_minPWM(thermostat,newpwm,index); \
+ return count; \
+}
+
+
+static ssize_t show_regtoread(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%02X\n", thermostat->regtoread);
+}
+
+static ssize_t show_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ uint8_t reg = 0;
+ reg = read_reg(thermostat, thermostat->regtoread);
+ return sprintf(buf, "%02X\n", reg);
+}
+
+static ssize_t set_regtoread(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned int r2r;
+ thermostat->regtoread=0;
+ if (sscanf (buf, "%X", &r2r) != 1)
+ return -EINVAL;
+ if ((r2r > 0x3F)||(ADM_USED_REG[r2r]==0)){
+ printk (KERN_INFO
+ "adm103x: invalid register %02X \n", r2r);
+ return -EINVAL;
+ }
+
+ if ((therm_type==ADM1030)&&(ADM_USED_REG[r2r]==2)) {
+ printk (KERN_INFO
+ "adm103x: invalid register %02X on device adm1030\n", r2r);
+ return -EINVAL;
+ }
+ DPRINTK (KERN_INFO "adm103x: register to read : %02X \n", r2r);
+ thermostat->regtoread=r2r;
+ return count;
+}
+
+
+
+#define BUILD_SHOW_FUNC(index) \
+static ssize_t show_info##index(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ uint8_t lim,rge; int32_t millitemp; \
+ get_limit(thermostat,index,&lim,&rge); \
+ get_temp(thermostat,index,&millitemp); \
+ return sprintf(buf, "T:%d.%03u%cC S:%d%cC R:%d%cC H:%d%cC\n", \
+ millitemp/1000, millitemp%1000, DEGREE_CHARACTER, \
+ lim, DEGREE_CHARACTER, \
+ rge, DEGREE_CHARACTER, \
+ thermostat->hysteresis[index],DEGREE_CHARACTER); \
+}
+
+#define BUILD_SET_FUNC(index) \
+static ssize_t set_info##index(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+ int start,range,hyst,narg; \
+ narg = sscanf (buf, " %u %u %u", &start, &range, &hyst); \
+ if ((narg != 2) && (narg != 3))return -EINVAL; \
+ if (narg == 2) hyst = 2; \
+ if (start > 124) return -EINVAL; \
+ if ((range!=5)&&(range!=10)&&(range!=20)&&(range!=40)) \
+ return -EINVAL; \
+ if ((hyst < 0) || (hyst > 100)) hyst = 2; \
+ set_limit(thermostat,index,start,range); \
+ thermostat->hysteresis[index] = hyst; \
+ return count; \
+}
+
+
+BUILD_SHOWPWM_FUNC (0)
+BUILD_SETPWM_FUNC (0)
+BUILD_SHOWPWM_FUNC (1)
+BUILD_SETPWM_FUNC (1)
+
+BUILD_SHOW_FUNC (0)
+BUILD_SET_FUNC (0)
+BUILD_SHOW_FUNC (1)
+BUILD_SET_FUNC (1)
+BUILD_SHOW_FUNC (2)
+BUILD_SET_FUNC (2)
+
+static DEVICE_ATTR (info0, S_IRUGO | S_IWUSR, show_info0, set_info0);
+static DEVICE_ATTR (info1, S_IRUGO | S_IWUSR, show_info1, set_info1);
+static DEVICE_ATTR (info2, S_IRUGO | S_IWUSR, show_info2, set_info2);
+static DEVICE_ATTR (minpwm0, S_IRUGO | S_IWUSR, show_minPWM0, set_minPWM0);
+static DEVICE_ATTR (minpwm1, S_IRUGO | S_IWUSR, show_minPWM1, set_minPWM1);
+static DEVICE_ATTR (regtoread, S_IRUGO | S_IWOTH , show_regtoread, set_regtoread);
+static DEVICE_ATTR (register, S_IRUGO | S_IWUSR , show_reg, NULL);
+
+/*****************************************************
+ *
+ * IOCTL Access
+ *
+ *****************************************************/
+#ifdef ADM103X_USE_IOCTL
+static int adm103x_open(struct inode *inode, struct file *file)
+{
+ file->private_data = 0;
+ return 0;
+}
+
+static int adm103x_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int adm103x_ioctl(struct inode * inode, struct file *filp,
+ u_int cmd, u_long arg)
+{
+ int error = 0;
+ IOC_Adm103x data;
+
+ switch (cmd) {
+ case ADM103X_IOC_SETLIMITS:
+ /* arg : struct {?id, ?tmin, ?trange} */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (copy_from_user(&data,(void*)arg,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ if (data.id >= 3) return -EINVAL;
+ if ((data.id >= 2) && (therm_type != ADM1031)) return -EINVAL;
+ if (data.mintemp > 124)
+ return -EINVAL;
+ if ((data.rangetemp!=5)&&(data.rangetemp!=10)&&
+ (data.rangetemp!=20)&&(data.rangetemp!=40))
+ return -EINVAL;
+ set_limit(thermostat,data.id,data.mintemp,data.rangetemp);
+ return 0;
+ case ADM103X_IOC_GETLIMITS:
+ /* arg : struct {?id, !tmin, !trange} */
+ if (copy_from_user(&data,(void*)arg,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ if (data.id >= 3) return -EINVAL;
+ if ((data.id >= 2) && (therm_type != ADM1031)) return -EINVAL;
+ {
+ uint8_t mt,rt;
+ get_limit(thermostat,data.id,&mt,&rt);
+ data.mintemp = mt;
+ data.rangetemp = rt;
+ }
+ if (copy_to_user((void*)arg,&data,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ return 0;
+ case ADM103X_IOC_GETTEMP:
+ /* arg : struct {?id, !temp} */
+ if (copy_from_user(&data,(void*)arg,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ if (data.id >= 3) return -EINVAL;
+ if ((data.id >= 2) && (therm_type != ADM1031)) return -EINVAL;
+ {
+ int32_t millitemp;
+ get_temp(thermostat,data.id,&millitemp);
+ data.millitemp = millitemp;
+ }
+ if (copy_to_user((void*)arg,&data,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ return 0;
+ case ADM103X_IOC_SETMINPWM:
+ /* arg : struct {?id, ?minpwm} */
+ if (copy_from_user(&data,(void*)arg,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (data.id >= 2) return -EINVAL;
+ if ((data.id >= 1) && (therm_type != ADM1031)) return -EINVAL;
+ if (data.minpwm > 100)
+ return -EINVAL;
+ set_minPWM(thermostat,data.minpwm,data.id);
+ return 0;
+ case ADM103X_IOC_GETMINPWM:
+ /* arg : struct {?id, !minpwm} */
+ if (copy_from_user(&data,(void*)arg,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ if (data.id >= 2) return -EINVAL;
+ if ((data.id >= 1) && (therm_type != ADM1031)) return -EINVAL;
+ data.minpwm = show_minPWM(thermostat,data.id);
+ if (copy_to_user((void*)arg,&data,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ return 0;
+ case ADM103X_IOC_CHECK_IF_FAN_IS_NEEDED:
+ /* arg : void */
+ error = checkIfFanIsNeeded(thermostat);
+ return error;
+ case ADM103X_IOC_GETHYSTERESIS:
+ /* arg : struct {?id, !hysteresis} */
+ if (copy_from_user(&data,(void*)arg,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ if (data.id >= 3) return -EINVAL;
+ if ((data.id >= 2) && (therm_type != ADM1031)) return -EINVAL;
+ data.hysteresis = thermostat->hysteresis[data.id];
+ if (copy_to_user((void*)arg,&data,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ return 0;
+ case ADM103X_IOC_SETHYSTERESIS:
+ /* arg : struct {?id, ?hysteresis} */
+ if (copy_from_user(&data,(void*)arg,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (data.id >= 3) return -EINVAL;
+ if ((data.id >= 2) && (therm_type != ADM1031)) return -EINVAL;
+ thermostat->hysteresis[data.id] = data.hysteresis;
+ return 0;
+ case ADM103X_IOC_GETREGISTER:
+ /* arg : struct {?id, ?register, !value} */
+ if (copy_from_user(&data,(void*)arg,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ if ((data.reg > 0x3F)||(ADM_USED_REG[data.reg]==0)){
+ printk (KERN_INFO "adm103x: invalid register %02X \n", data.reg);
+ return -EINVAL;
+ }
+ if ((therm_type==ADM1030)&&(ADM_USED_REG[data.reg]==2)) {
+ printk (KERN_INFO "adm103x: invalid register %02X on device adm1030\n", data.reg);
+ return -EINVAL;
+ }
+ data.value = read_reg(thermostat, data.reg);
+ if (copy_to_user((void*)arg,&data,sizeof(IOC_Adm103x)))
+ return -EFAULT;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+
+static ssize_t adm103x_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return -EINVAL;
+}
+
+static ssize_t adm103x_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return -EINVAL;
+}
+
+static unsigned int adm103x_fpoll(struct file *filp, poll_table *wait)
+{
+ return -EINVAL;
+}
+
+static struct file_operations adm103x_device_fops = {
+ .read = adm103x_read,
+ .write = adm103x_write,
+ .poll = adm103x_fpoll,
+ .ioctl = adm103x_ioctl,
+ .open = adm103x_open,
+ .release = adm103x_release,
+};
+
+
+#endif
+
+/*****************************************************
+ *
+ * Module management
+ *
+ *****************************************************/
+
+
+static int __init
+thermostat_init (void)
+{
+ int error;
+ struct device_node *np;
+ uint32_t *prop;
+
+
+ /* Currently, we only deal with the iBook G3, rev 2.2
+ */
+ np = of_find_node_by_name (NULL, "fan");
+ if (!np)
+ return -ENODEV;
+ if (device_is_compatible (np, "adm1030")) {
+ therm_type = ADM1030;
+ } else if (device_is_compatible (np, "adm1031")) {
+ therm_type = ADM1031;
+ }
+ else
+ return -ENODEV;
+
+ prop = (uint32_t *) get_property (np, "reg", NULL);
+ if (!prop)
+ return -ENODEV;
+ therm_bus = ((*prop) >> 8) & 0x0f;
+ therm_address = ((*prop) & 0xff) >> 1;
+
+ printk (KERN_INFO "adm103x: Thermostat bus: %d, address: 0x%02x\n",
+ therm_bus, therm_address);
+
+#ifndef CONFIG_I2C_KEYWEST
+ request_module ("i2c-keywest");
+#endif
+
+#ifdef ADM103X_USE_IOCTL
+ if (useioctl) {
+ /*
+ * * try to register device major number against driver entry points.
+ * */
+ if (register_chrdev(ADM103X_MAJOR,DRIVER_NAME,&adm103x_device_fops)) {
+ if (devfs_mk_cdev(MKDEV(ADM103X_MAJOR, ADM103X_MINOR) ,
+ S_IFCHR | S_IRUSR | S_IWUSR, DRIVER_NAME)!=0) {
+ printk(KERN_ERR "adm103x: cannot create device.\n");
+ useioctl = 0;
+ }
+ printk(KERN_ERR "adm103x: cannot register major %d device.\n",ADM103X_MAJOR);
+ useioctl = 0;
+ } else
+ printk(KERN_INFO "adm103x: device registered.\n");
+ }
+#endif
+ of_dev = of_platform_device_create (np, "temperatures",NULL);
+
+ if (of_dev == NULL) {
+ printk (KERN_ERR "Can't register temperatures device !\n");
+ return -ENODEV;
+ }
+
+ device_create_file (&of_dev->dev, &dev_attr_register);
+ device_create_file (&of_dev->dev, &dev_attr_regtoread);
+ device_create_file (&of_dev->dev, &dev_attr_info0);
+ device_create_file (&of_dev->dev, &dev_attr_info1);
+ device_create_file (&of_dev->dev, &dev_attr_minpwm0);
+ if (therm_type == ADM1031) {
+ device_create_file (&of_dev->dev, &dev_attr_minpwm1);
+ device_create_file (&of_dev->dev, &dev_attr_info2);
+ }
+
+ error = i2c_add_driver (&thermostat_driver);
+
+ DPRINTK(KERN_INFO "Driver initialized %d\n",error);
+
+ return error;
+}
+
+static void __exit
+thermostat_exit (void)
+{
+ if (of_dev) {
+ device_remove_file (&of_dev->dev, &dev_attr_register);
+ device_remove_file (&of_dev->dev, &dev_attr_regtoread);
+ device_remove_file (&of_dev->dev, &dev_attr_info0);
+ device_remove_file (&of_dev->dev, &dev_attr_info1);
+ device_remove_file (&of_dev->dev, &dev_attr_minpwm0);
+ if (therm_type == ADM1031) {
+ device_remove_file (&of_dev->dev, &dev_attr_minpwm1);
+ device_remove_file (&of_dev->dev, &dev_attr_info2);
+ }
+
+ of_device_unregister (of_dev);
+ }
+#ifdef ADM103X_USE_IOCTL
+ if (useioctl) {
+ devfs_remove(DRIVER_NAME);
+ if (unregister_chrdev(ADM103X_MAJOR,DRIVER_NAME)<0)
+ printk(KERN_ERR "adm103x: cannot deregister %d device.\n",ADM103X_MAJOR);
+ else
+ printk(KERN_INFO "adm103x: driver deregistered.\n");
+ }
+#endif
+ i2c_del_driver (&thermostat_driver);
+}
+
+module_init (thermostat_init);
+module_exit (thermostat_exit);
+
+
+
+
+
diff -Naurp -X linux-2.6.15/Documentation/dontdiff linux-2.6.15/include/linux/therm_adm103x.h linux-2.6.15-adm/include/linux/therm_adm103x.h
--- linux-2.6.15/include/linux/therm_adm103x.h 1970-01-01 10:00:00.000000000 +1000
+++ linux-2.6.15-adm/include/linux/therm_adm103x.h 2006-01-12 21:27:51.000000000 +1000
@@ -0,0 +1,30 @@
+#ifndef THERM_ADM103X_H
+#define THERM_ADM103X_H
+
+#define ADM103X_MINOR 200
+#define ADM103X_MAJOR 63 // Experimental
+
+typedef struct _IOC_Adm103x_ {
+ unsigned char id; /* sensor or fan id */
+ unsigned char mintemp; /* fan starting temp (deg)*/
+ unsigned char rangetemp; /* fan speeding range (deg)*/
+ unsigned char minpwm; /* min fan speed (percent)*/
+ signed long int millitemp; /* current temp (millideg)*/
+ unsigned char hysteresis;/* current histeresis (deg)*/
+ unsigned char reg; /* accessed register */
+ unsigned char value; /* value get/set into reg */
+} IOC_Adm103x;
+
+#define ADM103X_IOC_GETTEMP 1
+#define ADM103X_IOC_GETLIMITS 2
+#define ADM103X_IOC_SETLIMITS 3
+#define ADM103X_IOC_SETMINPWM 4
+#define ADM103X_IOC_GETMINPWM 5
+#define ADM103X_IOC_CHECK_IF_FAN_IS_NEEDED 6
+#define ADM103X_IOC_SETHYSTERESIS 7
+#define ADM103X_IOC_GETHYSTERESIS 8
+#define ADM103X_IOC_GETREGISTER 9
+
+
+
+#endif // THERM_ADM103X_H
--
Cedric
^ permalink raw reply
* Re: powerpc.git tree
From: Stephen Rothwell @ 2006-01-15 5:53 UTC (permalink / raw)
To: will schmidt; +Cc: linuxppc-dev, linuxppc64-dev
In-Reply-To: <43C55852.2060703@vnet.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 646 bytes --]
Hi Will,
On Wed, 11 Jan 2006 13:11:14 -0600 will schmidt <will_schmidt@vnet.ibm.com> wrote:
>
> Paul Mackerras wrote:
> >
> > That means that anyone who is following the powerpc.git tree by doing
> > pulls periodically will need to reset their tree too. Otherwise each
> > pull will do an unnecessary merge.
>
> By reset, do you mean to delete the local tree and pull a fresh one, or something fancier?
I just did a "git fetch -f powerpc" where my .git/remotes/powerpc points
at the powerpc.git tree on kernel.org.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: powerpc.git tree
From: Paul Mackerras @ 2006-01-15 6:07 UTC (permalink / raw)
To: will schmidt; +Cc: linuxppc-dev, linuxppc64-dev
In-Reply-To: <43C55852.2060703@vnet.ibm.com>
will schmidt writes:
> Paul Mackerras wrote:
> >
> > That means that anyone who is following the powerpc.git tree by doing
> > pulls periodically will need to reset their tree too. Otherwise each
> > pull will do an unnecessary merge.
>
> Hi Paul,
>
> By reset, do you mean to delete the local tree and pull a fresh
> one, or something fancier?
The powerpc.git tree is now identical to Linus' tree as of a day or so
ago. There are several ways you can reset your tree:
- make a fresh clone of Linus' tree, and make its .git/remotes/powerpc
point at the powerpc.git tree on kernel.org, or
- do "git fetch -f powerpc" (substitute whatever remote name you use
for the powerpc.git tree) (according to Stephen Rothwell), or
- do a pull as you would normally do, then throw away the merge and
the extra objects by doing:
git reset --hard FETCH_HEAD
git prune
- or you can delete the local tree and do a fresh clone.
I will start putting stuff in powerpc.git in the next day or so.
Paul.
^ permalink raw reply
* Re: [PATCH] powerpc: Add FSL SOC library and setup code
From: Olof Johansson @ 2006-01-15 7:15 UTC (permalink / raw)
To: Eugene Surovegin; +Cc: Kumar Gala, linuxppc-embedded, linuxppc-dev
In-Reply-To: <20060114234754.GB29766@gate.ebshome.net>
On Sat, Jan 14, 2006 at 03:47:54PM -0800, Eugene Surovegin wrote:
> On Sat, Jan 14, 2006 at 01:21:58PM -0600, Olof Johansson wrote:
> > > +
> > > +static phys_addr_t immrbase = -1;
> >
> > What does immr mean? Maybe a short comment would be good.
>
> IMHO, this is not needed because _everybody_ who is working
> with these chips know what IMMR means. And there cannot be _any_
> confusion about it. Let's not add useless comments.
I haven't been exposed much yet to embedded 32-bit PPC, I thought at
first that it was something chip-specific, not an architected feature
common across the families. I agree, it doesn't really need further
explanation in this case.
-Olof
^ permalink raw reply
* Re: [PATCH] powerpc: Add FSL SOC library and setup code
From: Kumar Gala @ 2006-01-15 7:31 UTC (permalink / raw)
To: Olof Johansson; +Cc: Kumar Gala, linuxppc-embedded, linuxppc-dev
In-Reply-To: <20060115071533.GA932@pb15.lixom.net>
On Jan 15, 2006, at 1:15 AM, Olof Johansson wrote:
> On Sat, Jan 14, 2006 at 03:47:54PM -0800, Eugene Surovegin wrote:
>> On Sat, Jan 14, 2006 at 01:21:58PM -0600, Olof Johansson wrote:
>>>> +
>>>> +static phys_addr_t immrbase = -1;
>>>
>>> What does immr mean? Maybe a short comment would be good.
>>
>> IMHO, this is not needed because _everybody_ who is working
>> with these chips know what IMMR means. And there cannot be _any_
>> confusion about it. Let's not add useless comments.
>
> I haven't been exposed much yet to embedded 32-bit PPC, I thought at
> first that it was something chip-specific, not an architected feature
> common across the families. I agree, it doesn't really need further
> explanation in this case.
To be clear its a system level architecture feature on Freescale
SOCs. It goes by a few different names (immrbar, ccsrbar, eumbar),
but the purpose is the same.
- kumar
^ permalink raw reply
* Re: Problems starting /sbin/init
From: David H. Lynch Jr. @ 2006-01-15 9:13 UTC (permalink / raw)
To: srideep.devireddy; +Cc: linuxppc-embedded
In-Reply-To: <6AD9F6A5F6E096408F0B703773355A070E705B@CHN-SNR-MBX01.wipro.com>
srideep.devireddy@wipro.com wrote:
> Hello David ,
>
> I am bringing up Montavista Linux on mpc8272 custom board .But as we completed almost all the configurations and linux is booting well till the NFS or Ramdisk file system is mounted . then it hangs .. when i tried to debug i saw the /sbin/init in the init/main.c is not getting executed . i had printk and checked all the printks are executed but not the /sbin/init and the printks after the init is also executed .so this /sbin/init is not getting excecuting and i am not getting any messages .
>
> Thanks & Regards
> Srideep Reddy D
> Wipro Technologies
>
>
Srideep;
I was eventually able to resolve my problem. My serial console driver
was inadvertently using the physical address of the uart and not the
virtual address. When the TLB entry created in head_4xx.S for that
physical address eventually got overwritten - which coincidentally
occured after loading /init (or /bin/sh or ....) but prior to their
outputting anything.
It is possible but unlikely you are having a similar problem.
Regardless, you can isolate your problem further. You can sprinkle
prink's inside init/main.c to figure out exactly how far you are getting.
If you are actually getting to attempting to start /init, you can
change main.c to start the program of your choice instead of init.
I started with "Hello World" in ppc assmebler with no library dependencies.
You can enable SHOW_SYSCALLS and find out what system calls are
occuring immeditely prior to your system running off the rails.
And I am sure others may have even more and better ideas.
Dave
^ permalink raw reply
* Download Eldk4.0
From: Chinafeng @ 2006-01-15 9:48 UTC (permalink / raw)
To: Linuxppc-embedded
SGk6DQoNCiAgICAgICBXaHkgbm90IGRvd25sb2FkIGVsZGs0LjA/Pz8NCg0KICAgICAgIGZ0cCBo
YXMgc29tZSBlcnJvcnMgIHdoZW4gSSBkb3dubG9hZCBlbGRrNC4wICBieSBmdHAuLi4NCg0KICAg
ICAgIFNwZWVkIGlzIHZlcnkgdmVyeSAgc2xvdy4uLi4uDQoJDQogICAgICAgICAgICAgICAgICAg
ICBXSFk/DQqhoaGhoaGhoaGhoaGhoSAJCQkJDQoNCqGhoaGhoaGhoaGhoaGhoaENCqGhoaGhoaGh
oaGhoaGhoaFjaGluYWZlbmcyMDA4QDE2My5jb20NCqGhoaGhoaGhoaGhoaGhoaGhoaGhMjAwNi0w
MS0xNQ0K
^ permalink raw reply
* Re: PPC440EP/Yosemite PCI misbehavior
From: Stefan Roese @ 2006-01-15 9:21 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <43C88013.40800@ovro.caltech.edu>
Hi David,
On Saturday 14 January 2006 05:37, David Hawkins wrote:
> I'll go and play with the 440EP DMA controller and see if I can get
> that to burst to the PCI bus.
>
> > access to PCI I/O space causes a machine check exception.
>
> I still get this in 2.6.15, but Wolfgang Denx indicated that
> they'd tested PCI I/O pretty thoroughly, so I'm inclined to
> believe that its my driver that is at fault. I'll do a little
> more digging on that one.
I have to admit, that PCI I/O can't have worked until now on
Yosemite/Yellowstone. I just found a bug in
arch/ppc/platforms/4xx/yosemite.h:
-#define YOSEMITE_PCI_IO_BASE 0x00000000e0000000ULL
+#define YOSEMITE_PCI_IO_BASE 0x00000000e8000000ULL
Please give it a try and let me know if the problem is fixed.
Best regards,
Stefan
^ permalink raw reply
* Re: Download Eldk4.0
From: Wolfgang Denk @ 2006-01-15 14:39 UTC (permalink / raw)
To: Chinafeng; +Cc: Linuxppc-embedded
In-Reply-To: <43CA24BB.1EE448.29192>
In message <43CA24BB.1EE448.29192> you wrote:
> Why not download eldk4.0???
Because it's not released yet?
Best regards,
Wolfgang Denk
--
Software Engineering: Embedded and Realtime Systems, Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Business is like a wheelbarrow. Nothing ever happens until you start
pushing.
^ permalink raw reply
* How to check which CPU we are using? PPC?
From: jeanwelly @ 2006-01-15 15:07 UTC (permalink / raw)
To: Linuxppc-embedded
SG93IHRvIGNoZWNrIHdoaWNoIENQVSB3ZSBhcmUgdXNpbmc/IEFueSBtZXRob2RzPw0KDQoJDQpU
aGFua3MhDQoNCqGhoaGhoaGhoaGhoaGhoaFqZWFud2VsbHkNCqGhoaGhoaGhoaGhoaGhoaFqZWFu
d2VsbHlAMTI2LmNvbQ0KoaGhoaGhoaGhoaGhoaGhoaGhoaEyMDA2LTAxLTE1DQo=
^ permalink raw reply
* [PATCH] PPC32 CPM_UART: update to utilize the new TTY flip API
From: Vitaly Bordug @ 2006-01-15 15:44 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-embedded
This replaces old direct usage of tty->flip stuff with relative flip API
calls.
---
drivers/serial/cpm_uart/cpm_uart_core.c | 13 ++++---------
1 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index 16af562..5e25c2d 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -252,12 +252,9 @@ static void cpm_uart_int_rx(struct uart_
/* If we have not enough room in tty flip buffer, then we try
* later, which will be the next rx-interrupt or a timeout
*/
- if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE) {
- tty->flip.work.func((void *)tty);
- if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE) {
- printk(KERN_WARNING "TTY_DONT_FLIP set\n");
- return;
- }
+ if(tty_buffer_request_room(tty, i) < i) {
+ printk(KERN_WARNING "No room in flip buffer\n");
+ return;
}
/* get pointer */
@@ -276,9 +273,7 @@ static void cpm_uart_int_rx(struct uart_
continue;
error_return:
- *tty->flip.char_buf_ptr++ = ch;
- *tty->flip.flag_buf_ptr++ = flg;
- tty->flip.count++;
+ tty_insert_flip_char(tty, ch, flg);
} /* End while (i--) */
^ permalink raw reply related
* Re: [linux-usb-devel] Re: [2.6 patch] remove unused tmp_buf_sem's
From: Alan Cox @ 2006-01-15 15:46 UTC (permalink / raw)
To: Greg KH
Cc: akpm, Jes Sorensen, tony.luck, linux-ia64, linux-usb-devel,
linux-kernel, Adrian Bunk, linuxppc-dev, torvalds, R.E.Wolff
In-Reply-To: <20060114034903.GA23074@suse.de>
On Gwe, 2006-01-13 at 19:49 -0800, Greg KH wrote:
> On Sat, Jan 14, 2006 at 03:08:16AM +0100, Adrian Bunk wrote:
> > <-- snip -->
> >
> >
> > tmp_buf_sem sems to be a common name for something completely unused...
That would be correct. The old tty driver layer used to call ->write
from both kernel and user contexts according to a flag. Drivers then all
ended up with the same code copying it into a tmp buffer and using a
locking semaphore.
Linus took out that code and arranged that ->write always got a kernel
buffer so the remainders should indeed go.
Alan
^ permalink raw reply
* Re: How to check which CPU we are using? PPC?
From: Wolfgang Denk @ 2006-01-15 17:19 UTC (permalink / raw)
To: jeanwelly; +Cc: Linuxppc-embedded
In-Reply-To: <43CA7AF1.11609B.03655>
In message <43CA7AF1.11609B.03655> you wrote:
> SG93IHRvIGNoZWNrIHdoaWNoIENQVSB3ZSBhcmUgdXNpbmc/IEFueSBtZXRob2RzPw0KDQoJDQpU
> aGFua3MhDQoNCqGhoaGhoaGhoaGhoaGhoaFqZWFud2VsbHkNCqGhoaGhoaGhoaGhoaGhoaFqZWFu
> d2VsbHlAMTI2LmNvbQ0KoaGhoaGhoaGhoaGhoaGhoaGhoaEyMDA2LTAxLTE1DQpfX19fX19fX19f
> X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwpMaW51eHBwYy1lbWJlZGRlZCBt
> YWlsaW5nIGxpc3QKTGludXhwcGMtZW1iZWRkZWRAb3psYWJzLm9yZwpodHRwczovL296bGFicy5v
> cmcvbWFpbG1hbi9saXN0aW5mby9saW51eHBwYy1lbWJlZGRlZA==
Please fix your mailer. Don't use base64 encsding. Post plain text,
please.
> How to check which CPU we are using? Any methods?
Check the print on the processor? Check the documentation? Check the
schematics?
Best regards,
Wolfgang Denk
--
Software Engineering: Embedded and Realtime Systems, Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Use C++ to confuse your enemies; use C to produce stable code.
^ permalink raw reply
* Re: AGPGART driver for ArticiaS - ioremap() problem
From: Benjamin Herrenschmidt @ 2006-01-15 21:48 UTC (permalink / raw)
To: Gerhard Pircher; +Cc: linuxppc-dev, debian-powerpc
In-Reply-To: <19351.1137053713@www55.gmx.net>
> Please take a look at the end of my previous mail, where I included the
> debug messages of the driver and the driver code itself. The log shows that
> the physical address is mapped (IMHO) to the PCI memory range (>
> 0x0c0000000). Is this correct? Shouldn't it be mapped to the system memory
> address range?
I don't understand. I would need to now more about what the bridge
actually does to get any sense out of that.
> The aperture size is 4MB, page_order should be 1 and num_entries = 1024.
>
> Hope this helps!? :-)
>
> Thanks!
>
> Regards,
>
> Gerhard
>
> --
> DSL-Aktion wegen großer Nachfrage bis 28.2.2006 verlängert:
> GMX DSL-Flatrate 1 Jahr kostenlos* http://www.gmx.net/de/go/dsl
>
>
^ permalink raw reply
* Re: AGPGART driver for ArticiaS - ioremap() problem
From: Gerhard Pircher @ 2006-01-15 23:10 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, debian-powerpc
[-- Attachment #1: Type: text/plain, Size: 4215 bytes --]
> --- Ursprüngliche Nachricht ---
> Von: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> An: Gerhard Pircher <gerhard_pircher@gmx.net>
> Kopie: linuxppc-dev@ozlabs.org, debian-powerpc@lists.debian.org
> Betreff: Re: AGPGART driver for ArticiaS - ioremap() problem
> Datum: Mon, 16 Jan 2006 08:48:28 +1100
>
> I don't understand. I would need to now more about what
> the bridge actually does to get any sense out of that.
Thanks for answering! It's hard to explain for me what the code does, but I
will try.
I included a cleaned-up version of the AGPGART driver code for the ArticiaS
(AmigaOne/Pegasos1). As mentioned, the driver is based on the VIA AGPGART
driver and uses the agp_generic_create_gatt_table() and
agp_generic_free_gatt_table() functions (well, I copied and renamed this
functions to insert debug code).
Actually at least the bridge does everthing right until now (IMHO :-). The
bridge is detected and also the aperture size is read out correctly from the
registers. After that, the agp_backend_initialize() function in
drivers/cahr/agp/backend.c calls the create_gatt_table() function of the
driver (articias_create_gatt_table). Based on the detected aperture size and
its definitions, this function allocates pages for the GATT table
(alloc_gatt_pages). The function then tries to map this pages with
ioremap_nocache(virt_to_gatt(table, (PAGE_SIZE * (1 << page_order))). But
ioremap_nocache() cannot remap the pages, because the following code snipped
in __ioremap (arch/ppc/mm/pgtable.c) is trigged:
/*
* Don't allow anybody to remap normal RAM that we're using.
* mem_init() sets high_memory so only do the check after that.
*/
if ( mem_init_done && (p < virt_to_phys(high_memory)) )
{
printk("__ioremap(): phys addr "PHYS_FMT" is RAM lr %p\n", p,
__builtin_return_address(0));
return NULL;
}
As it can be seen in the following log, the table address (0xde200000 ->
virt_to_gart(table) = 0x1e200000) is lower than the maximum amount of memory
0x20000000 (512MB) and therefore __ioremap() does not remap the pages.
Debuglog:
agpgart: [ARTICIAS] articias_fetch_size()
agpgart: [ARTICIAS] * non masked temp = 0x6
agpgart: [ARTICIAS] * aperature size loop index #0
agpgart: [ARTICIAS] * values[0].size_value = 1
agpgart: [ARTICIAS] * aperature size loop index #1
agpgart: [ARTICIAS] * values[1].size_value = 2
agpgart: [ARTICIAS] * aperature size loop index #2
agpgart: [ARTICIAS] * values[2].size_value = 3
agpgart: [ARTICIAS] * aperature size loop index #3
agpgart: [ARTICIAS] * values[3].size_value = 4
agpgart: [ARTICIAS] * aperature size loop index #4
agpgart: [ARTICIAS] * values[4].size_value = 5
agpgart: [ARTICIAS] * aperature size loop index #5
agpgart: [ARTICIAS] * values[5].size_value = 6
agpgart: [ARTICIAS] * masked temp = 0x6
agpgart: [ARTICIAS] * values[5].size = 128 (128MB aperture size)
agpgart: [ARTICIAS] * current_size->size = 128
agpgart: [ARTICIAS] * current_size->page_order = 5
agpgart: [ARTICIAS] * current_size->num_entries = 32768
agpgart: [ARTICIAS] * current_size->size_value = 6
agpgart: [ARTICIAS] articias_create_gatt_table()
agpgart: [ARTICIAS] * table address = 0xde200000
agpgart: [ARTICIAS] * table end address = 0xde21ffff
agpgart: [ARTICIAS] * page = 0xc09c4400
agpgart: [ARTICIAS] * gatt_table_real = 0xde200000
agpgart: [ARTICIAS] * agp_gatt_table = 0xde200000
agpgart: [ARTICIAS] * virt_to_gart(table) = 0x1e200000
__ioremap() debug: addr = 0x1e200000
__ioremap() debug: phys addr = 0x1e200000
__ioremap() debug: size = 0x20000
__ioremap() debug: Highmem check
__ioremap() debug: high_memory = 0xe0000000
__ioremap() debug: virt_to_phys(high_memory) = 0x20000000
__ioremap(): phys addr 1e200000 is RAM lr c000f210
agpgart: [ARTICIAS] * gatt_table_real = 0x0
agpgart: unable to get memory for graphics translation table.
agpgart: agp_backend_initialize() failed.
agpgart-articias: probe of 0000:00:00.0 failed with error -12
How can I achieve it that ioremap_nocache() can map the pages or that
alloc_gatt_pages() returns valid pages for the GATT table?
Thanks again!
Regards,
Gerhard
--
Lust, ein paar Euro nebenbei zu verdienen? Ohne Kosten, ohne Risiko!
Satte Provisionen für GMX Partner: http://www.gmx.net/de/go/partner
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: articias-agp.c --]
[-- Type: text/x-csrc; name="articias-agp.c", Size: 11419 bytes --]
/*
* ArticiaS AGPGART routines.
*/
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/pci.h>
#include <asm/pci-bridge.h>
#include <linux/init.h>
#include <linux/agp_backend.h>
#include "agp.h"
static struct pci_device_id agp_articias_pci_table[];
__u32 *agp_gatt_table;
#define ARTICIAS_AGP_EN 0x49 /* bit 0 -> AGP enable */
#define ARTICIAS_GART_EN 0x58 /* bit 6 -> GART enable */
#define ARTICIAS_APSIZE 0x59 /* bits 2:0 set size */
#define ARTICIAS_APBASE 0x59 /* TLB address Base [31:12]*/
#define ARTICIAS_GATTBASE 0x10 /* GART base address register */
#define ARTICIAS_TLB_BASE 0x5A /* bits 16:31 of TLB base address */
#define ARTICIAS_GATT_MASK 0xFFFFF000
#define ARTICIAS_SIZE_MASK 0x07 /* Mask aperture size bits. */
static int articias_fetch_size(void)
{
int i;
u8 temp;
struct aper_size_info_8 *values;
values = A_SIZE_8(agp_bridge->driver->aperture_sizes);
pci_read_config_byte(agp_bridge->dev, ARTICIAS_APSIZE, &temp);
/* Mask the GART/Aperture size selection bits. */
temp = temp & ARTICIAS_SIZE_MASK;
for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
if (temp == values[i].size_value) {
agp_bridge->previous_size =
agp_bridge->current_size = (void *) (values + i);
/* Geri: Was <(void *) (values)> before, but that
* didn't make sense to me!? Otherwise it would always
* point to the same value!
*/
agp_bridge->aperture_size_idx = i;
return values[i].size;
}
}
printk(KERN_ERR PFX "Unknown aperture size from AGP bridge (0x%x)\n", temp);
return 0;
}
static int articias_configure(void)
{
u32 temp = 0;
u16 shift16 = 0;
u8 shift8 = 0;
struct aper_size_info_8 *current_size;
/* Get current aperture size */
current_size = A_SIZE_8(agp_bridge->current_size);
temp = (u32) agp_bridge->gatt_table_real;
/* Get upper word from dword. Note that the ArticiaS should have 20
* bits for the TLB base address. Otherwise the PCI write config code
* for the aperture size below doesn't make sense!?
*/
shift16 = (u16) (temp>>16);
pci_write_config_word(agp_bridge->dev, ARTICIAS_TLB_BASE, shift16);
/* Get the byte 1 from dword and mask it out with the aperture size. */
shift8 = (u8) (temp>>8);
shift8 &= ~(ARTICIAS_SIZE_MASK);
shift8 |= current_size->size_value;
pci_write_config_byte(agp_bridge->dev, ARTICIAS_APBASE, shift8);
/* Get address to map too */
pci_read_config_dword(agp_bridge->dev, ARTICIAS_GATTBASE, (void *)&temp);
temp = temp & ARTICIAS_GATT_MASK;
agp_bridge->gart_bus_addr = temp;
/* GART control register */
/* Enable GART and bus concurrency */
pci_write_config_byte(agp_bridge->dev, ARTICIAS_GART_EN, 0x41);
/* Enable AGP operation */
pci_write_config_byte(agp_bridge->dev, ARTICIAS_AGP_EN, 0x01);
return 0;
}
int articias_create_gatt_table(struct agp_bridge_data *bridge)
{
char *table;
char *table_end;
int size;
int page_order;
int num_entries;
int i;
void *temp;
struct page *page;
/* The generic routines can't handle 2 level gatt's */
if (bridge->driver->size_type == LVL2_APER_SIZE)
return -EINVAL;
table = NULL;
i = bridge->aperture_size_idx;
temp = bridge->current_size;
size = page_order = num_entries = 0;
if (bridge->driver->size_type != FIXED_APER_SIZE) {
do {
switch (bridge->driver->size_type) {
case U8_APER_SIZE:
size = A_SIZE_8(temp)->size;
page_order =
A_SIZE_8(temp)->page_order;
num_entries =
A_SIZE_8(temp)->num_entries;
break;
case U16_APER_SIZE:
size = A_SIZE_16(temp)->size;
page_order = A_SIZE_16(temp)->page_order;
num_entries = A_SIZE_16(temp)->num_entries;
break;
case U32_APER_SIZE:
size = A_SIZE_32(temp)->size;
page_order = A_SIZE_32(temp)->page_order;
num_entries = A_SIZE_32(temp)->num_entries;
break;
/* This case will never really happen. */
case FIXED_APER_SIZE:
case LVL2_APER_SIZE:
default:
size = page_order = num_entries = 0;
break;
}
table = alloc_gatt_pages(page_order);
if (table == NULL) {
i++;
switch (bridge->driver->size_type) {
case U8_APER_SIZE:
bridge->current_size = A_IDX8(bridge);
break;
case U16_APER_SIZE:
bridge->current_size = A_IDX16(bridge);
break;
case U32_APER_SIZE:
bridge->current_size = A_IDX32(bridge);
break;
/* This case will never really happen. */
case FIXED_APER_SIZE:
case LVL2_APER_SIZE:
default:
bridge->current_size =
bridge->current_size;
break;
}
temp = bridge->current_size;
} else {
bridge->aperture_size_idx = i;
}
} while (!table && (i < bridge->driver->num_aperture_sizes));
} else {
size = ((struct aper_size_info_fixed *) temp)->size;
page_order = ((struct aper_size_info_fixed *) temp)->page_order;
num_entries = ((struct aper_size_info_fixed *) temp)->num_entries;
table = alloc_gatt_pages(page_order);
}
if (table == NULL)
return -ENOMEM;
table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
SetPageReserved(page);
bridge->gatt_table_real = (u32 *) table;
agp_gatt_table = (void *) table;
bridge->driver->cache_flush();
bridge->gatt_table = ioremap_nocache(virt_to_gart(table),
(PAGE_SIZE * (1 << page_order)));
bridge->driver->cache_flush();
if (bridge->gatt_table == NULL) {
for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
ClearPageReserved(page);
free_gatt_pages(table, page_order);
return -ENOMEM;
}
bridge->gatt_bus_addr = virt_to_gart(bridge->gatt_table_real);
/* AK: bogus, should encode addresses > 4GB */
for (i = 0; i < num_entries; i++) {
writel(bridge->scratch_page, bridge->gatt_table+i);
readl(bridge->gatt_table+i); /* PCI Posting. */
}
return 0;
}
int articias_free_gatt_table(struct agp_bridge_data *bridge)
{
int page_order;
char *table, *table_end;
void *temp;
struct page *page;
temp = bridge->current_size;
switch (bridge->driver->size_type) {
case U8_APER_SIZE:
page_order = A_SIZE_8(temp)->page_order;
break;
case U16_APER_SIZE:
page_order = A_SIZE_16(temp)->page_order;
break;
case U32_APER_SIZE:
page_order = A_SIZE_32(temp)->page_order;
break;
case FIXED_APER_SIZE:
page_order = A_SIZE_FIX(temp)->page_order;
break;
case LVL2_APER_SIZE:
/* The generic routines can't deal with 2 level gatt's */
return -EINVAL;
break;
default:
page_order = 0;
break;
}
/* Do not worry about freeing memory, because if this is
* called, then all agp memory is deallocated and removed
* from the table. */
iounmap(bridge->gatt_table);
table = (char *) bridge->gatt_table_real;
table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
ClearPageReserved(page);
free_gatt_pages(bridge->gatt_table_real, page_order);
agp_gatt_table = NULL;
bridge->gatt_table = NULL;
bridge->gatt_table_real = NULL;
bridge->gatt_bus_addr = 0;
return 0;
}
#endif
static void articias_cleanup(void)
{
struct aper_size_info_8 *previous_size;
previous_size = A_SIZE_8(agp_bridge->previous_size);
pci_write_config_byte(agp_bridge->dev, ARTICIAS_APSIZE,
previous_size->size_value);
}
static void articias_tlbflush(struct agp_memory *mem)
{
u8 temp;
pci_read_config_byte(agp_bridge->dev, ARTICIAS_GART_EN, &temp);
pci_write_config_byte(agp_bridge->dev, ARTICIAS_GART_EN, (temp | 0x80));
pci_write_config_byte(agp_bridge->dev, ARTICIAS_GART_EN, (temp & 0x7F));
return;
}
static struct aper_size_info_8 articias_generic_sizes[7] =
{
/* size, num_entries, page_order, size_value */
{4, 1024, 1, 1},
{8, 2048, 1, 2},
{16, 4096, 2, 3},
{32, 8192, 3, 4},
{64, 16384, 4, 5},
{128, 32768, 5, 6},
{256, 65536, 6, 7},
};
static struct agp_bridge_driver articias_driver = {
.owner = THIS_MODULE,
.aperture_sizes = articias_generic_sizes,
.size_type = U8_APER_SIZE,
.num_aperture_sizes = 7,
.configure = articias_configure,
.fetch_size = articias_fetch_size,
.cleanup = articias_cleanup,
.tlb_flush = articias_tlbflush,
.mask_memory = agp_generic_mask_memory,
.masks = NULL,
.agp_enable = agp_generic_enable,
.cache_flush = global_cache_flush,
.create_gatt_table = articias_create_gatt_table,
.free_gatt_table = articias_free_gatt_table,
.insert_memory = agp_generic_insert_memory,
.remove_memory = agp_generic_remove_memory,
.alloc_by_type = agp_generic_alloc_by_type,
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
};
static struct agp_device_ids articias_agp_device_ids[] __devinitdata =
{
{
.device_id = PCI_DEVICE_ID_MAI_ARTICIAS,
.chipset_name = "ArticiaS",
},
{ }, /* dummy final entry, always present */
};
static int __devinit agp_articias_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct agp_device_ids *devs = articias_agp_device_ids;
struct agp_bridge_data *bridge;
int j = 0;
u8 cap_ptr;
cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
if (!cap_ptr)
return -ENODEV;
j = ent - agp_articias_pci_table;
printk (KERN_INFO PFX "Detected MAI %s chipset\n", devs[j].chipset_name);
bridge = agp_alloc_bridge();
if (!bridge)
return -ENOMEM;
#ifdef ARTICIAS_DEBUG
/* Geri: Print all AGP relevant registers of the ArticiaS. */
articias_print_agp_register(pdev);
#endif
bridge->dev = pdev;
bridge->capndx = cap_ptr;
bridge->driver = &articias_driver;
/* Set a higher aperture size! Now it should be 128MB. */
pci_write_config_byte(pdev, ARTICIAS_APSIZE, 0x06);
return agp_add_bridge(bridge);
}
static void __devexit agp_articias_remove(struct pci_dev *pdev)
{
struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
agp_remove_bridge(bridge);
agp_put_bridge(bridge);
}
#ifdef CONFIG_PM
static int agp_articias_suspend(struct pci_dev *pdev, pm_message_t state)
{
pci_save_state (pdev);
pci_set_power_state (pdev, PCI_D3hot);
return 0;
}
static int agp_articias_resume(struct pci_dev *pdev)
{
struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
pci_set_power_state (pdev, PCI_D0);
pci_restore_state(pdev);
if (bridge->driver == &articias_driver)
return articias_configure();
return 0;
}
#endif /* CONFIG_PM */
/* must be the same order as name table above */
static struct pci_device_id agp_articias_pci_table[] = {
#define ID(x) \
{ \
.class = (PCI_CLASS_BRIDGE_HOST << 8), \
.class_mask = ~0, \
.vendor = PCI_VENDOR_ID_MAI, \
.device = x, \
.subvendor = PCI_ANY_ID, \
.subdevice = PCI_ANY_ID, \
}
ID(PCI_DEVICE_ID_MAI_ARTICIAS),
{ }
};
MODULE_DEVICE_TABLE(pci, agp_articias_pci_table);
static struct pci_driver agp_articias_pci_driver = {
.name = "agpgart-articias",
.id_table = agp_articias_pci_table,
.probe = agp_articias_probe,
.remove = agp_articias_remove,
#ifdef CONFIG_PM
.suspend = agp_articias_suspend,
.resume = agp_articias_resume,
#endif
};
static int __init agp_articias_init(void)
{
if (agp_off)
{
return -EINVAL;
}
return pci_register_driver(&agp_articias_pci_driver);
}
static void __exit agp_articias_cleanup(void)
{
pci_unregister_driver(&agp_articias_pci_driver);
}
module_init(agp_articias_init);
module_exit(agp_articias_cleanup);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>");
^ permalink raw reply
* Re: AGPGART driver for ArticiaS - ioremap() problem
From: Benjamin Herrenschmidt @ 2006-01-15 23:25 UTC (permalink / raw)
To: Gerhard Pircher; +Cc: linuxppc-dev, debian-powerpc
In-Reply-To: <13039.1137366615@www38.gmx.net>
> Actually at least the bridge does everthing right until now (IMHO :-). The
> bridge is detected and also the aperture size is read out correctly from the
> registers. After that, the agp_backend_initialize() function in
> drivers/cahr/agp/backend.c calls the create_gatt_table() function of the
> driver (articias_create_gatt_table). Based on the detected aperture size and
> its definitions, this function allocates pages for the GATT table
> (alloc_gatt_pages). The function then tries to map this pages with
> ioremap_nocache(virt_to_gatt(table, (PAGE_SIZE * (1 << page_order))). But
> ioremap_nocache() cannot remap the pages, because the following code snipped
> in __ioremap (arch/ppc/mm/pgtable.c) is trigged:
Yes, you are not allowed to ioremap RAM on ppc at least not with
CONFIG_6xx. You should leave it cacheable and use explicit cache flush
like the UniNorth driver.
> As it can be seen in the following log, the table address (0xde200000 ->
> virt_to_gart(table) = 0x1e200000) is lower than the maximum amount of memory
> 0x20000000 (512MB) and therefore __ioremap() does not remap the pages.
^ permalink raw reply
* Re: [PATCH 00/10] Xilinx Virtex-* updates
From: David H. Lynch Jr. @ 2006-01-16 5:27 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <87u0c8q9f4.fsf@48ers.dk>
I merged your ml403 changes into my copy of the kernel.org linux-2.6 git
repository, and I am working to adapt my Pico E12-Virtex-4 port to work
with them. I have mostly succeeded, but I am still working through a few
rough spots.
Peter Korsgaard wrote:
>>>>>>"grant" == grant likely <grant.likely@secretlab.ca> writes:
>
>
> grant> Here's a repost of my Xilinx ML300 and ML403 patches with a few
> grant> cleanups, a bit of patch reordering, and rebased to 2.6.15.
>
> Nice, ..
>
> grant> I've tested on an ML403
> grant> Can someone test on an ML300? (I no longer have one)
>
> Works fine here on a ML300-alike board.
>
^ permalink raw reply
* Re: [PATCH 00/10] Xilinx Virtex-* updates
From: Grant Likely @ 2006-01-16 7:30 UTC (permalink / raw)
To: David H. Lynch Jr.; +Cc: linuxppc-embedded
In-Reply-To: <43CB2EAB.7080307@dlasys.net>
David H. Lynch Jr. wrote:
> I merged your ml403 changes into my copy of the kernel.org linux-2.6 git
> repository, and I am working to adapt my Pico E12-Virtex-4 port to work
> with them. I have mostly succeeded, but I am still working through a few
> rough spots.
Cool, thanks! Let me know about anything you've got issues with.
It looks like I missed the merge window for 2.6.16, so this stuff
probably won't get in until 2.6.17. OTOH, that give us some time to get
the weeds out.
Cheers,
g.
--
Grant Likely, B.Sc. P.Eng.
Secret Lab Technologies Ltd.
(403) 663-0761
^ permalink raw reply
* Re: AGPGART driver for ArticiaS - ioremap() problem
From: Gerhard Pircher @ 2006-01-16 8:11 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, debian-powerpc
In-Reply-To: <1137367531.4823.42.camel@localhost.localdomain>
> --- Ursprüngliche Nachricht ---
> Von: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> An: Gerhard Pircher <gerhard_pircher@gmx.net>
> Kopie: linuxppc-dev@ozlabs.org, debian-powerpc@lists.debian.org
> Betreff: Re: AGPGART driver for ArticiaS - ioremap() problem
> Datum: Mon, 16 Jan 2006 10:25:31 +1100
>
> >Actually at least the bridge does everthing right until now (IMHO :-).
> >The bridge is detected and also the aperture size is read out correctly
> >from the registers. After that, the agp_backend_initialize() function in
> >drivers/cahr/agp/backend.c calls the create_gatt_table() function of the
> >driver (articias_create_gatt_table). Based on the detected aperture size
> >and its definitions, this function allocates pages for the GATT table
> >(alloc_gatt_pages). The function then tries to map this pages with
> >ioremap_nocache(virt_to_gatt(table, (PAGE_SIZE * (1 << page_order))).
> >But ioremap_nocache() cannot remap the pages, because the following code
> >snipped in __ioremap (arch/ppc/mm/pgtable.c) is trigged:
>
> Yes, you are not allowed to ioremap RAM on ppc at least not with
> CONFIG_6xx. You should leave it cacheable and use explicit cache flush
> like the UniNorth driver.
Ah, okay. So at least the approach to use the Uninorth code was a step in
the right direction. But that requires changes in the DRI and X server code,
right?
Thanks!
regards,
Gerhard
--
10 GB Mailbox, 100 FreeSMS/Monat http://www.gmx.net/de/go/topmail
+++ GMX - die erste Adresse für Mail, Message, More +++
^ permalink raw reply
* [PATCH] fix spider compilation
From: Olaf Hering @ 2006-01-16 12:11 UTC (permalink / raw)
To: Arnd Bergmann, linuxppc-dev
linux-2.6.15/drivers/net/spider_net.c: In function `spider_net_set_txdescr_cmdstat':
linux-2.6.15/drivers/net/spider_net.c:890: error: `IPPROTO_TCP' undeclared (first use in this function)
linux-2.6.15/drivers/net/spider_net.c:890: error: (Each undeclared identifier is reported only once
linux-2.6.15/drivers/net/spider_net.c:890: error: for each function it appears in.)
linux-2.6.15/drivers/net/spider_net.c:892: error: `IPPROTO_UDP' undeclared (first use in this function)
Signed-off-by: Olaf Hering <olh@suse.de>
drivers/net/spider_net.c | 1 +
1 files changed, 1 insertion(+)
Index: linux-2.6.15/drivers/net/spider_net.c
===================================================================
--- linux-2.6.15.orig/drivers/net/spider_net.c
+++ linux-2.6.15/drivers/net/spider_net.c
@@ -33,6 +33,7 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/ip.h>
+#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/mii.h>
#include <linux/module.h>
--
short story of a lazy sysadmin:
alias appserv=wotan
^ permalink raw reply
* [PATCH] drop linuxppc64-dev
From: Olaf Hering @ 2006-01-16 12:12 UTC (permalink / raw)
To: Paul Mackeras, linuxppc-dev
Everything is merged into arch/powerpc now.
Stop cross-posting.
Signed-off-by: Olaf Hering <olh@suse.de>
Documentation/powerpc/hvcs.txt | 2 +-
MAINTAINERS | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
Index: linux-2.6.15-olh/Documentation/powerpc/hvcs.txt
===================================================================
--- linux-2.6.15-olh.orig/Documentation/powerpc/hvcs.txt
+++ linux-2.6.15-olh/Documentation/powerpc/hvcs.txt
@@ -560,7 +560,7 @@ The proper channel for reporting bugs is
distribution company that provided your OS or by posting issues to the
ppc64 development mailing list at:
-linuxppc64-dev@lists.linuxppc.org
+linuxppc-dev@ozlabs.org
This request is to provide a documented and searchable public exchange
of the problems and solutions surrounding this driver for the benefit of
Index: linux-2.6.15-olh/MAINTAINERS
===================================================================
--- linux-2.6.15-olh.orig/MAINTAINERS
+++ linux-2.6.15-olh/MAINTAINERS
@@ -527,7 +527,7 @@ S: Supported
BROADBAND PROCESSOR ARCHITECTURE
P: Arnd Bergmann
M: arnd@arndb.de
-L: linuxppc64-dev@ozlabs.org
+L: linuxppc-dev@ozlabs.org
W: http://linuxppc64.org
S: Supported
@@ -1606,7 +1606,7 @@ P: Anton Blanchard
M: anton@samba.org
M: anton@au.ibm.com
W: http://linuxppc64.org
-L: linuxppc64-dev@ozlabs.org
+L: linuxppc-dev@ozlabs.org
S: Supported
LINUX SECURITY MODULE (LSM) FRAMEWORK
--
short story of a lazy sysadmin:
alias appserv=wotan
^ permalink raw reply
* Re: [PATCH] drop linuxppc64-dev
From: Hollis Blanchard @ 2006-01-16 15:52 UTC (permalink / raw)
To: Olaf Hering; +Cc: linuxppc-dev
In-Reply-To: <20060116121244.GB7171@suse.de>
On Mon, 2006-01-16 at 13:12 +0100, Olaf Hering wrote:
> Everything is merged into arch/powerpc now.
> Stop cross-posting.
> --- linux-2.6.15-olh.orig/MAINTAINERS
> +++ linux-2.6.15-olh/MAINTAINERS
> @@ -527,7 +527,7 @@ S: Supported
> BROADBAND PROCESSOR ARCHITECTURE
> P: Arnd Bergmann
> M: arnd@arndb.de
> -L: linuxppc64-dev@ozlabs.org
> +L: linuxppc-dev@ozlabs.org
> W: http://linuxppc64.org
> S: Supported
Are you suggesting that nobody should ever use linuxppc64-dev now? If
so, patching MAINTAINERS doesn't seem like the right way to enforce
that.
Do we want to think about merging the mailing lists? Both seem fairly
high-volume right now (compare
http://ozlabs.org/pipermail/linuxppc64-dev/ and
http://ozlabs.org/pipermail/linuxppc-dev/). linuxppc-embedded is
separate. There are certainly lots of emails and patches that are common
to both 32- and 64-bit, though...
The subscriber lists don't overlap 100%, but the difference might be
small enough not to matter to many people.
-Hollis
^ permalink raw reply
* Re: [PATCH] fix spider compilation
From: Arnd Bergmann @ 2006-01-16 12:45 UTC (permalink / raw)
To: Olaf Hering; +Cc: linuxppc-dev, jgarzik, Jens Osterkamp
In-Reply-To: <20060116121157.GA7171@suse.de>
Olaf Hering <olh@suse.de> wrote on 01/16/2006 01:11:57 PM:
>
> linux-2.6.15/drivers/net/spider_net.c: In function
> `spider_net_set_txdescr_cmdstat':
> linux-2.6.15/drivers/net/spider_net.c:890: error: `IPPROTO_TCP'
> undeclared (first use in this function)
> linux-2.6.15/drivers/net/spider_net.c:890: error: (Each undeclared
> identifier is reported only once
> linux-2.6.15/drivers/net/spider_net.c:890: error: for each function
> it appears in.)
> linux-2.6.15/drivers/net/spider_net.c:892: error: `IPPROTO_UDP'
> undeclared (first use in this function)
>
> Signed-off-by: Olaf Hering <olh@suse.de>
Thanks. I already submitted the same patch to Jeff Garzik,
but had a problem with a quilt bug that caused another patch
in the series to fail.
Jeff, did you get the '[RESEND 2]' patches for spidernet?
Sorry for messing this up twice before, but I'm pretty
sure that I fixed up the diff now and the contents are
somewhat important, at least the compile fix.
Arnd <><
> drivers/net/spider_net.c | 1 +
> 1 files changed, 1 insertion(+)
>
> Index: linux-2.6.15/drivers/net/spider_net.c
> ===================================================================
> --- linux-2.6.15.orig/drivers/net/spider_net.c
> +++ linux-2.6.15/drivers/net/spider_net.c
> @@ -33,6 +33,7 @@
> #include <linux/init.h>
> #include <linux/ioport.h>
> #include <linux/ip.h>
> +#include <linux/in.h>
> #include <linux/kernel.h>
> #include <linux/mii.h>
> #include <linux/module.h>
^ permalink raw reply
* Re: [PATCH] drop linuxppc64-dev
From: Olaf Hering @ 2006-01-16 16:30 UTC (permalink / raw)
To: Hollis Blanchard; +Cc: linuxppc-dev
In-Reply-To: <1137426731.22151.8.camel@localhost.localdomain>
On Mon, Jan 16, Hollis Blanchard wrote:
> Are you suggesting that nobody should ever use linuxppc64-dev now? If
> so, patching MAINTAINERS doesn't seem like the right way to enforce
> that.
It felt like a good starting point for this kind of discussion. :-)
--
short story of a lazy sysadmin:
alias appserv=wotan
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox