RE: [PATCH] thermal: Add msm tsens thermal sensor driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> -----Original Message-----
> From: Srinivas Kandagatla [mailto:srinivas.kandagatla@xxxxxxxxxx]
> Sent: Wednesday, January 28, 2015 10:06 PM
> To: Narendran Rajan; 'Narendran Rajan'; 'Zhang Rui'; 'Eduardo Valentin'
> Cc: 'Linux ARM MSM'; 'Linux PM'; 'Siddartha Mohanadoss'; 'Stephen Boyd'
> Subject: Re: [PATCH] thermal: Add msm tsens thermal sensor driver
> 
> 
> 
> On 27/01/15 22:31, Narendran Rajan wrote:
> >
> >> -----Original Message-----
> >> From: Srinivas Kandagatla [mailto:srinivas.kandagatla@xxxxxxxxxx]
> >> Sent: Monday, January 26, 2015 11:15 PM
> >> To: Narendran Rajan; Zhang Rui; Eduardo Valentin
> >> Cc: Linux ARM MSM; Linux PM; Siddartha Mohanadoss; Stephen Boyd
> >> Subject: Re: [PATCH] thermal: Add msm tsens thermal sensor driver
> >>
> >> Thankyou for sending the patch..
> >> here are some comments
> >>
> >
> > Thanks Srini for the detail review.
> >
> >> On 27/01/15 04:09, Narendran Rajan wrote:
> >> ...
> >>
> ...
> 
> >>
> >>> +#include <linux/io.h>
> >>> +#include <linux/mfd/syscon.h>
> >>> +
> >>> +/* Trips: from very hot to very cold */ enum tsens_trip_type {
> >>> +	TSENS_TRIP_STAGE3,
> >>> +	TSENS_TRIP_STAGE2,
> >>> +	TSENS_TRIP_STAGE1,
> >>> +	TSENS_TRIP_STAGE0,
> >>> +	TSENS_TRIP_NUM,
> >>> +};
> >> Do you need this if trips are actually coming from DT?
> >>
> >
> > Yes, for HW driven trip points. This feature still under development
> > in the core framework.
> > Please see https://patchwork.ozlabs.org/patch/364812/
> >
> > I should have added this under THERMAL_TSENS8960_HWTRIPS as rest of
> > the code.  Thx
> >
> >>> +
> >>> +#define TSENS_CAL_MDEGC				30000
> >>> +
> >>> +#define TSENS_MAX_SENSORS			11
> >>> +
> >>> +#define TSENS_8960_CONFIG_ADDR			0x3640
> >>> +#define TSENS_8960_CONFIG			0x9b
> >>> +#define TSENS_8960_CONFIG_MASK			0xf
> >>> +
> >>> +#define TSENS_CNTL_ADDR				0x3620
> >>> +#define TSENS_CNTL_RESUME_MASK			0xfffffff9
> >>> +#define TSENS_EN				BIT(0)
> >>> +#define TSENS_SW_RST				BIT(1)
> >>> +#define SENSOR0_EN				BIT(3)
> >>> +#define TSENS_MIN_STATUS_MASK			BIT(0)
> >>> +#define TSENS_LOWER_STATUS_CLR			BIT(1)
> >>> +#define TSENS_UPPER_STATUS_CLR			BIT(2)
> >>> +#define TSENS_MAX_STATUS_MASK			BIT(3)
> >>> +#define TSENS_MEASURE_PERIOD			1
> >>> +#define TSENS_8960_SLP_CLK_ENA			BIT(26)
> >>> +#define TSENS_8660_SLP_CLK_ENA			BIT(24)
> >>> +#define TSENS_8064_STATUS_CNTL			0x3660
> >>> +
> >>> +#define TSENS_THRESHOLD_ADDR			0x3624
> >>> +#define TSENS_THRESHOLD_MAX_CODE		0xff
> >>> +#define TSENS_THRESHOLD_MIN_CODE		0
> >>> +#define TSENS_THRESHOLD_MAX_LIMIT_SHIFT		24
> >>> +#define TSENS_THRESHOLD_MIN_LIMIT_SHIFT		16
> >>> +#define TSENS_THRESHOLD_UPPER_LIMIT_SHIFT	8
> >>> +#define TSENS_THRESHOLD_LOWER_LIMIT_SHIFT	0
> >>> +
> >>> +/* Initial temperature threshold values */
> >>> +#define TSENS_LOWER_LIMIT_TH			0x50
> >>> +#define TSENS_UPPER_LIMIT_TH			0xdf
> >>> +#define TSENS_MIN_LIMIT_TH			0x0
> >>> +#define TSENS_MAX_LIMIT_TH			0xff
> >>> +
> >>> +#define TSENS_S0_STATUS_ADDR			0x3628
> >>> +
> >>> +#define TSENS_INT_STATUS_ADDR			0x363c
> >>> +#define TSENS_LOWER_INT_MASK			BIT(1)
> >>> +#define TSENS_UPPER_INT_MASK			BIT(2)
> >>> +#define TSENS_MAX_INT_MASK			BIT(3)
> >>> +#define TSENS_TRDY_MASK				BIT(7)
> >>> +
> >>> +#define TSENS_SENSOR_SHIFT			16
> >>> +#define TSENS_REDUND_SHIFT			24
> >>> +#define TSENS_SENSOR0_SHIFT			3
> >>> +
> >>> +#define TSENS_8660_QFPROM_ADDR			0x00bc
> >> ?? Why is this offset defined in the driver, Is'nt this supposed to
> >> come
> > via dt?
> 
> ???

Correct, needs to be removed.

> >>> +#define TSENS_8660_CONFIG			1
> >>> +#define TSENS_8660_CONFIG_SHIFT			28
> >>> +#define TSENS_8660_CONFIG_MASK			(3 <<
> >> TSENS_8660_CONFIG_SHIFT)
> >>> +
> >>> +struct tsens_device;
> >>> +
> >>> +struct tsens_sensor {
> >>> +	struct thermal_zone_device	*tz_dev;
> >>> +	enum thermal_device_mode	mode;
> >>> +	unsigned int			sensor_num;
> >>> +	int				offset;
> >>> +	u32				slope;
> >>> +	struct tsens_device		*tmdev;
> >>> +	u32                             status;
> >>> +};
> >>> +
> >>> +struct tsens_device {
> >>> +	bool			prev_reading_avail;
> >>> +	unsigned int		num_sensors;
> >>> +	int			pm_tsens_thr_data;
> >>> +	int			pm_tsens_cntl;
> >>> +	unsigned int            calib_offset;
> >>> +	unsigned int            backup_calib_offset;
> >>> +	struct work_struct	tsens_work;
> >>> +	struct regmap		*map;
> >>> +	struct regmap_field	*status_field;
> >>> +	struct tsens_sensor	sensor[0];
> >>> +};
> >>> +
> >>> +static struct device *tsens_dev;
> >> Hmm.. I think you should remove this global variable and find a
> >> better way
> > to
> >> get hold of this.
> >>
> > Didn't find anything simple enough. A few other drivers seems to use
> > global as well. Will look around. If you have some quick tips let me
please
> know.
> 
> Add this to struct tsens_device.
> 

Thx, this would work.

> >
> ...
> 
> >>> +#ifdef THERMAL_TSENS8960_HWTRIPS
> >>
> >> Should this be a kernel config?
> >>    Or by default this should'nt be On?
> >> Do you need this code if the trip values are actually coming from DT?
> >>
> >
> > This feature need thermal core framework change as well.
> > This is not yet landed in upstream, but is used in some downstream
> > Kernels (like chrome kernel). Hence under #ifdef and disabled by
default.
> >
> 
> Am not sure if this is right thing to do it now, the email thread you
pointed to
> be last updated in 1st Aug 2014 .

Agree, the both Stephen and you have pointed out not to base the code on
this work.
Let me redo the patch to remove the dependency on HWTRIPs and have just a
polling based 
Solution.

> >>
> >>> +static int
> >>> +tsens_calib_sensors8960(struct tsens_device *tmdev, struct regmap
> >>> +*map) {
> >>> +	int i;
> >>> +	u32 temp_data[TSENS_MAX_SENSORS];
> >>> +	u8 *byte_data;
> >>> +	u32 fuse, redun, num_read;
> >>> +	struct tsens_sensor *s = tmdev->sensor;
> >>> +
> >>> +	fuse = tmdev->calib_offset;
> >>> +	redun = tmdev->backup_calib_offset;
> >>> +
> >>> +	/**
> >>> +	* syscon regmap is 32-bit data, but calibration data is 8-bit.
> >>> +	* read 4 bytes from regmap in a loop and then extract bytes
> >> seprately
> >>> +	*/
> >>> +
> >> It looks like workaround for the problem in syscon driver.
> >> Please use this patch to fix it.
> >>
> > Unfortunately, this won't work. The same imem region as read as 32-bit
> > for OPP table chip characterization. Looks like this workaround needs
> > to stay Please see the patch below for reference
> > https://chromium-review.googlesource.com/#/c/231792/6
> 
> Does'nt matter If we can read a byte we can also read a word, use
> regmap_read_bulk().
> 
> Again the big plan is to abstract the qfprom access this into something
like
> http://www.spinics.net/lists/linux-arm-msm/msg13090.html
> 
> This will take care of all the code related to qfprom in the drivers.
> Please have a look and give us some comments so that we know whats best.
> 
> ...

My mistake, stride solution is indeed elegant. I just need to put a patch to
change 
the above patch in reference to read 4 bytes.

> 
> >>> +
> >>> +static int tsens_register(struct tsens_device *tmdev, int i) {
> >>> +	char name[18];
> >>> +	u32 addr = TSENS_S0_STATUS_ADDR;
> >>> +	struct tsens_sensor *s = &tmdev->sensor[i];
> >>> +
> >>> +	/*
> >>> +	* The status registers for each sensor are discontiguous
> >>> +	* because some SoCs have 5 sensors while others have more
> >>> +	* but the control registers stay in the same place, i.e.
> >>> +	* directly after the first 5 status registers.
> >>> +	*/
> >>> +	if (i >= 5)
> >>> +		addr += 40;
> >>
> >> This magic values should be going in to some descriptive constants..
> >>
> > There is descriptive comment just above and this is not used anywhere
> else.
> > Perhaps this is easier to read?
> This seems to be like an register offset, So I would prefer it to be a
nice
> #define

Fair enough.

> >
> >>> +
> >>> +	addr += i * 4;
> >>> +
> >>> +	snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
> >> Hmm where is the name actually used??
> >
> > Oops, not needed in the of based registration. Will remove
> >
> >>
> >>> +	s->mode = THERMAL_DEVICE_ENABLED;
> >>> +	s->sensor_num = i;
> >>> +	s->status = addr;
> >>> +	s->tmdev = tmdev;
> >>> +	s->tz_dev = thermal_zone_of_sensor_register(tsens_dev, i, s,
> >>> +						&tsens_thermal_of_ops);
> >>> +
> >>> +	if (IS_ERR(s->tz_dev))
> >>> +		return -ENODEV;
> >> So does that mean that driver would not register tsens unless there
> >> is a
> > DT
> >> node for it?
> >> For apq8064 which has 11 sensors, its becomes necessary to add all 11
> >> sensors in DT with trip points and cooling devices. Which IMO is not
> > right.
> >> You could probably do something like:
> >>
> >> 	s->tz_dev = thermal_zone_of_sensor_register(tsens_dev, i, s,
> >> 					&tsens_thermal_of_ops);
> >>
> >> 	if (IS_ERR(s->tz_dev)) {
> >> 		s->tz_dev = thermal_zone_device_register( ... )
> >> 		if (IS_ERR(s->tz_dev))
> >> 			return -ENODEV;
> >> 	}
> >>
> >> same thing in faliure/remove case ..
> >>
> >
> > Not really. If you look at further down where tsens_register is called
> > (around ln 752), only primary register Is mandatory. If other sensor
> > registration fails, the code just  disables those sensors. Code
> > snipped pasted below
> 
> I think you missed my point.
> Ok, I agree sensor 0 is primary one and should always be registered.
> 
> What am saying is Lets say we have 11 sensors ex: in APQ8064.
> 
> Now we have got dt entries for sensor0 and sensor6.
> Your code would only register sensor0 and sensor6, because you only
> considered DT nodes.
> This is not correct, as we are not short of any resources to populate the
other
> 9 sensors. You should still register all the 11 sensors but 2 of them are
> comming from dt with there own trip point values and the rest of them are
> registered as regular non dt thermal sensors.
> 
> Doing this way would give the user to see all the sensors via sysfs If not
you
> are loosing the real value of all the 9 sensors in the system.
> 
> have a look at other drivers like TI you will understand what Am saying.
> 

Ah, thx for the clarification. 
Alternate thought : 
What if the system want to leverage only say 2 sensors out of 11. The user
has the flexibility 
to select the sensors by specifying this in the dt node. If I do what is
done in TI drivers, all sensors
get registered and polled regardless of this being used in the userspace
thermal daemon.

As a data point, the user-space daemon that exists seems to use only a sub
set of sensors.

> 
> > --------------------->cut<----------------------
> > 	/*
> > 	 * Register sensor 0 separately. This sensor is always
> > 	 * expected to be present and if this fails, thermal
> > 	 * sensor probe would fail
> > 	 * Other sensors are optional and if registration fails
> > 	 * disable the sensor and continue
> > 	*/
> > 	ret = tsens_register(tmdev, 0);
> > 	if (ret < 0) {
> > 		dev_err(tsens_dev, "Registering failed for primary sensor");
> > 		ret = -ENODEV;
> > 		goto fail;
> > 	} else {
> > 		tsens_tz_set_mode(&tmdev->sensor[0],
> > THERMAL_DEVICE_ENABLED);
> > 	}
> > --------------------->cut<----------------------
> >
> >>> +
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static int tsens_probe(struct platform_device *pdev) {
> >>> +	struct device_node *np = pdev->dev.of_node;
> >>> +	struct device_node *base_node;
> >>> +	struct platform_device *base_pdev;
> >>> +	int ret, i, irq, num;
> >>> +	struct tsens_sensor *s;
> >>> +	struct tsens_device *tmdev;
> >>> +	struct regmap *map, *imem_regmap;
> >>> +	struct reg_field *field;
> >>> +	static struct reg_field status_0 = {
> >>> +		.reg = TSENS_8064_STATUS_CNTL,
> >>> +		.lsb = 0,
> >>> +		.msb = 3,
> >>> +	};
> >>> +	static struct reg_field status_8 = {
> >>> +		.reg = TSENS_CNTL_ADDR,
> >>> +		.lsb = 8,
> >>> +		.msb = 11,
> >>> +	};
> >>> +
> >>> +	tsens_dev = &pdev->dev;
> >>> +
> >>> +	num = of_property_count_u32_elems(np, "qcom,tsens-slopes");
> >>> +	if (num <= 0) {
> >>> +		dev_err(tsens_dev, "invalid tsens slopes\n");
> >>> +		return -EINVAL;
> >>> +	}
> >>> +
> >>> +	tmdev = devm_kzalloc(tsens_dev, sizeof(*tmdev) +
> >>> +			     num * sizeof(struct tsens_sensor), GFP_KERNEL);
> >>> +	if (tmdev == NULL)
> >>> +		return -ENOMEM;
> >>> +
> >>> +	tmdev->num_sensors = num;
> >>> +	for (i = 0, s = tmdev->sensor; i < num; i++, s++)
> >>> +		of_property_read_u32_index(np, "qcom,tsens-slopes", i,
> >>> +					   &s->slope);
> >>> +
> >>> +	irq = platform_get_irq(pdev, 0);
> >>> +	if (irq < 0) {
> >>> +		dev_err(tsens_dev,  "no irq resource?\n");
> >>> +		return  -EINVAL;
> >>> +	}
> >>> +
> >>> +	ret = of_property_read_u32_index(np, "qcom,calib-offsets", 0,
> >>> +					   &tmdev->calib_offset);
> >>> +	if (ret != 0) {
> >>> +		dev_err(tsens_dev,  "No calibration offset set\n");
> >>> +		return  -EINVAL;
> >>> +	}
> >>> +
> >>> +	ret = of_property_read_u32_index(np, "qcom,calib-offsets", 1,
> >>> +					   &tmdev->backup_calib_offset);
> >>> +	if (ret) {
> >>> +		dev_info(tsens_dev, "Missing backup calibration offset\n");
> >>> +		tmdev->backup_calib_offset = tmdev->calib_offset;
> >>> +	}
> >>> +
> >>> +	imem_regmap = syscon_regmap_lookup_by_phandle(np,
> >> "qcom,imem");
> >>> +	if (IS_ERR(imem_regmap)) {
> >>> +		dev_err(tsens_dev, "syscon regmap look up error\n");
> >>> +		return PTR_ERR(imem_regmap);
> >>> +	}
> >>> +
> >> Please see my comments in the bindings patch.
> >
> > As mentioned above, the syscon needs to be 32-bit for other
> > calibration data, so I guess no option.
> >
> > On base_regmap, I am good with either ways. Will wait for your further
> > comments and update accordingly in next revision.
> have a look at http://www.spinics.net/lists/linux-arm-msm/msg13090.html

Agree, my error.

> >
> >>
> >>> +	if (num == 1)
> >>> +		ret = tsens_calib_sensors8660(tmdev, imem_regmap);
> >>> +	else
> >>> +		ret = tsens_calib_sensors8960(tmdev, imem_regmap);
> >>> +
> >>> +	if (ret < 0) {
> >>> +		dev_err(tsens_dev, "tsense calibration failed\n");
> >>> +		return ret;
> >>> +	}
> >>> +
> >>> +	base_node = of_parse_phandle(np, "qcom,tsens-base", 0);
> >>> +	if (base_node == NULL) {
> >>> +		dev_err(tsens_dev, "no base node present\n");
> >>> +		return  -EINVAL;
> >>> +	}
> >>> +
> >>> +	base_pdev = of_find_device_by_node(base_node);
> >>> +	if (base_pdev == NULL) {
> >>> +		dev_err(tsens_dev, "no base pdev node\n");
> >>> +		return  -ENODEV;
> >>> +	}
> >>> +
> >>> +	tmdev->map = map = dev_get_regmap(&base_pdev->dev, NULL);
> >>> +	if (map == NULL) {
> >>> +		dev_err(tsens_dev, "base regmap get failed\n");
> >>> +		return  -ENODEV;
> >>> +	}
> >>> +
> >>> +	/* Status bits move when the sensor bits next to them overlap */
> >>> +	if (num > 5)
> >>> +		field = &status_0;
> >>> +	else
> >>> +		field = &status_8;
> >>> +
> >>> +	tmdev->status_field = devm_regmap_field_alloc(tsens_dev, map,
> >> *field);
> >>> +	if (IS_ERR(tmdev->status_field)) {
> >>> +		dev_err(tsens_dev, "regmap alloc failed\n");
> >>> +		return PTR_ERR(tmdev->status_field);
> >>> +	}
> >>> +
> >>> +	tsens_hw_init(tmdev);
> >>> +
> >>> +	/*
> >>> +	 * Register sensor 0 separately. This sensor is always
> >>> +	 * expected to be present and if this fails, thermal
> >>> +	 * sensor probe would fail
> >>> +	 * Other sensors are optional and if registration fails
> >>> +	 * disable the sensor and continue
> >>> +	*/
> >>> +	ret = tsens_register(tmdev, 0);
> >>> +	if (ret < 0) {
> >>> +		dev_err(tsens_dev, "Registering failed for primary sensor");
> >>> +		ret = -ENODEV;
> >>> +		goto fail;
> >>> +	} else {
> >>> +		tsens_tz_set_mode(&tmdev->sensor[0],
> >> THERMAL_DEVICE_ENABLED);
> >>> +	}
> >>> +
> >>> +	for (i = 1;  i < tmdev->num_sensors; i++) {
> >>> +		ret = tsens_register(tmdev, i);
> >>> +
> >>> +		if (ret < 0) {
> >>> +			dev_err(tsens_dev,
> >>> +				"Registering failed. Sensor(%i), disabled",
> > i);
> >>> +			tsens_tz_set_mode(&tmdev->sensor[i],
> >>> +				THERMAL_DEVICE_DISABLED);
> >>> +		} else {
> >>> +			tsens_tz_set_mode(&tmdev->sensor[i],
> >>> +				THERMAL_DEVICE_ENABLED);
> >>> +		}
> >>> +	}
> >>> +
> >>> +	INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
> >>> +
> >>> +	ret = devm_request_irq(tsens_dev, irq, tsens_isr,
> >> IRQF_TRIGGER_RISING,
> >>> +			       "tsens", &tmdev->tsens_work);
> >> Unless I missing something,...Would it actually get an interrupt
> >> without setting the proper trip values in the hw? For example in this
> >> driver we
> > only
> >> register from DT.. and the values from Dt never ends up writing into
> >> the
> > hw
> >> registers.. so this would never trigger an interrupt from trip points
> >> mentioned in DT. Unless the default reg values makes sense..
> >> still its out of sync from DT trip values.
> >>
> > Correct, in polling mode (which is what exists in thermal framework
> > today), HW interrupt do not make sense as the trip points are set to
> > default and never updated based on Dt values.
> >
> > But the code under the #ifdef THERMAL_TSENS8960_HWTRIPS supports
> the
> > HW trip point mode.
> > This code needs the additional patch
> > Please see https://patchwork.ozlabs.org/patch/364812/
> >
> > May be I will remove everything under HWTRIPs until it lands in the
> > core thermal framework?
> >
> >> Does the interrupt actually work? Last time when I tested it on 3.4
> >> It
> > never
> >> did work?..
> 
> ???

The code was indeed running in polling mode and interrupts are not getting
triggered on 
3.14 as well. 
I need to go back and check the older version to see if I am missing some
register
setting. From a register map, it has only documented interrupt status, not
enable/disable.

> 
> How do you enable/disable the interrupt in the tses IP, I did not find any
> register to do that?
> Do we have one?
> >>> +	if (ret < 0)
> >>> +		goto err_irq;
> >>> +
> >>> +	platform_set_drvdata(pdev, tmdev);
> >>> +
> >>> +	dev_info(tsens_dev, "Tsens driver initialized\n");
> >>> +
> >>> +	return 0;
> >>> +err_irq:
> >>> +	for (i = 0, s = tmdev->sensor; i < tmdev->num_sensors; i++, s++)
> >>> +		thermal_zone_of_sensor_unregister(&pdev->dev, s-
> >>> tz_dev);
> >>> +fail:
> >>> +	tsens_disable_mode(tmdev);
> >>> +	return ret;
> >>> +}
> >>> +
> >>> +static int tsens_remove(struct platform_device *pdev) {
> >>> +	int i;
> >>> +	struct tsens_sensor *s;
> >>> +	struct tsens_device *tmdev = platform_get_drvdata(pdev);
> >>> +
> >>> +	tsens_disable_mode(tmdev);
> >>> +	for (i = 0, s = tmdev->sensor; i < tmdev->num_sensors; i++, s++)
> >>> +		thermal_zone_device_unregister(s->tz_dev);
> >>> +
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static struct of_device_id tsens_match_table[] = {
> >>> +	{.compatible = "qcom,ipq806x-tsens"},
> >> should be "qcom,msm8960-tsens"
> >>
> >
> > Thx, will address in next version.
> >
> >>> +	{},
> >>> +};
> >>> +
> >>> +MODULE_DEVICE_TABLE(of, tsens_match_table);
> >>> +
> >>> +static struct platform_driver tsens_driver = {
> >>> +	.probe = tsens_probe,
> >>> +	.remove = tsens_remove,
> >>> +	.driver = {
> >>> +		.of_match_table = tsens_match_table,
> >>> +		.name = "tsens8960-thermal",
> >>> +		.owner = THIS_MODULE,
> >> remove the owner as it would be set anyway byt the core.
> >
> > Thx, will address in next version.
> >
> >>> +#ifdef CONFIG_PM
> >>> +		.pm	= &tsens_pm_ops,
> >>> +#endif
> >> Please use SIMPLE_DEV_PM_OPS(...)
> >>
> >
> > Thx, will address in next version.
> >
> >>> +	},
> >>> +};
> >>> +module_platform_driver(tsens_driver);
> >>> +
> >>> +MODULE_LICENSE("GPL v2");
> >>> +MODULE_DESCRIPTION("Temperature Sensor driver");
> >>> +MODULE_ALIAS("platform:tsens8960-tm");
> >>>
> >> --srini
> >

--Naren

--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [Linux for Sparc]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux