mirror of https://github.com/hak5/openwrt.git
parent
b2b965a696
commit
26b3cdad1c
File diff suppressed because it is too large
Load Diff
|
@ -1,341 +0,0 @@
|
|||
--- /dev/null
|
||||
+++ b/drivers/hwmon/gsp.c
|
||||
@@ -0,0 +1,310 @@
|
||||
+/*
|
||||
+ * A hwmon driver for the Gateworks System Peripheral
|
||||
+ * Copyright (C) 2009 Gateworks Corporation
|
||||
+ *
|
||||
+ * Author: Chris Lang <clang@gateworks.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License,
|
||||
+ * as published by the Free Software Foundation - version 2.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <linux/hwmon.h>
|
||||
+#include <linux/hwmon-sysfs.h>
|
||||
+#include <linux/err.h>
|
||||
+
|
||||
+
|
||||
+#define DRV_VERSION "0.2"
|
||||
+
|
||||
+enum chips { gsp };
|
||||
+
|
||||
+/* AD7418 registers */
|
||||
+#define GSP_REG_TEMP_IN 0x00
|
||||
+#define GSP_REG_VIN 0x02
|
||||
+#define GSP_REG_3P3 0x05
|
||||
+#define GSP_REG_BAT 0x08
|
||||
+#define GSP_REG_5P0 0x0b
|
||||
+#define GSP_REG_CORE 0x0e
|
||||
+#define GSP_REG_CPU1 0x11
|
||||
+#define GSP_REG_CPU2 0x14
|
||||
+#define GSP_REG_DRAM 0x17
|
||||
+#define GSP_REG_EXT_BAT 0x1a
|
||||
+#define GSP_REG_IO1 0x1d
|
||||
+#define GSP_REG_IO2 0x20
|
||||
+#define GSP_REG_PCIE 0x23
|
||||
+#define GSP_REG_CURRENT 0x26
|
||||
+#define GSP_FAN_0 0x2C
|
||||
+#define GSP_FAN_1 0x2E
|
||||
+#define GSP_FAN_2 0x30
|
||||
+#define GSP_FAN_3 0x32
|
||||
+#define GSP_FAN_4 0x34
|
||||
+#define GSP_FAN_5 0x36
|
||||
+
|
||||
+struct gsp_sensor_info {
|
||||
+ const char* name;
|
||||
+ int reg;
|
||||
+};
|
||||
+
|
||||
+static const struct gsp_sensor_info gsp_sensors[] = {
|
||||
+ {"temp", GSP_REG_TEMP_IN},
|
||||
+ {"vin", GSP_REG_VIN},
|
||||
+ {"3p3", GSP_REG_3P3},
|
||||
+ {"bat", GSP_REG_BAT},
|
||||
+ {"5p0", GSP_REG_5P0},
|
||||
+ {"core", GSP_REG_CORE},
|
||||
+ {"cpu1", GSP_REG_CPU1},
|
||||
+ {"cpu2", GSP_REG_CPU2},
|
||||
+ {"dram", GSP_REG_DRAM},
|
||||
+ {"ext_bat", GSP_REG_EXT_BAT},
|
||||
+ {"io1", GSP_REG_IO1},
|
||||
+ {"io2", GSP_REG_IO2},
|
||||
+ {"pci2", GSP_REG_PCIE},
|
||||
+ {"current", GSP_REG_CURRENT},
|
||||
+ {"fan_point0", GSP_FAN_0},
|
||||
+ {"fan_point1", GSP_FAN_1},
|
||||
+ {"fan_point2", GSP_FAN_2},
|
||||
+ {"fan_point3", GSP_FAN_3},
|
||||
+ {"fan_point4", GSP_FAN_4},
|
||||
+ {"fan_point5", GSP_FAN_5},
|
||||
+};
|
||||
+
|
||||
+struct gsp_data {
|
||||
+ struct device *hwmon_dev;
|
||||
+ struct attribute_group attrs;
|
||||
+ enum chips type;
|
||||
+};
|
||||
+
|
||||
+static int gsp_probe(struct i2c_client *client,
|
||||
+ const struct i2c_device_id *id);
|
||||
+static int gsp_remove(struct i2c_client *client);
|
||||
+
|
||||
+static const struct i2c_device_id gsp_id[] = {
|
||||
+ { "gsp", 0 },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(i2c, gsp_id);
|
||||
+
|
||||
+static struct i2c_driver gsp_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "gsp",
|
||||
+ },
|
||||
+ .probe = gsp_probe,
|
||||
+ .remove = gsp_remove,
|
||||
+ .id_table = gsp_id,
|
||||
+};
|
||||
+
|
||||
+/* All registers are word-sized, except for the configuration registers.
|
||||
+ * AD7418 uses a high-byte first convention. Do NOT use those functions to
|
||||
+ * access the configuration registers CONF and CONF2, as they are byte-sized.
|
||||
+ */
|
||||
+static inline int gsp_read(struct i2c_client *client, u8 reg)
|
||||
+{
|
||||
+ unsigned int adc = 0;
|
||||
+ if (reg == GSP_REG_TEMP_IN || reg > GSP_REG_CURRENT)
|
||||
+ {
|
||||
+ adc |= i2c_smbus_read_byte_data(client, reg);
|
||||
+ adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8;
|
||||
+ return adc;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ adc |= i2c_smbus_read_byte_data(client, reg);
|
||||
+ adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8;
|
||||
+ adc |= i2c_smbus_read_byte_data(client, reg + 2) << 16;
|
||||
+ return adc;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static inline int gsp_write(struct i2c_client *client, u8 reg, u16 value)
|
||||
+{
|
||||
+ i2c_smbus_write_byte_data(client, reg, value & 0xff);
|
||||
+ i2c_smbus_write_byte_data(client, reg + 1, ((value >> 8) & 0xff));
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static ssize_t show_adc(struct device *dev, struct device_attribute *devattr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
+ struct i2c_client *client = to_i2c_client(dev);
|
||||
+ return sprintf(buf, "%d\n", gsp_read(client, gsp_sensors[attr->index].reg));
|
||||
+}
|
||||
+
|
||||
+static ssize_t show_label(struct device *dev,
|
||||
+ struct device_attribute *devattr, char *buf)
|
||||
+{
|
||||
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
+
|
||||
+ return sprintf(buf, "%s\n", gsp_sensors[attr->index].name);
|
||||
+}
|
||||
+
|
||||
+static ssize_t store_fan(struct device *dev,
|
||||
+ struct device_attribute *devattr, const char *buf, size_t count)
|
||||
+{
|
||||
+ u16 val;
|
||||
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
+ struct i2c_client *client = to_i2c_client(dev);
|
||||
+ val = simple_strtoul(buf, NULL, 10);
|
||||
+ gsp_write(client, gsp_sensors[attr->index].reg, val);
|
||||
+ return count;
|
||||
+}
|
||||
+
|
||||
+static SENSOR_DEVICE_ATTR(temp0_input, S_IRUGO, show_adc, NULL, 0);
|
||||
+static SENSOR_DEVICE_ATTR(temp0_label, S_IRUGO, show_label, NULL, 0);
|
||||
+
|
||||
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_adc, NULL, 1);
|
||||
+static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL, 1);
|
||||
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_adc, NULL, 2);
|
||||
+static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_label, NULL, 2);
|
||||
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 3);
|
||||
+static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_label, NULL, 3);
|
||||
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 4);
|
||||
+static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 4);
|
||||
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 5);
|
||||
+static SENSOR_DEVICE_ATTR(in4_label, S_IRUGO, show_label, NULL, 5);
|
||||
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_adc, NULL, 6);
|
||||
+static SENSOR_DEVICE_ATTR(in5_label, S_IRUGO, show_label, NULL, 6);
|
||||
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_adc, NULL, 7);
|
||||
+static SENSOR_DEVICE_ATTR(in6_label, S_IRUGO, show_label, NULL, 7);
|
||||
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_adc, NULL, 8);
|
||||
+static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 8);
|
||||
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_adc, NULL, 9);
|
||||
+static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 9);
|
||||
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_adc, NULL, 10);
|
||||
+static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 10);
|
||||
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_adc, NULL, 11);
|
||||
+static SENSOR_DEVICE_ATTR(in10_label, S_IRUGO, show_label, NULL, 11);
|
||||
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_adc, NULL, 12);
|
||||
+static SENSOR_DEVICE_ATTR(in11_label, S_IRUGO, show_label, NULL, 12);
|
||||
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_adc, NULL, 13);
|
||||
+static SENSOR_DEVICE_ATTR(in12_label, S_IRUGO, show_label, NULL, 13);
|
||||
+
|
||||
+static SENSOR_DEVICE_ATTR(fan0_point0, S_IRUGO | S_IWUSR, show_adc, store_fan, 14);
|
||||
+static SENSOR_DEVICE_ATTR(fan0_point1, S_IRUGO | S_IWUSR, show_adc, store_fan, 15);
|
||||
+static SENSOR_DEVICE_ATTR(fan0_point2, S_IRUGO | S_IWUSR, show_adc, store_fan, 16);
|
||||
+static SENSOR_DEVICE_ATTR(fan0_point3, S_IRUGO | S_IWUSR, show_adc, store_fan, 17);
|
||||
+static SENSOR_DEVICE_ATTR(fan0_point4, S_IRUGO | S_IWUSR, show_adc, store_fan, 18);
|
||||
+static SENSOR_DEVICE_ATTR(fan0_point5, S_IRUGO | S_IWUSR, show_adc, store_fan, 19);
|
||||
+
|
||||
+
|
||||
+
|
||||
+static struct attribute *gsp_attributes[] = {
|
||||
+ &sensor_dev_attr_temp0_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in3_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in5_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in6_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in7_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in8_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in9_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in10_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in11_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in12_input.dev_attr.attr,
|
||||
+
|
||||
+ &sensor_dev_attr_temp0_label.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in0_label.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in1_label.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in2_label.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in3_label.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in4_label.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in5_label.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in6_label.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in7_label.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in8_label.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in9_label.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in10_label.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in11_label.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in12_label.dev_attr.attr,
|
||||
+
|
||||
+ &sensor_dev_attr_fan0_point0.dev_attr.attr,
|
||||
+ &sensor_dev_attr_fan0_point1.dev_attr.attr,
|
||||
+ &sensor_dev_attr_fan0_point2.dev_attr.attr,
|
||||
+ &sensor_dev_attr_fan0_point3.dev_attr.attr,
|
||||
+ &sensor_dev_attr_fan0_point4.dev_attr.attr,
|
||||
+ &sensor_dev_attr_fan0_point5.dev_attr.attr,
|
||||
+
|
||||
+ NULL
|
||||
+};
|
||||
+
|
||||
+
|
||||
+static int gsp_probe(struct i2c_client *client,
|
||||
+ const struct i2c_device_id *id)
|
||||
+{
|
||||
+ struct i2c_adapter *adapter = client->adapter;
|
||||
+ struct gsp_data *data;
|
||||
+ int err;
|
||||
+
|
||||
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
+ I2C_FUNC_SMBUS_WORD_DATA)) {
|
||||
+ err = -EOPNOTSUPP;
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
+ if (!(data = kzalloc(sizeof(struct gsp_data), GFP_KERNEL))) {
|
||||
+ err = -ENOMEM;
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
+ i2c_set_clientdata(client, data);
|
||||
+
|
||||
+ data->type = id->driver_data;
|
||||
+
|
||||
+ switch (data->type) {
|
||||
+ case 0:
|
||||
+ data->attrs.attrs = gsp_attributes;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ dev_info(&client->dev, "%s chip found\n", client->name);
|
||||
+
|
||||
+ /* Register sysfs hooks */
|
||||
+ if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
|
||||
+ goto exit_free;
|
||||
+
|
||||
+ data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
+ if (IS_ERR(data->hwmon_dev)) {
|
||||
+ err = PTR_ERR(data->hwmon_dev);
|
||||
+ goto exit_remove;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+exit_remove:
|
||||
+ sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||
+exit_free:
|
||||
+ kfree(data);
|
||||
+exit:
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int gsp_remove(struct i2c_client *client)
|
||||
+{
|
||||
+ struct gsp_data *data = i2c_get_clientdata(client);
|
||||
+ hwmon_device_unregister(data->hwmon_dev);
|
||||
+ sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||
+ kfree(data);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int __init gsp_init(void)
|
||||
+{
|
||||
+ return i2c_add_driver(&gsp_driver);
|
||||
+}
|
||||
+
|
||||
+static void __exit gsp_exit(void)
|
||||
+{
|
||||
+ i2c_del_driver(&gsp_driver);
|
||||
+}
|
||||
+
|
||||
+MODULE_AUTHOR("Chris Lang <clang@gateworks.com>");
|
||||
+MODULE_DESCRIPTION("GSP HWMON driver");
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_VERSION(DRV_VERSION);
|
||||
+
|
||||
+module_init(gsp_init);
|
||||
+module_exit(gsp_exit);
|
||||
--- a/drivers/hwmon/Kconfig
|
||||
+++ b/drivers/hwmon/Kconfig
|
||||
@@ -57,6 +57,15 @@ config SENSORS_ABITUGURU3
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called abituguru3.
|
||||
|
||||
+config SENSORS_GSP
|
||||
+ tristate "Gateworks System Peripheral"
|
||||
+ depends on I2C && EXPERIMENTAL
|
||||
+ help
|
||||
+ If you say yes here you get support for the Gateworks System Peripherals.
|
||||
+
|
||||
+ This driver can also be built as a module. If so, the module
|
||||
+ will be called gsp.
|
||||
+
|
||||
config SENSORS_AD7414
|
||||
tristate "Analog Devices AD7414"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
--- a/drivers/hwmon/Makefile
|
||||
+++ b/drivers/hwmon/Makefile
|
||||
@@ -15,6 +15,7 @@ obj-$(CONFIG_SENSORS_W83791D) += w83791d
|
||||
|
||||
obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
|
||||
obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
|
||||
+obj-$(CONFIG_SENSORS_GSP) += gsp.o
|
||||
obj-$(CONFIG_SENSORS_AD7414) += ad7414.o
|
||||
obj-$(CONFIG_SENSORS_AD7418) += ad7418.o
|
||||
obj-$(CONFIG_SENSORS_ADCXX) += adcxx.o
|
File diff suppressed because it is too large
Load Diff
|
@ -1,416 +0,0 @@
|
|||
--- /dev/null
|
||||
+++ b/drivers/i2c/busses/i2c-cns3xxx.c
|
||||
@@ -0,0 +1,388 @@
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <asm/io.h>
|
||||
+#include <linux/wait.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <mach/pm.h>
|
||||
+
|
||||
+/*
|
||||
+ * We need the memory map
|
||||
+ */
|
||||
+
|
||||
+#include <mach/board.h>
|
||||
+
|
||||
+#define MISC_MEM_MAP_VALUE(reg_offset) (*((uint32_t volatile *)(CNS3XXX_MISC_BASE_VIRT + reg_offset)))
|
||||
+#define MISC_IOCDB_CTRL MISC_MEM_MAP_VALUE(0x020)
|
||||
+
|
||||
+#define I2C_MEM_MAP_ADDR(x) (CNS3XXX_SSP_BASE_VIRT + x)
|
||||
+#define I2C_MEM_MAP_VALUE(x) (*((unsigned int volatile*)I2C_MEM_MAP_ADDR(x)))
|
||||
+
|
||||
+#define I2C_CONTROLLER_REG I2C_MEM_MAP_VALUE(0x20)
|
||||
+#define I2C_TIME_OUT_REG I2C_MEM_MAP_VALUE(0x24)
|
||||
+#define I2C_SLAVE_ADDRESS_REG I2C_MEM_MAP_VALUE(0x28)
|
||||
+#define I2C_WRITE_DATA_REG I2C_MEM_MAP_VALUE(0x2C)
|
||||
+#define I2C_READ_DATA_REG I2C_MEM_MAP_VALUE(0x30)
|
||||
+#define I2C_INTERRUPT_STATUS_REG I2C_MEM_MAP_VALUE(0x34)
|
||||
+#define I2C_INTERRUPT_ENABLE_REG I2C_MEM_MAP_VALUE(0x38)
|
||||
+#define I2C_TWI_OUT_DLY_REG I2C_MEM_MAP_VALUE(0x3C)
|
||||
+
|
||||
+#define I2C_BUS_ERROR_FLAG (0x1)
|
||||
+#define I2C_ACTION_DONE_FLAG (0x2)
|
||||
+
|
||||
+#define CNS3xxx_I2C_ENABLE() (I2C_CONTROLLER_REG) |= ((unsigned int)0x1 << 31)
|
||||
+#define CNS3xxx_I2C_DISABLE() (I2C_CONTROLLER_REG) &= ~((unsigned int)0x1 << 31)
|
||||
+#define CNS3xxx_I2C_ENABLE_INTR() (I2C_INTERRUPT_ENABLE_REG) |= 0x03
|
||||
+#define CNS3xxx_I2C_DISABLE_INTR() (I2C_INTERRUPT_ENABLE_REG) &= 0xfc
|
||||
+
|
||||
+#define TWI_TIMEOUT (10*HZ)
|
||||
+#define I2C_100KHZ 100000
|
||||
+#define I2C_200KHZ 200000
|
||||
+#define I2C_300KHZ 300000
|
||||
+#define I2C_400KHZ 400000
|
||||
+
|
||||
+#define CNS3xxx_I2C_CLK I2C_100KHZ
|
||||
+
|
||||
+#define STATE_DONE 1
|
||||
+#define STATE_ERROR 2
|
||||
+
|
||||
+struct cns3xxx_i2c {
|
||||
+ void __iomem *base;
|
||||
+ wait_queue_head_t wait;
|
||||
+ struct i2c_adapter adap;
|
||||
+ struct i2c_msg *msg;
|
||||
+ int state; /* see STATE_ */
|
||||
+ int rd_wr_len;
|
||||
+ u8 *buf;
|
||||
+};
|
||||
+
|
||||
+static u32 cns3xxx_i2c_func(struct i2c_adapter *adap)
|
||||
+{
|
||||
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+cns3xxx_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg)
|
||||
+{
|
||||
+ struct cns3xxx_i2c *i2c = i2c_get_adapdata(adap);
|
||||
+ int i, j;
|
||||
+ u8 buf[1] = { 0 };
|
||||
+
|
||||
+ if (msg->len == 0) {
|
||||
+ /*
|
||||
+ * We are probably doing a probe for a device here,
|
||||
+ * so set the length to one, and data to 0
|
||||
+ */
|
||||
+ msg->len = 1;
|
||||
+ i2c->buf = buf;
|
||||
+ } else {
|
||||
+ i2c->buf = msg->buf;
|
||||
+ }
|
||||
+
|
||||
+ if (msg->flags & I2C_M_TEN) {
|
||||
+ printk
|
||||
+ ("%s:%d: Presently the driver does not handle extended addressing\n",
|
||||
+ __FUNCTION__, __LINE__);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ i2c->msg = msg;
|
||||
+
|
||||
+ for (i = 0; i < msg->len; i++) {
|
||||
+ if (msg->len - i >= 4)
|
||||
+ i2c->rd_wr_len = 3;
|
||||
+ else
|
||||
+ i2c->rd_wr_len = msg->len - i - 1;
|
||||
+
|
||||
+ // Set Data Width and TWI_EN
|
||||
+ I2C_CONTROLLER_REG = 0x80000000 | (i2c->rd_wr_len << 2) | (i2c->rd_wr_len);
|
||||
+
|
||||
+ // Clear Write Reg
|
||||
+ I2C_WRITE_DATA_REG = 0;
|
||||
+
|
||||
+ // Set the slave address
|
||||
+ I2C_SLAVE_ADDRESS_REG = (msg->addr << 1);
|
||||
+
|
||||
+ // Are we Writing
|
||||
+ if (!(msg->flags & I2C_M_RD)) {
|
||||
+ I2C_CONTROLLER_REG |= (1 << 4);
|
||||
+ if (i != 0) {
|
||||
+ /*
|
||||
+ * We need to set the address in the first byte.
|
||||
+ * The base address is going to be in buf[0] and then
|
||||
+ * it needs to be incremented by i - 1.
|
||||
+ */
|
||||
+ i2c->buf--;
|
||||
+ *i2c->buf = buf[0] + i - 1;
|
||||
+
|
||||
+ if (i2c->rd_wr_len < 3) {
|
||||
+ i += i2c->rd_wr_len;
|
||||
+ i2c->rd_wr_len++;
|
||||
+ I2C_CONTROLLER_REG = 0x80000000 | (1 << 4) | (i2c->rd_wr_len << 2) | (i2c->rd_wr_len);
|
||||
+ } else {
|
||||
+ i += i2c->rd_wr_len - 1;
|
||||
+ }
|
||||
+ } else {
|
||||
+ i += i2c->rd_wr_len;
|
||||
+ buf[0] = *i2c->buf;
|
||||
+ }
|
||||
+ for (j = 0; j <= i2c->rd_wr_len; j++) {
|
||||
+ I2C_WRITE_DATA_REG |= ((*i2c->buf++) << (8 * j));
|
||||
+ }
|
||||
+ } else {
|
||||
+ i += i2c->rd_wr_len;
|
||||
+ }
|
||||
+
|
||||
+ // Start the Transfer
|
||||
+ i2c->state = 0; // Clear out the State
|
||||
+ I2C_CONTROLLER_REG |= (1 << 6);
|
||||
+
|
||||
+ if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
|
||||
+ (i2c->state == STATE_DONE), TWI_TIMEOUT)) {
|
||||
+ if (i2c->state == STATE_ERROR) {
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+ } else {
|
||||
+ return -ETIMEDOUT;
|
||||
+ }
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+cns3xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
+{
|
||||
+ int i;
|
||||
+ int ret;
|
||||
+ for (i = 0; i < num; i++)
|
||||
+ {
|
||||
+ ret = cns3xxx_i2c_xfer_msg(adap, &msgs[i]);
|
||||
+ if (ret < 0) {
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+ return num;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static struct i2c_algorithm cns3xxx_i2c_algo = {
|
||||
+ .master_xfer = cns3xxx_i2c_xfer,
|
||||
+ .functionality = cns3xxx_i2c_func,
|
||||
+};
|
||||
+
|
||||
+static struct i2c_adapter cns3xxx_i2c_adapter = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .algo = &cns3xxx_i2c_algo,
|
||||
+ .algo_data = NULL,
|
||||
+ .nr = 0,
|
||||
+ .name = "CNS3xxx I2C 0",
|
||||
+ .retries = 5,
|
||||
+};
|
||||
+
|
||||
+static void cns3xxx_i2c_adapter_init(struct cns3xxx_i2c *i2c)
|
||||
+{
|
||||
+
|
||||
+ /* Steps
|
||||
+ * 1. Check if the power is enabled to the module (PMU_BASE + 0x010)
|
||||
+ * 2. Enable the clock (Enabled by default (PMU doc
|
||||
+ * but check clk status anyway PMU_BASE + 0X00C)
|
||||
+ * 3. Configure the registers of i2c
|
||||
+ */
|
||||
+
|
||||
+ // if (!CNS3xxx_I2C_POWER_ON())
|
||||
+// CNS3xxx_I2C_POWER_ENABLE();
|
||||
+
|
||||
+ // if (!CNS3xxx_I2C_CLOCK())
|
||||
+ // CNS3xxx_I2C_CLOCK_ENABLE();
|
||||
+
|
||||
+ cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_SPI_PCM_I2C);
|
||||
+ cns3xxx_pwr_power_up(0x1 << PM_CLK_GATE_REG_OFFSET_SPI_PCM_I2C);
|
||||
+ cns3xxx_pwr_soft_rst(0x1 << PM_CLK_GATE_REG_OFFSET_SPI_PCM_I2C);
|
||||
+
|
||||
+ /* Disable the I2C */
|
||||
+ I2C_CONTROLLER_REG = 0; /* Disabled the I2C */
|
||||
+
|
||||
+ //enable SCL and SDA which share pin with GPIOB_PIN_EN(0x18)
|
||||
+ //GPIOB[12]: SCL
|
||||
+ //GPIOB[13]: SDA
|
||||
+ (*(u32*)(CNS3XXX_MISC_BASE_VIRT+0x18)) |= ((1<<12)|(1<<13));
|
||||
+
|
||||
+ MISC_IOCDB_CTRL &= ~0x300;
|
||||
+ MISC_IOCDB_CTRL |= 0x300; //21mA...
|
||||
+
|
||||
+ /* Check the Reg Dump when testing */
|
||||
+ I2C_TIME_OUT_REG =
|
||||
+ ((((((cns3xxx_cpu_clock()*(1000000/8)) / (2 * CNS3xxx_I2C_CLK)) -
|
||||
+ 1) & 0x3FF) << 8) | (1 << 7) | 0x7F);
|
||||
+ I2C_TWI_OUT_DLY_REG |= 0x3;
|
||||
+
|
||||
+ /* Enable The Interrupt */
|
||||
+ CNS3xxx_I2C_ENABLE_INTR();
|
||||
+
|
||||
+ /* Clear Interrupt Status (0x2 | 0x1) */
|
||||
+ I2C_INTERRUPT_STATUS_REG |= (I2C_ACTION_DONE_FLAG | I2C_BUS_ERROR_FLAG);
|
||||
+
|
||||
+ /* Enable the I2C Controller */
|
||||
+ CNS3xxx_I2C_ENABLE();
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t cns3xxx_i2c_isr(int irq, void *dev_id)
|
||||
+{
|
||||
+ struct cns3xxx_i2c *i2c = dev_id;
|
||||
+ int i;
|
||||
+ uint32_t stat = I2C_INTERRUPT_STATUS_REG;
|
||||
+
|
||||
+ /* Clear Interrupt */
|
||||
+ I2C_INTERRUPT_STATUS_REG |= 0x1;
|
||||
+
|
||||
+ if (stat & I2C_BUS_ERROR_FLAG) {
|
||||
+ i2c->state = STATE_ERROR;
|
||||
+ } else {
|
||||
+ if (i2c->msg->flags & I2C_M_RD) {
|
||||
+ for (i = 0; i <= i2c->rd_wr_len; i++)
|
||||
+ {
|
||||
+ *i2c->buf++ = ((I2C_READ_DATA_REG >> (8 * i)) & 0xff);
|
||||
+ }
|
||||
+ }
|
||||
+ i2c->state = STATE_DONE;
|
||||
+ }
|
||||
+ wake_up(&i2c->wait);
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static int __devinit cns3xxx_i2c_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct cns3xxx_i2c *i2c;
|
||||
+ struct resource *res, *res2;
|
||||
+ int ret;
|
||||
+
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ if (!res) {
|
||||
+ printk("%s: IORESOURCE_MEM not defined \n", __FUNCTION__);
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
+ if (!res2) {
|
||||
+ printk("%s: IORESOURCE_IRQ not defined \n", __FUNCTION__);
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
|
||||
+ if (!i2c)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ if (!request_mem_region(res->start, res->end - res->start + 1,
|
||||
+ pdev->name)) {
|
||||
+ dev_err(&pdev->dev, "Memory region busy\n");
|
||||
+ ret = -EBUSY;
|
||||
+ goto request_mem_failed;
|
||||
+ }
|
||||
+
|
||||
+ i2c->base = ioremap(res->start, res->end - res->start + 1);
|
||||
+ if (!i2c->base) {
|
||||
+ dev_err(&pdev->dev, "Unable to map registers\n");
|
||||
+ ret = -EIO;
|
||||
+ goto map_failed;
|
||||
+ }
|
||||
+
|
||||
+ cns3xxx_i2c_adapter_init(i2c);
|
||||
+
|
||||
+ init_waitqueue_head(&i2c->wait);
|
||||
+ ret = request_irq(res2->start, cns3xxx_i2c_isr, 0, pdev->name, i2c);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "Cannot claim IRQ\n");
|
||||
+ goto request_irq_failed;
|
||||
+ }
|
||||
+
|
||||
+ platform_set_drvdata(pdev, i2c);
|
||||
+ i2c->adap = cns3xxx_i2c_adapter;
|
||||
+ i2c_set_adapdata(&i2c->adap, i2c);
|
||||
+ i2c->adap.dev.parent = &pdev->dev;
|
||||
+
|
||||
+ /* add i2c adapter to i2c tree */
|
||||
+ ret = i2c_add_numbered_adapter(&i2c->adap);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "Failed to add adapter\n");
|
||||
+ goto add_adapter_failed;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+ add_adapter_failed:
|
||||
+ free_irq(res2->start, i2c);
|
||||
+ request_irq_failed:
|
||||
+ iounmap(i2c->base);
|
||||
+ map_failed:
|
||||
+ release_mem_region(res->start, res->end - res->start + 1);
|
||||
+ request_mem_failed:
|
||||
+ kfree(i2c);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int __devexit cns3xxx_i2c_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct cns3xxx_i2c *i2c = platform_get_drvdata(pdev);
|
||||
+ struct resource *res;
|
||||
+
|
||||
+ /* disable i2c logic */
|
||||
+ CNS3xxx_I2C_DISABLE_INTR();
|
||||
+ CNS3xxx_I2C_DISABLE();
|
||||
+ /* remove adapter & data */
|
||||
+ i2c_del_adapter(&i2c->adap);
|
||||
+ platform_set_drvdata(pdev, NULL);
|
||||
+
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
+ if (res)
|
||||
+ free_irq(res->start, i2c);
|
||||
+
|
||||
+ iounmap(i2c->base);
|
||||
+
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ if (res)
|
||||
+ release_mem_region(res->start, res->end - res->start + 1);
|
||||
+
|
||||
+ kfree(i2c);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#ifdef CONFIG_PM
|
||||
+#warning "CONFIG_PM defined: suspend and resume not implemented"
|
||||
+#define cns3xxx_i2c_suspend NULL
|
||||
+#define cns3xxx_i2c_resume NULL
|
||||
+#else
|
||||
+#define cns3xxx_i2c_suspend NULL
|
||||
+#define cns3xxx_i2c_resume NULL
|
||||
+#endif
|
||||
+
|
||||
+static struct platform_driver cns3xxx_i2c_driver = {
|
||||
+ .probe = cns3xxx_i2c_probe,
|
||||
+ .remove = cns3xxx_i2c_remove,
|
||||
+ .suspend = cns3xxx_i2c_suspend,
|
||||
+ .resume = cns3xxx_i2c_resume,
|
||||
+ .driver = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .name = "cns3xxx-i2c",
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static int __init cns3xxx_i2c_init(void)
|
||||
+{
|
||||
+ return platform_driver_register(&cns3xxx_i2c_driver);
|
||||
+}
|
||||
+
|
||||
+static void __exit cns3xxx_i2c_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&cns3xxx_i2c_driver);
|
||||
+}
|
||||
+
|
||||
+module_init(cns3xxx_i2c_init);
|
||||
+module_exit(cns3xxx_i2c_exit);
|
||||
+
|
||||
+MODULE_AUTHOR("Cavium Networks");
|
||||
+MODULE_DESCRIPTION("Cavium CNS3XXX I2C Controller");
|
||||
+MODULE_LICENSE("GPL");
|
||||
--- a/drivers/i2c/busses/Kconfig
|
||||
+++ b/drivers/i2c/busses/Kconfig
|
||||
@@ -422,6 +422,12 @@ config I2C_MV64XXX
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-mv64xxx.
|
||||
|
||||
+config I2C_CNS3XXX
|
||||
+ tristate "Cavium Networks CNS3XXX I2C Controller"
|
||||
+ depends on ARCH_CNS3XXX
|
||||
+ help
|
||||
+ Supports the Cavium Networks CNS3XXX on-chip I2C interfaces
|
||||
+
|
||||
config I2C_OCORES
|
||||
tristate "OpenCores I2C Controller"
|
||||
depends on EXPERIMENTAL
|
||||
--- a/drivers/i2c/busses/Makefile
|
||||
+++ b/drivers/i2c/busses/Makefile
|
||||
@@ -39,6 +39,7 @@ obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
|
||||
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
|
||||
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
|
||||
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
|
||||
+obj-$(CONFIG_I2C_CNS3XXX) += i2c-cns3xxx.o
|
||||
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
|
||||
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
|
||||
obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,438 +0,0 @@
|
|||
--- a/crypto/xor.c
|
||||
+++ b/crypto/xor.c
|
||||
@@ -25,6 +25,26 @@
|
||||
/* The xor routines to use. */
|
||||
static struct xor_block_template *active_template;
|
||||
|
||||
+#ifdef CONFIG_CNS3XXX_RAID
|
||||
+extern void do_cns_rdma_xorgen(unsigned int src_no, unsigned int bytes,
|
||||
+ void **bh_ptr, void *dst_ptr);
|
||||
+/**
|
||||
+ * xor_blocks - one pass xor
|
||||
+ * @src_count: source count
|
||||
+ * @bytes: length in bytes
|
||||
+ * @dest: dest
|
||||
+ * @srcs: srcs
|
||||
+ *
|
||||
+ * Desc:
|
||||
+ * 1. dest = xor(srcs[0...src_count-1]) within one calc
|
||||
+ * 2. don't care if dest also be placed in srcs list or not.
|
||||
+ */
|
||||
+void xor_blocks(unsigned int src_count, unsigned int bytes, void *dest,
|
||||
+ void **srcs)
|
||||
+{
|
||||
+ do_cns_rdma_xorgen(src_count, bytes, srcs, dest);
|
||||
+}
|
||||
+#else
|
||||
void
|
||||
xor_blocks(unsigned int src_count, unsigned int bytes, void *dest, void **srcs)
|
||||
{
|
||||
@@ -51,6 +71,7 @@ xor_blocks(unsigned int src_count, unsig
|
||||
p4 = (unsigned long *) srcs[3];
|
||||
active_template->do_5(bytes, dest, p1, p2, p3, p4);
|
||||
}
|
||||
+#endif /* CONFIG_CNS3XXX_RAID */
|
||||
EXPORT_SYMBOL(xor_blocks);
|
||||
|
||||
/* Set of all registered templates. */
|
||||
@@ -95,7 +116,11 @@ do_xor_speed(struct xor_block_template *
|
||||
speed / 1000, speed % 1000);
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_CNS3XXX_RAID
|
||||
+int
|
||||
+#else
|
||||
static int __init
|
||||
+#endif /* CONFIG_CNS3XXX_RAID */
|
||||
calibrate_xor_blocks(void)
|
||||
{
|
||||
void *b1, *b2;
|
||||
@@ -139,7 +164,10 @@ calibrate_xor_blocks(void)
|
||||
if (f->speed > fastest->speed)
|
||||
fastest = f;
|
||||
}
|
||||
-
|
||||
+#ifdef CONFIG_CNS3XXX_RAID
|
||||
+ /* preferred */
|
||||
+ fastest = template_list;
|
||||
+#endif /* CONFIG_CNS3XXX_RAID */
|
||||
printk(KERN_INFO "xor: using function: %s (%d.%03d MB/sec)\n",
|
||||
fastest->name, fastest->speed / 1000, fastest->speed % 1000);
|
||||
|
||||
@@ -151,10 +179,20 @@ calibrate_xor_blocks(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static __exit void xor_exit(void) { }
|
||||
+#ifndef CONFIG_CNS3XXX_RAID
|
||||
+static __exit void xor_exit(void)
|
||||
+{
|
||||
+}
|
||||
+#endif /* ! CONFIG_CNS3XXX_RAID */
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
+#ifdef CONFIG_CNS3XXX_RAID
|
||||
+/*
|
||||
+ * Calibrate in R5 init.
|
||||
+ */
|
||||
+#else
|
||||
/* when built-in xor.o must initialize before drivers/md/md.o */
|
||||
core_initcall(calibrate_xor_blocks);
|
||||
module_exit(xor_exit);
|
||||
+#endif /* ! CONFIG_CNS3XXX_RAID */
|
||||
--- a/drivers/md/Makefile
|
||||
+++ b/drivers/md/Makefile
|
||||
@@ -17,7 +17,7 @@ raid6_pq-y += raid6algos.o raid6recov.o
|
||||
raid6int8.o raid6int16.o raid6int32.o \
|
||||
raid6altivec1.o raid6altivec2.o raid6altivec4.o \
|
||||
raid6altivec8.o \
|
||||
- raid6mmx.o raid6sse1.o raid6sse2.o
|
||||
+ raid6mmx.o raid6sse1.o raid6sse2.o raid6cns.o
|
||||
hostprogs-y += mktables
|
||||
|
||||
# Note: link order is important. All raid personalities
|
||||
--- a/drivers/md/raid5.c
|
||||
+++ b/drivers/md/raid5.c
|
||||
@@ -1817,11 +1817,30 @@ static void compute_block_2(struct strip
|
||||
compute_parity6(sh, UPDATE_PARITY);
|
||||
return;
|
||||
} else {
|
||||
+#ifdef CONFIG_CNS3XXX_RAID
|
||||
+ void *ptrs[disks];
|
||||
+
|
||||
+ count = 0;
|
||||
+ i = d0_idx;
|
||||
+ do {
|
||||
+ ptrs[count++] = page_address(sh->dev[i].page);
|
||||
+ i = raid6_next_disk(i, disks);
|
||||
+ if (i != dd_idx1 && i != dd_idx2 &&
|
||||
+ !test_bit(R5_UPTODATE, &sh->dev[i].flags))
|
||||
+ printk
|
||||
+ ("compute_2 with missing block %d/%d\n",
|
||||
+ count, i);
|
||||
+ } while (i != d0_idx);
|
||||
+
|
||||
+ raid6_dataq_recov(disks, STRIPE_SIZE, faila, ptrs);
|
||||
+#else
|
||||
+
|
||||
/* We're missing D+Q; recompute D from P */
|
||||
compute_block_1(sh, ((dd_idx1 == sh->qd_idx) ?
|
||||
dd_idx2 : dd_idx1),
|
||||
0);
|
||||
compute_parity6(sh, UPDATE_PARITY); /* Is this necessary? */
|
||||
+#endif /* CONFIG_CNS3XXX_RAID */
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -5412,8 +5431,21 @@ static struct mdk_personality raid4_pers
|
||||
.quiesce = raid5_quiesce,
|
||||
};
|
||||
|
||||
+#ifdef CONFIG_CNS3XXX_RAID
|
||||
+extern int calibrate_xor_blocks(void);
|
||||
+#endif /* CONFIG_CNS3XXX_RAID */
|
||||
+
|
||||
static int __init raid5_init(void)
|
||||
{
|
||||
+
|
||||
+#ifdef CONFIG_CNS3XXX_RAID
|
||||
+ /* Just execute calibrate xor blocks */
|
||||
+ int e;
|
||||
+ e = calibrate_xor_blocks();
|
||||
+ if (e)
|
||||
+ return e;
|
||||
+#endif /* CONFIG_CNS3XXX_RAID */
|
||||
+
|
||||
register_md_personality(&raid6_personality);
|
||||
register_md_personality(&raid5_personality);
|
||||
register_md_personality(&raid4_personality);
|
||||
--- a/drivers/md/raid6algos.c
|
||||
+++ b/drivers/md/raid6algos.c
|
||||
@@ -49,6 +49,9 @@ extern const struct raid6_calls raid6_al
|
||||
extern const struct raid6_calls raid6_altivec2;
|
||||
extern const struct raid6_calls raid6_altivec4;
|
||||
extern const struct raid6_calls raid6_altivec8;
|
||||
+#ifdef CONFIG_CNS3XXX_RAID
|
||||
+extern const struct raid6_calls raid6_cns_raid;
|
||||
+#endif /* CONFIG_CNS3XXX_RAID */
|
||||
|
||||
const struct raid6_calls * const raid6_algos[] = {
|
||||
&raid6_intx1,
|
||||
@@ -78,6 +81,11 @@ const struct raid6_calls * const raid6_a
|
||||
&raid6_altivec4,
|
||||
&raid6_altivec8,
|
||||
#endif
|
||||
+#ifdef CONFIG_CNS3XXX_RAID
|
||||
+ /* CNS3000 HW RAID acceleration */
|
||||
+ &raid6_cns_raid,
|
||||
+#endif /* CONFIG_CNS3XXX_RAID */
|
||||
+
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -125,7 +133,9 @@ int __init raid6_select_algo(void)
|
||||
if ( !(*algo)->valid || (*algo)->valid() ) {
|
||||
perf = 0;
|
||||
|
||||
+#ifndef CONFIG_CNS3XXX_RAID
|
||||
preempt_disable();
|
||||
+#endif
|
||||
j0 = jiffies;
|
||||
while ( (j1 = jiffies) == j0 )
|
||||
cpu_relax();
|
||||
@@ -134,7 +144,9 @@ int __init raid6_select_algo(void)
|
||||
(*algo)->gen_syndrome(disks, PAGE_SIZE, dptrs);
|
||||
perf++;
|
||||
}
|
||||
+#ifndef CONFIG_CNS3XXX_RAID
|
||||
preempt_enable();
|
||||
+#endif
|
||||
|
||||
if ( (*algo)->prefer > bestprefer ||
|
||||
((*algo)->prefer == bestprefer &&
|
||||
--- /dev/null
|
||||
+++ b/drivers/md/raid6cns.c
|
||||
@@ -0,0 +1,38 @@
|
||||
+/*
|
||||
+ * raid6cns.c
|
||||
+ *
|
||||
+ * CNS3xxx xor & gen_syndrome functions
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#ifdef CONFIG_CNS3XXX_RAID
|
||||
+
|
||||
+#include <linux/raid/pq.h>
|
||||
+
|
||||
+extern void do_cns_rdma_gfgen(unsigned int src_no, unsigned int bytes, void **bh_ptr,
|
||||
+ void *p_dst, void *q_dst);
|
||||
+
|
||||
+/**
|
||||
+ * raid6_cnsraid_gen_syndrome - CNSRAID Syndrome Generate
|
||||
+ *
|
||||
+ * @disks: raid disks
|
||||
+ * @bytes: length
|
||||
+ * @ptrs: already arranged stripe ptrs,
|
||||
+ * disk0=[0], diskNNN=[disks-3],
|
||||
+ * P/Q=[z0+1] & [z0+2], or, [disks-2], [disks-1]
|
||||
+ */
|
||||
+static void raid6_cnsraid_gen_syndrome(int disks, size_t bytes, void **ptrs)
|
||||
+{
|
||||
+ do_cns_rdma_gfgen(disks - 2, bytes, ptrs, ptrs[disks-2], ptrs[disks-1]);
|
||||
+}
|
||||
+
|
||||
+const struct raid6_calls raid6_cns_raid = {
|
||||
+ raid6_cnsraid_gen_syndrome, /* callback */
|
||||
+ NULL, /* always valid */
|
||||
+ "CNS-RAID", /* name */
|
||||
+ 1 /* preferred: revise it to "0" to compare/compete with others algos */
|
||||
+};
|
||||
+
|
||||
+EXPORT_SYMBOL(raid6_cns_raid);
|
||||
+
|
||||
+#endif /* CONFIG_CNS3XXX_RAID */
|
||||
--- a/drivers/md/raid6recov.c
|
||||
+++ b/drivers/md/raid6recov.c
|
||||
@@ -20,6 +20,136 @@
|
||||
|
||||
#include <linux/raid/pq.h>
|
||||
|
||||
+#ifdef CONFIG_CNS3XXX_RAID
|
||||
+#define R6_RECOV_PD 1
|
||||
+#define R6_RECOV_DD 2
|
||||
+#define R6_RECOV_DQ 3
|
||||
+extern void do_cns_rdma_gfgen_pd_dd_dq(unsigned int src_no, unsigned int bytes,
|
||||
+ void **bh_ptr, void *w1_dst,
|
||||
+ void *w2_dst, int pd_dd_qd,
|
||||
+ unsigned int w1_idx, unsigned int w2_idx,
|
||||
+ unsigned int *src_idx);
|
||||
+
|
||||
+/**
|
||||
+ * @disks: nr_disks
|
||||
+ * @bytes: len
|
||||
+ * @faila: 1st failed DD
|
||||
+ * @ptrs: ptrs by order {d0, d1, ..., da, ..., dn, P, Q}
|
||||
+ *
|
||||
+ * Desc:
|
||||
+ * new_read_ptrs = {d0, d1, ... dn, Q}
|
||||
+ * dd1 = faila
|
||||
+ * p_dst = P
|
||||
+ */
|
||||
+void raid6_datap_recov(int disks, size_t bytes, int faila, void **ptrs)
|
||||
+{
|
||||
+ int cnt = 0;
|
||||
+ int count = 0;
|
||||
+ void *p_dst, *q;
|
||||
+ void *dd1_dst;
|
||||
+ void *new_read_ptrs[disks - 2];
|
||||
+ unsigned int read_idx[disks - 2];
|
||||
+
|
||||
+ q = ptrs[disks - 1];
|
||||
+ p_dst = ptrs[disks - 2];
|
||||
+ dd1_dst = ptrs[faila];
|
||||
+
|
||||
+ while (cnt < disks) {
|
||||
+ if (cnt != faila && cnt != disks - 2) {
|
||||
+ new_read_ptrs[count] = ptrs[cnt];
|
||||
+ read_idx[count] = cnt;
|
||||
+ count++;
|
||||
+ }
|
||||
+ cnt++;
|
||||
+ }
|
||||
+
|
||||
+ do_cns_rdma_gfgen_pd_dd_dq(disks - 2, bytes,
|
||||
+ new_read_ptrs, p_dst, dd1_dst,
|
||||
+ R6_RECOV_PD, disks - 1, faila + 1, read_idx);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * @disks: nr_disks
|
||||
+ * @bytes: len
|
||||
+ * @faila: 1st failed DD
|
||||
+ * @failb: 2nd failed DD
|
||||
+ * @ptrs: ptrs by order {d0, d1, ..., da, ..., db, ..., dn, P, Q}
|
||||
+ *
|
||||
+ * Desc:
|
||||
+ * new_read_ptrs = {d0, d1, ... dn, P, Q}
|
||||
+ * dd1_dst = faila
|
||||
+ * dd2_dst = failb
|
||||
+ */
|
||||
+void raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
|
||||
+ void **ptrs)
|
||||
+{
|
||||
+
|
||||
+ int cnt = 0;
|
||||
+ int count = 0;
|
||||
+ void *p, *q;
|
||||
+ void *dd1_dst, *dd2_dst;
|
||||
+ void *new_read_ptrs[disks - 2];
|
||||
+ unsigned int read_idx[disks - 2];
|
||||
+
|
||||
+ q = ptrs[disks - 1];
|
||||
+ p = ptrs[disks - 2];
|
||||
+ dd1_dst = ptrs[faila];
|
||||
+ dd2_dst = ptrs[failb];
|
||||
+
|
||||
+ while (cnt < disks) {
|
||||
+ if (cnt != faila && cnt != failb) {
|
||||
+ new_read_ptrs[count] = ptrs[cnt];
|
||||
+ read_idx[count] = cnt;
|
||||
+ count++;
|
||||
+ }
|
||||
+ cnt++;
|
||||
+ }
|
||||
+
|
||||
+ do_cns_rdma_gfgen_pd_dd_dq(disks - 2, bytes,
|
||||
+ new_read_ptrs, dd1_dst, dd2_dst,
|
||||
+ R6_RECOV_DD, faila + 1, failb + 1, read_idx);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * @disks: nr_disks
|
||||
+ * @bytes: len
|
||||
+ * @faila: 1st failed DD
|
||||
+ * @ptrs: ptrs by order {d0, d1, ..., da, ..., dn, P, Q}
|
||||
+ *
|
||||
+ * Desc:
|
||||
+ * new_read_ptrs = {d0, d1, ... dn, P}
|
||||
+ * dd1 = faila
|
||||
+ * q_dst = Q
|
||||
+ */
|
||||
+void raid6_dataq_recov(int disks, size_t bytes, int faila, void **ptrs)
|
||||
+{
|
||||
+ int cnt = 0;
|
||||
+ int count = 0;
|
||||
+ void *q_dst, *p;
|
||||
+ void *dd1_dst;
|
||||
+ void *new_read_ptrs[disks - 2];
|
||||
+ unsigned int read_idx[disks - 2];
|
||||
+
|
||||
+ p = ptrs[disks - 2];
|
||||
+ q_dst = ptrs[disks - 1];
|
||||
+ dd1_dst = ptrs[faila];
|
||||
+
|
||||
+ while (cnt < disks) {
|
||||
+ if (cnt != faila && cnt != disks - 1) {
|
||||
+ new_read_ptrs[count] = ptrs[cnt];
|
||||
+ read_idx[count] = cnt;
|
||||
+ count++;
|
||||
+ }
|
||||
+ cnt++;
|
||||
+ }
|
||||
+
|
||||
+ do_cns_rdma_gfgen_pd_dd_dq(disks - 2, bytes,
|
||||
+ new_read_ptrs, dd1_dst, q_dst,
|
||||
+ R6_RECOV_DQ, faila + 1, disks, read_idx);
|
||||
+}
|
||||
+
|
||||
+#else /* CONFIG_CNS3XXX_RAID
|
||||
+
|
||||
/* Recover two failed data blocks. */
|
||||
void raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
|
||||
void **ptrs)
|
||||
@@ -96,6 +226,7 @@ void raid6_datap_recov(int disks, size_t
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(raid6_datap_recov);
|
||||
+#endif /* CONFIG_CNS3XXX_RAID */
|
||||
|
||||
#ifndef __KERNEL__
|
||||
/* Testing only */
|
||||
--- a/include/linux/raid/pq.h
|
||||
+++ b/include/linux/raid/pq.h
|
||||
@@ -100,6 +100,9 @@ void raid6_2data_recov(int disks, size_t
|
||||
void raid6_datap_recov(int disks, size_t bytes, int faila, void **ptrs);
|
||||
void raid6_dual_recov(int disks, size_t bytes, int faila, int failb,
|
||||
void **ptrs);
|
||||
+#ifdef CONFIG_CNS3XXX_RAID
|
||||
+void raid6_dataq_recov(int disks, size_t bytes, int faila, void **ptrs);
|
||||
+#endif /* CONFIG_CNS3XXX_RAID */
|
||||
|
||||
/* Some definitions to allow code to be compiled for testing in userspace */
|
||||
#ifndef __KERNEL__
|
||||
--- a/include/linux/raid/xor.h
|
||||
+++ b/include/linux/raid/xor.h
|
||||
@@ -1,7 +1,11 @@
|
||||
#ifndef _XOR_H
|
||||
#define _XOR_H
|
||||
|
||||
+#ifdef CONFIG_CNS3XXX_RAID
|
||||
+#define MAX_XOR_BLOCKS 32
|
||||
+#else
|
||||
#define MAX_XOR_BLOCKS 4
|
||||
+#endif /* CONFIG_CNS3XXX_RAID */
|
||||
|
||||
extern void xor_blocks(unsigned int count, unsigned int bytes,
|
||||
void *dest, void **srcs);
|
||||
--- a/mm/mempool.c
|
||||
+++ b/mm/mempool.c
|
||||
@@ -250,6 +250,28 @@ repeat_alloc:
|
||||
}
|
||||
EXPORT_SYMBOL(mempool_alloc);
|
||||
|
||||
+#ifdef CONFIG_CNS3XXX_RAID
|
||||
+/**
|
||||
+ * acs_mempool_alloc - allocate an element from a specific memory pool
|
||||
+ * @pool: pointer to the memory pool which was allocated via
|
||||
+ * mempool_create().
|
||||
+ *
|
||||
+ * this function differs from mempool_alloc by directly allocating an element
|
||||
+ * from @pool without calling @pool->alloc().
|
||||
+ */
|
||||
+void *acs_mempool_alloc(mempool_t * pool)
|
||||
+{
|
||||
+ unsigned long flags;
|
||||
+ void *element = NULL;
|
||||
+
|
||||
+ spin_lock_irqsave(&pool->lock, flags);
|
||||
+ if (likely(pool->curr_nr))
|
||||
+ element = remove_element(pool);
|
||||
+ spin_unlock_irqrestore(&pool->lock, flags);
|
||||
+ return element;
|
||||
+}
|
||||
+#endif /* CONFIG_CNS3XXX_RAID */
|
||||
+
|
||||
/**
|
||||
* mempool_free - return an element to the pool.
|
||||
* @element: pool element pointer.
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,496 +0,0 @@
|
|||
--- /dev/null
|
||||
+++ b/drivers/watchdog/cns3xxx_wdt.c
|
||||
@@ -0,0 +1,465 @@
|
||||
+/*******************************************************************************
|
||||
+ *
|
||||
+ * drivers/watchdog/cns3xxx_wdt.c
|
||||
+ *
|
||||
+ * Watchdog timer driver for the CNS3XXX SOCs
|
||||
+ *
|
||||
+ * Author: Scott Shu
|
||||
+ *
|
||||
+ * Copyright (c) 2008 Cavium Networks
|
||||
+ *
|
||||
+ * This file is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License, Version 2, as
|
||||
+ * published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This file is distributed in the hope that it will be useful,
|
||||
+ * but AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
|
||||
+ * NONINFRINGEMENT. See the GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this file; if not, write to the Free Software
|
||||
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA or
|
||||
+ * visit http://www.gnu.org/licenses/.
|
||||
+ *
|
||||
+ * This file may also be available under a different license from Cavium.
|
||||
+ * Contact Cavium Networks for more information
|
||||
+ *
|
||||
+ ******************************************************************************/
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/moduleparam.h>
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/miscdevice.h>
|
||||
+#include <linux/watchdog.h>
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/reboot.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/uaccess.h>
|
||||
+
|
||||
+#include <asm/hardware/arm_twd.h>
|
||||
+
|
||||
+struct cns3xxx_wdt {
|
||||
+ unsigned long timer_alive;
|
||||
+ struct device *dev;
|
||||
+ void __iomem *base;
|
||||
+ int irq;
|
||||
+ unsigned int perturb;
|
||||
+ char expect_close;
|
||||
+};
|
||||
+
|
||||
+static struct platform_device *cns3xxx_wdt_dev;
|
||||
+extern unsigned int twd_timer_rate;
|
||||
+static spinlock_t wdt_lock;
|
||||
+
|
||||
+#define TIMER_MARGIN 60
|
||||
+static int cns3xxx_margin = TIMER_MARGIN;
|
||||
+module_param(cns3xxx_margin, int, 0);
|
||||
+MODULE_PARM_DESC(cns3xxx_margin,
|
||||
+ "CNS3XXX timer margin in seconds. (0 < cns3xxx_margin < 65536, default="
|
||||
+ __MODULE_STRING(TIMER_MARGIN) ")");
|
||||
+
|
||||
+static int nowayout = WATCHDOG_NOWAYOUT;
|
||||
+module_param(nowayout, int, 0);
|
||||
+MODULE_PARM_DESC(nowayout,
|
||||
+ "Watchdog cannot be stopped once started (default="
|
||||
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
|
||||
+
|
||||
+#define ONLY_TESTING 0
|
||||
+static int cns3xxx_noboot = ONLY_TESTING;
|
||||
+module_param(cns3xxx_noboot, int, 0);
|
||||
+MODULE_PARM_DESC(cns3xxx_noboot, "CNS3XXX watchdog action, "
|
||||
+ "set to 1 to ignore reboots, 0 to reboot (default="
|
||||
+ __MODULE_STRING(ONLY_TESTING) ")");
|
||||
+
|
||||
+/*
|
||||
+ * This is the interrupt handler. Note that we only use this
|
||||
+ * in testing mode, so don't actually do a reboot here.
|
||||
+ */
|
||||
+static irqreturn_t cns3xxx_wdt_fire(int irq, void *arg)
|
||||
+{
|
||||
+ struct cns3xxx_wdt *wdt = arg;
|
||||
+
|
||||
+ /* Check it really was our interrupt */
|
||||
+ if (readl(wdt->base + TWD_WDOG_INTSTAT)) {
|
||||
+ dev_printk(KERN_CRIT, wdt->dev,
|
||||
+ "Triggered - Reboot ignored.\n");
|
||||
+ /* Clear the interrupt on the watchdog */
|
||||
+ writel(1, wdt->base + TWD_WDOG_INTSTAT);
|
||||
+ return IRQ_HANDLED;
|
||||
+ }
|
||||
+ return IRQ_NONE;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * cns3xxx_wdt_keepalive - reload the timer
|
||||
+ *
|
||||
+ * Note that the spec says a DIFFERENT value must be written to the reload
|
||||
+ * register each time. The "perturb" variable deals with this by adding 1
|
||||
+ * to the count every other time the function is called.
|
||||
+ */
|
||||
+static void cns3xxx_wdt_keepalive(struct cns3xxx_wdt *wdt)
|
||||
+{
|
||||
+ unsigned int count;
|
||||
+
|
||||
+ /* Assume prescale is set to 256 */
|
||||
+ count = (twd_timer_rate / 256) * cns3xxx_margin;
|
||||
+
|
||||
+ /* Reload the counter */
|
||||
+ spin_lock(&wdt_lock);
|
||||
+ writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD);
|
||||
+ wdt->perturb = wdt->perturb ? 0 : 1;
|
||||
+ spin_unlock(&wdt_lock);
|
||||
+}
|
||||
+
|
||||
+static void cns3xxx_wdt_stop(struct cns3xxx_wdt *wdt)
|
||||
+{
|
||||
+ spin_lock(&wdt_lock);
|
||||
+ writel(0x12345678, wdt->base + TWD_WDOG_DISABLE);
|
||||
+ writel(0x87654321, wdt->base + TWD_WDOG_DISABLE);
|
||||
+ writel(0x0, wdt->base + TWD_WDOG_CONTROL);
|
||||
+ spin_unlock(&wdt_lock);
|
||||
+}
|
||||
+
|
||||
+static void cns3xxx_wdt_start(struct cns3xxx_wdt *wdt)
|
||||
+{
|
||||
+ dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n");
|
||||
+
|
||||
+ //spin_lock(&wdt_lock);
|
||||
+ /* This loads the count register but does NOT start the count yet */
|
||||
+ cns3xxx_wdt_keepalive(wdt);
|
||||
+ spin_lock(&wdt_lock);
|
||||
+
|
||||
+ if (cns3xxx_noboot) {
|
||||
+ /* Enable watchdog - prescale=256, watchdog mode=0, enable=1 */
|
||||
+ writel(0x0000FF01, wdt->base + TWD_WDOG_CONTROL);
|
||||
+ } else {
|
||||
+ /* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */
|
||||
+ writel(0x0000FF09, wdt->base + TWD_WDOG_CONTROL);
|
||||
+ }
|
||||
+ spin_unlock(&wdt_lock);
|
||||
+}
|
||||
+
|
||||
+static int cns3xxx_wdt_set_heartbeat(int t)
|
||||
+{
|
||||
+ if (t < 0x0001 || t > 0xFFFF)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ cns3xxx_margin = t;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * /dev/watchdog handling
|
||||
+ */
|
||||
+static int cns3xxx_wdt_open(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ struct cns3xxx_wdt *wdt = platform_get_drvdata(cns3xxx_wdt_dev);
|
||||
+
|
||||
+ if (test_and_set_bit(0, &wdt->timer_alive))
|
||||
+ return -EBUSY;
|
||||
+
|
||||
+ if (nowayout)
|
||||
+ __module_get(THIS_MODULE);
|
||||
+
|
||||
+ file->private_data = wdt;
|
||||
+
|
||||
+ /*
|
||||
+ * Activate timer
|
||||
+ */
|
||||
+ cns3xxx_wdt_start(wdt);
|
||||
+
|
||||
+ return nonseekable_open(inode, file);
|
||||
+}
|
||||
+
|
||||
+static int cns3xxx_wdt_release(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ struct cns3xxx_wdt *wdt = file->private_data;
|
||||
+
|
||||
+ /*
|
||||
+ * Shut off the timer.
|
||||
+ * Lock it in if it's a module and we set nowayout
|
||||
+ */
|
||||
+ if (wdt->expect_close == 42)
|
||||
+ cns3xxx_wdt_stop(wdt);
|
||||
+ else {
|
||||
+ dev_printk(KERN_CRIT, wdt->dev,
|
||||
+ "unexpected close, not stopping watchdog!\n");
|
||||
+ cns3xxx_wdt_keepalive(wdt);
|
||||
+ }
|
||||
+ clear_bit(0, &wdt->timer_alive);
|
||||
+ wdt->expect_close = 0;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static ssize_t cns3xxx_wdt_write(struct file *file, const char *data,
|
||||
+ size_t len, loff_t *ppos)
|
||||
+{
|
||||
+ struct cns3xxx_wdt *wdt = file->private_data;
|
||||
+
|
||||
+ /*
|
||||
+ * Refresh the timer.
|
||||
+ */
|
||||
+ if (len) {
|
||||
+ if (!nowayout) {
|
||||
+ size_t i;
|
||||
+
|
||||
+ /* In case it was set long ago */
|
||||
+ wdt->expect_close = 0;
|
||||
+
|
||||
+ for (i = 0; i != len; i++) {
|
||||
+ char c;
|
||||
+
|
||||
+ if (get_user(c, data + i))
|
||||
+ return -EFAULT;
|
||||
+ if (c == 'V')
|
||||
+ wdt->expect_close = 42;
|
||||
+ }
|
||||
+ }
|
||||
+ cns3xxx_wdt_keepalive(wdt);
|
||||
+ }
|
||||
+ return len;
|
||||
+}
|
||||
+
|
||||
+static struct watchdog_info ident = {
|
||||
+ .options = WDIOF_SETTIMEOUT |
|
||||
+ WDIOF_KEEPALIVEPING |
|
||||
+ WDIOF_MAGICCLOSE,
|
||||
+ .identity = "CNS3XXX Watchdog",
|
||||
+};
|
||||
+
|
||||
+static long cns3xxx_wdt_ioctl(struct file *file, unsigned int cmd,
|
||||
+ unsigned long arg)
|
||||
+{
|
||||
+ struct cns3xxx_wdt *wdt = file->private_data;
|
||||
+ int ret;
|
||||
+ union {
|
||||
+ struct watchdog_info ident;
|
||||
+ int i;
|
||||
+ } uarg;
|
||||
+
|
||||
+ if (_IOC_DIR(cmd) && _IOC_SIZE(cmd) > sizeof(uarg))
|
||||
+ return -ENOTTY;
|
||||
+
|
||||
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
|
||||
+ ret = copy_from_user(&uarg, (void __user *)arg, _IOC_SIZE(cmd));
|
||||
+ if (ret)
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case WDIOC_GETSUPPORT:
|
||||
+ uarg.ident = ident;
|
||||
+ ret = 0;
|
||||
+ break;
|
||||
+
|
||||
+ case WDIOC_GETSTATUS:
|
||||
+ case WDIOC_GETBOOTSTATUS:
|
||||
+ uarg.i = 0;
|
||||
+ ret = 0;
|
||||
+ break;
|
||||
+
|
||||
+ case WDIOC_SETOPTIONS:
|
||||
+ ret = -EINVAL;
|
||||
+ if (uarg.i & WDIOS_DISABLECARD) {
|
||||
+ cns3xxx_wdt_stop(wdt);
|
||||
+ ret = 0;
|
||||
+ }
|
||||
+ if (uarg.i & WDIOS_ENABLECARD) {
|
||||
+ cns3xxx_wdt_start(wdt);
|
||||
+ ret = 0;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case WDIOC_KEEPALIVE:
|
||||
+ cns3xxx_wdt_keepalive(wdt);
|
||||
+ ret = 0;
|
||||
+ break;
|
||||
+
|
||||
+ case WDIOC_SETTIMEOUT:
|
||||
+ ret = cns3xxx_wdt_set_heartbeat(uarg.i);
|
||||
+ if (ret)
|
||||
+ break;
|
||||
+
|
||||
+ cns3xxx_wdt_keepalive(wdt);
|
||||
+ /* Fall */
|
||||
+ case WDIOC_GETTIMEOUT:
|
||||
+ uarg.i = cns3xxx_margin;
|
||||
+ ret = 0;
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ return -ENOTTY;
|
||||
+ }
|
||||
+
|
||||
+ if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
|
||||
+ ret = copy_to_user((void __user *)arg, &uarg, _IOC_SIZE(cmd));
|
||||
+ if (ret)
|
||||
+ ret = -EFAULT;
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * System shutdown handler. Turn off the watchdog if we're
|
||||
+ * restarting or halting the system.
|
||||
+ */
|
||||
+static void cns3xxx_wdt_shutdown(struct platform_device *dev)
|
||||
+{
|
||||
+ struct cns3xxx_wdt *wdt = platform_get_drvdata(dev);
|
||||
+
|
||||
+ if (system_state == SYSTEM_RESTART || system_state == SYSTEM_HALT)
|
||||
+ cns3xxx_wdt_stop(wdt);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Kernel Interfaces
|
||||
+ */
|
||||
+static const struct file_operations cns3xxx_wdt_fops = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .llseek = no_llseek,
|
||||
+ .write = cns3xxx_wdt_write,
|
||||
+ .unlocked_ioctl = cns3xxx_wdt_ioctl,
|
||||
+ .open = cns3xxx_wdt_open,
|
||||
+ .release = cns3xxx_wdt_release,
|
||||
+};
|
||||
+
|
||||
+static struct miscdevice cns3xxx_wdt_miscdev = {
|
||||
+ .minor = WATCHDOG_MINOR,
|
||||
+ .name = "watchdog",
|
||||
+ .fops = &cns3xxx_wdt_fops,
|
||||
+};
|
||||
+
|
||||
+static int __devinit cns3xxx_wdt_probe(struct platform_device *dev)
|
||||
+{
|
||||
+ struct cns3xxx_wdt *wdt;
|
||||
+ struct resource *res;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* We only accept one device, and it must have an id of -1 */
|
||||
+ if (dev->id != -1)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
+ if (!res) {
|
||||
+ ret = -ENODEV;
|
||||
+ goto err_out;
|
||||
+ }
|
||||
+
|
||||
+ wdt = kzalloc(sizeof(struct cns3xxx_wdt), GFP_KERNEL);
|
||||
+ if (!wdt) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto err_out;
|
||||
+ }
|
||||
+
|
||||
+ wdt->dev = &dev->dev;
|
||||
+ wdt->irq = platform_get_irq(dev, 0);
|
||||
+ if (wdt->irq < 0) {
|
||||
+ ret = -ENXIO;
|
||||
+ goto err_free;
|
||||
+ }
|
||||
+ wdt->base = ioremap(res->start, res->end - res->start + 1);
|
||||
+ if (!wdt->base) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto err_free;
|
||||
+ }
|
||||
+
|
||||
+ cns3xxx_wdt_miscdev.parent = &dev->dev;
|
||||
+ ret = misc_register(&cns3xxx_wdt_miscdev);
|
||||
+ if (ret) {
|
||||
+ dev_printk(KERN_ERR, wdt->dev,
|
||||
+ "cannot register miscdev on minor=%d (err=%d)\n",
|
||||
+ WATCHDOG_MINOR, ret);
|
||||
+ goto err_misc;
|
||||
+ }
|
||||
+
|
||||
+ ret = request_irq(wdt->irq, cns3xxx_wdt_fire, IRQF_DISABLED,
|
||||
+ dev->name, wdt);
|
||||
+ if (ret) {
|
||||
+ dev_printk(KERN_ERR, wdt->dev,
|
||||
+ "cannot register IRQ%d for watchdog\n", wdt->irq);
|
||||
+ goto err_irq;
|
||||
+ }
|
||||
+
|
||||
+ cns3xxx_wdt_stop(wdt);
|
||||
+ platform_set_drvdata(dev, wdt);
|
||||
+ cns3xxx_wdt_dev = dev;
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_irq:
|
||||
+ misc_deregister(&cns3xxx_wdt_miscdev);
|
||||
+err_misc:
|
||||
+ platform_set_drvdata(dev, NULL);
|
||||
+ iounmap(wdt->base);
|
||||
+err_free:
|
||||
+ kfree(wdt);
|
||||
+err_out:
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int __devexit cns3xxx_wdt_remove(struct platform_device *dev)
|
||||
+{
|
||||
+ struct cns3xxx_wdt *wdt = platform_get_drvdata(dev);
|
||||
+
|
||||
+ platform_set_drvdata(dev, NULL);
|
||||
+
|
||||
+ misc_deregister(&cns3xxx_wdt_miscdev);
|
||||
+
|
||||
+ cns3xxx_wdt_dev = NULL;
|
||||
+
|
||||
+ free_irq(wdt->irq, wdt);
|
||||
+ iounmap(wdt->base);
|
||||
+ kfree(wdt);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static struct platform_driver cns3xxx_wdt_driver = {
|
||||
+ .probe = cns3xxx_wdt_probe,
|
||||
+ .remove = __devexit_p(cns3xxx_wdt_remove),
|
||||
+ .shutdown = cns3xxx_wdt_shutdown,
|
||||
+ .driver = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .name = "cns3xxx-wdt",
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static char banner[] __initdata = KERN_INFO
|
||||
+ "CNS3XXX Watchdog Timer, noboot=%d margin=%d sec (nowayout= %d)\n";
|
||||
+
|
||||
+static int __init cns3xxx_wdt_init(void)
|
||||
+{
|
||||
+ /*
|
||||
+ * Check that the margin value is within it's range;
|
||||
+ * if not reset to the default
|
||||
+ */
|
||||
+ if (cns3xxx_wdt_set_heartbeat(cns3xxx_margin)) {
|
||||
+ cns3xxx_wdt_set_heartbeat(TIMER_MARGIN);
|
||||
+ printk(KERN_INFO "cns3xxx_margin value must be 0 < cns3xxx_margin < 65536, using %d\n",
|
||||
+ TIMER_MARGIN);
|
||||
+ }
|
||||
+
|
||||
+ printk(banner, cns3xxx_noboot, cns3xxx_margin, nowayout);
|
||||
+
|
||||
+ spin_lock_init(&wdt_lock);
|
||||
+
|
||||
+ return platform_driver_register(&cns3xxx_wdt_driver);
|
||||
+}
|
||||
+
|
||||
+static void __exit cns3xxx_wdt_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&cns3xxx_wdt_driver);
|
||||
+}
|
||||
+
|
||||
+module_init(cns3xxx_wdt_init);
|
||||
+module_exit(cns3xxx_wdt_exit);
|
||||
+
|
||||
+MODULE_AUTHOR("Scott Shu");
|
||||
+MODULE_DESCRIPTION("CNS3XXX Watchdog Device Driver");
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
|
||||
+MODULE_ALIAS("platform:cns3xxx-wdt");
|
||||
--- a/drivers/watchdog/Kconfig
|
||||
+++ b/drivers/watchdog/Kconfig
|
||||
@@ -231,6 +231,15 @@ config DAVINCI_WATCHDOG
|
||||
NOTE: once enabled, this timer cannot be disabled.
|
||||
Say N if you are unsure.
|
||||
|
||||
+config CNS3XXX_WATCHDOG
|
||||
+ tristate "CNS3XXX watchdog"
|
||||
+ depends on ARCH_CNS3XXX && LOCAL_TIMERS
|
||||
+ help
|
||||
+ Watchdog timer embedded into the CNS3XXX SoCs system.
|
||||
+
|
||||
+ To compile this driver as a module, choose M here: the
|
||||
+ module will be called cns3xxx_wdt.
|
||||
+
|
||||
config ORION_WATCHDOG
|
||||
tristate "Orion watchdog"
|
||||
depends on ARCH_ORION5X || ARCH_KIRKWOOD
|
||||
--- a/drivers/watchdog/Makefile
|
||||
+++ b/drivers/watchdog/Makefile
|
||||
@@ -41,6 +41,7 @@ obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_
|
||||
obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
|
||||
obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
|
||||
obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
|
||||
+obj-$(CONFIG_CNS3XXX_WATCHDOG) += cns3xxx_wdt.o
|
||||
obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o
|
||||
obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
|
||||
obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o
|
|
@ -1,39 +0,0 @@
|
|||
--- a/drivers/serial/8250.c
|
||||
+++ b/drivers/serial/8250.c
|
||||
@@ -1743,6 +1743,7 @@ static void serial8250_backup_timeout(un
|
||||
unsigned int iir, ier = 0, lsr;
|
||||
unsigned long flags;
|
||||
|
||||
+ spin_lock_irqsave(&up->port.lock, flags);
|
||||
/*
|
||||
* Must disable interrupts or else we risk racing with the interrupt
|
||||
* based handler.
|
||||
@@ -1760,10 +1761,8 @@ static void serial8250_backup_timeout(un
|
||||
* the "Diva" UART used on the management processor on many HP
|
||||
* ia64 and parisc boxes.
|
||||
*/
|
||||
- spin_lock_irqsave(&up->port.lock, flags);
|
||||
lsr = serial_in(up, UART_LSR);
|
||||
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
|
||||
- spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
|
||||
(!uart_circ_empty(&up->port.info->xmit) || up->port.x_char) &&
|
||||
(lsr & UART_LSR_THRE)) {
|
||||
@@ -1771,12 +1770,14 @@ static void serial8250_backup_timeout(un
|
||||
iir |= UART_IIR_THRI;
|
||||
}
|
||||
|
||||
- if (!(iir & UART_IIR_NO_INT))
|
||||
- serial8250_handle_port(up);
|
||||
-
|
||||
if (is_real_interrupt(up->port.irq))
|
||||
serial_out(up, UART_IER, ier);
|
||||
|
||||
+ spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
+
|
||||
+ if (!(iir & UART_IIR_NO_INT))
|
||||
+ serial8250_handle_port(up);
|
||||
+
|
||||
/* Standard timer interval plus 0.2s to keep the port running */
|
||||
mod_timer(&up->timer,
|
||||
jiffies + poll_timeout(up->port.timeout) + HZ / 5);
|
|
@ -1,21 +0,0 @@
|
|||
--- a/arch/arm/include/asm/dma-mapping.h
|
||||
+++ b/arch/arm/include/asm/dma-mapping.h
|
||||
@@ -350,7 +350,8 @@ static inline dma_addr_t dma_map_page(st
|
||||
static inline void dma_unmap_single(struct device *dev, dma_addr_t handle,
|
||||
size_t size, enum dma_data_direction dir)
|
||||
{
|
||||
- /* nothing to do */
|
||||
+ if (dir != DMA_TO_DEVICE)
|
||||
+ dma_cache_maint(dma_to_virt(dev, handle), size, DMA_FROM_DEVICE);
|
||||
}
|
||||
#endif /* CONFIG_DMABOUNCE */
|
||||
|
||||
@@ -398,6 +399,8 @@ static inline void dma_sync_single_range
|
||||
{
|
||||
BUG_ON(!valid_dma_direction(dir));
|
||||
|
||||
+ if (dir != DMA_TO_DEVICE)
|
||||
+ dma_cache_maint(dma_to_virt(dev, handle) + offset, size, DMA_FROM_DEVICE);
|
||||
dmabounce_sync_for_cpu(dev, handle, offset, size, dir);
|
||||
}
|
||||
|
Loading…
Reference in New Issue