From fb86ec51406a414974a44138c8f194054c10dd52 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Wed, 2 Jun 2004 03:10:52 -0700 Subject: [Driver Model] Consolidate attribute definition macros - Create __ATTR(), __ATTR_RO(), and __ATTR_NULL macros to help define attributes in a neat, short-hand form. - Apply these macros to the attribute definition in include/linux/device.h - Note: These can be used to more cleanly define attributes in your own code. e.g: static struct device_attribute attrs[] = { __ATTR_RO(foo), __ATTR_RO(bar), __ATTR(baz,0666,baz_show,baz_store), __ATTR_NULL, }; ...etc. Signed-off-by: Greg Kroah-Hartman --- include/linux/device.h | 31 ++++++------------------------- include/linux/sysfs.h | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/include/linux/device.h b/include/linux/device.h index 2b8b3d636889..e125402c948e 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -90,11 +90,7 @@ struct bus_attribute { }; #define BUS_ATTR(_name,_mode,_show,_store) \ -struct bus_attribute bus_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ - .show = _show, \ - .store = _store, \ -}; +struct bus_attribute bus_attr_##_name = __ATTR(_name,_mode,_show,_store) extern int bus_create_file(struct bus_type *, struct bus_attribute *); extern void bus_remove_file(struct bus_type *, struct bus_attribute *); @@ -131,11 +127,7 @@ struct driver_attribute { }; #define DRIVER_ATTR(_name,_mode,_show,_store) \ -struct driver_attribute driver_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ - .show = _show, \ - .store = _store, \ -}; +struct driver_attribute driver_attr_##_name = __ATTR(_name,_mode,_show,_store) extern int driver_create_file(struct device_driver *, struct driver_attribute *); extern void driver_remove_file(struct device_driver *, struct driver_attribute *); @@ -172,11 +164,7 @@ struct class_attribute { }; #define CLASS_ATTR(_name,_mode,_show,_store) \ -struct class_attribute class_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ - .show = _show, \ - .store = _store, \ -}; +struct class_attribute class_attr_##_name = __ATTR(_name,_mode,_show,_store) extern int class_create_file(struct class *, const struct class_attribute *); extern void class_remove_file(struct class *, const struct class_attribute *); @@ -224,11 +212,8 @@ struct class_device_attribute { }; #define CLASS_DEVICE_ATTR(_name,_mode,_show,_store) \ -struct class_device_attribute class_device_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ - .show = _show, \ - .store = _store, \ -}; +struct class_device_attribute class_device_attr_##_name = \ + __ATTR(_name,_mode,_show,_store) extern int class_device_create_file(struct class_device *, const struct class_device_attribute *); @@ -342,11 +327,7 @@ struct device_attribute { }; #define DEVICE_ATTR(_name,_mode,_show,_store) \ -struct device_attribute dev_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ - .show = _show, \ - .store = _store, \ -}; +struct device_attribute dev_attr_##_name = __ATTR(_name,_mode,_show,_store) extern int device_create_file(struct device *device, struct device_attribute * entry); diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 4cb54379e85a..2417f2d6dca1 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -24,6 +24,27 @@ struct attribute_group { }; + +/** + * Use these macros to make defining attributes easier. See include/linux/device.h + * for examples.. + */ + +#define __ATTR(_name,_mode,_show,_store) { \ + .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ + .show = _show, \ + .store = _store, \ +} + +#define __ATTR_RO(_name) { \ + .attr = { .name = __stringify(_name), .mode = 0444, .owner = THIS_MODULE }, \ + .show = _name##_show, \ +} + +#define __ATTR_NULL { .attr = { .name = NULL } } + + + struct bin_attribute { struct attribute attr; size_t size; -- cgit v1.2.3 From e62a34fb50f2d4fdba2b22d53c637024b5046d04 Mon Sep 17 00:00:00 2001 From: Pat LaVarre Date: Wed, 2 Jun 2004 13:08:30 -0400 Subject: [PATCH] ata_check_bmdma Move hand-coded BMDMA status check into separate function. --- drivers/scsi/libata-core.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 29dee2c25ba0..f7cf90b9e170 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2145,6 +2145,22 @@ static void ata_pio_task(void *_data) } } +/** + * ata_check_bmdma - read PCI IDE BMDMA status + * @ap: struct ata_port + */ + +static u8 ata_check_bmdma(struct ata_port *ap) +{ + u8 host_stat; + if (ap->flags & ATA_FLAG_MMIO) { + void *mmio = (void *) ap->ioaddr.bmdma_addr; + host_stat = readb(mmio + ATA_DMA_STATUS); + } else + host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + return host_stat; +} + /** * ata_eng_timeout - Handle timeout of queued command * @ap: Port on which timed-out command is active @@ -2188,11 +2204,7 @@ void ata_eng_timeout(struct ata_port *ap) switch (qc->tf.protocol) { case ATA_PROT_DMA: - if (ap->flags & ATA_FLAG_MMIO) { - void *mmio = (void *) ap->ioaddr.bmdma_addr; - host_stat = readb(mmio + ATA_DMA_STATUS); - } else - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + host_stat = ata_check_bmdma(ap); printk(KERN_ERR "ata%u: DMA timeout, stat 0x%x\n", ap->id, host_stat); @@ -2622,11 +2634,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap, /* BMDMA completion */ case ATA_PROT_DMA: case ATA_PROT_ATAPI_DMA: - if (ap->flags & ATA_FLAG_MMIO) { - void *mmio = (void *) ap->ioaddr.bmdma_addr; - host_stat = readb(mmio + ATA_DMA_STATUS); - } else - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + host_stat = ata_check_bmdma(ap); VPRINTK("BUS_DMA (host_stat 0x%X)\n", host_stat); if (!(host_stat & ATA_DMA_INTR)) { -- cgit v1.2.3 From a4e2bce3c68e6ddd22df5cc41295512cd0a3d64f Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Wed, 2 Jun 2004 18:44:34 -0700 Subject: [Driver Model] Fix up silly scsi usage of DEVICE_ATTR() macros. - Hey, just because the macro incorrectly included a ';' doesn't mean one shouldn't add one on their own.. (Or at least be consistent.) Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index fceb6f9a1be1..db109921782b 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -320,7 +320,7 @@ sdev_store_timeout (struct device *dev, const char *buf, size_t count) sdev->timeout = timeout * HZ; return count; } -static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout) +static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout); static ssize_t store_rescan_field (struct device *dev, const char *buf, size_t count) @@ -328,7 +328,7 @@ store_rescan_field (struct device *dev, const char *buf, size_t count) scsi_rescan_device(dev); return count; } -static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field) +static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field); static ssize_t sdev_store_delete(struct device *dev, const char *buf, size_t count) -- cgit v1.2.3 From a7ba0893a36d9b9460a78781178886ae315767c4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 2 Jun 2004 19:48:45 -0700 Subject: Add basic sysfs support for raw devices This is needed by people who use udev and want raw devices. SuSE is shipping with this patch. Signed-off-by: Greg Kroah-Hartman --- drivers/char/raw.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 9c19dbc8eb19..b416bdf57080 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -26,6 +27,7 @@ struct raw_device_data { int inuse; }; +static struct class_simple *raw_class; static struct raw_device_data raw_devices[MAX_RAW_MINORS]; static DECLARE_MUTEX(raw_mutex); static struct file_operations raw_ctl_fops; /* forward declaration */ @@ -123,6 +125,13 @@ raw_ioctl(struct inode *inode, struct file *filp, return ioctl_by_bdev(bdev, command, arg); } +static void bind_device(struct raw_config_request rq) +{ + class_simple_device_remove(MKDEV(RAW_MAJOR, rq.raw_minor)); + class_simple_device_add(raw_class, MKDEV(RAW_MAJOR, rq.raw_minor), + NULL, "raw%d", rq.raw_minor); +} + /* * Deal with ioctls against the raw-device control interface, to bind * and unbind other raw devices. @@ -191,12 +200,15 @@ static int raw_ctl_ioctl(struct inode *inode, struct file *filp, if (rq.block_major == 0 && rq.block_minor == 0) { /* unbind */ rawdev->binding = NULL; + class_simple_device_remove(MKDEV(RAW_MAJOR, rq.raw_minor)); } else { rawdev->binding = bdget(dev); if (rawdev->binding == NULL) err = -ENOMEM; - else + else { __module_get(THIS_MODULE); + bind_device(rq); + } } up(&raw_mutex); } else { @@ -287,6 +299,15 @@ static int __init raw_init(void) goto error; } + raw_class = class_simple_create(THIS_MODULE, "raw"); + if (IS_ERR(raw_class)) { + printk(KERN_ERR "Error creating raw class.\n"); + cdev_del(&raw_cdev); + unregister_chrdev_region(dev, MAX_RAW_MINORS); + goto error; + } + class_simple_device_add(raw_class, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); + devfs_mk_cdev(MKDEV(RAW_MAJOR, 0), S_IFCHR | S_IRUGO | S_IWUGO, "raw/rawctl"); @@ -309,6 +330,8 @@ static void __exit raw_exit(void) devfs_remove("raw/raw%d", i); devfs_remove("raw/rawctl"); devfs_remove("raw"); + class_simple_device_remove(MKDEV(RAW_MAJOR, 0)); + class_simple_destroy(raw_class); cdev_del(&raw_cdev); unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS); } -- cgit v1.2.3 From e33617a4edef44f60a169cb261bd25781341945f Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Wed, 2 Jun 2004 20:27:16 -0700 Subject: [sysfs] Add attr_name() macro - Returns the name of an embedded attribute in a higher-level attribute. --- include/linux/sysfs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 2417f2d6dca1..f94c7ac77c48 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -43,7 +43,7 @@ struct attribute_group { #define __ATTR_NULL { .attr = { .name = NULL } } - +#define attr_name(_attr) (_attr).attr.name struct bin_attribute { struct attribute attr; -- cgit v1.2.3 From 0d1c76a044e8a7234267c11c8fc9661c5a8052c5 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Wed, 2 Jun 2004 20:41:29 -0700 Subject: [Driver Model] Add default attributes for classes class devices. - add struct class::class_attrs, which is designed to point to an array of class_attributes that are added when the class is registered and removed when the class is unregistered. This allows for more consolidated and cleaner definition of and management of attributes. - Add struct class::class_dev_attrs to do something similarly for class devices. Each class device that is registered with the class gets that set of attributes added for them, and subsequently removed when the device is unregistered. Each array depends on a terminating attribute with a NULL name. Hint: use the new __ATTR_NULL macro to terminate it. --- drivers/base/class.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++---- include/linux/device.h | 3 ++ 2 files changed, 78 insertions(+), 6 deletions(-) diff --git a/drivers/base/class.c b/drivers/base/class.c index ed13d9de0d1d..b9973e92f9fa 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -100,6 +100,37 @@ void class_put(struct class * cls) subsys_put(&cls->subsys); } + +static int add_class_attrs(struct class * cls) +{ + int i; + int error = 0; + + if (cls->class_attrs) { + for (i = 0; attr_name(cls->class_attrs[i]); i++) { + error = class_create_file(cls,&cls->class_attrs[i]); + if (error) + goto Err; + } + } + Done: + return error; + Err: + while (--i >= 0) + class_remove_file(cls,&cls->class_attrs[i]); + goto Done; +} + +static void remove_class_attrs(struct class * cls) +{ + int i; + + if (cls->class_attrs) { + for (i = 0; attr_name(cls->class_attrs[i]); i++) + class_remove_file(cls,&cls->class_attrs[i]); + } +} + int class_register(struct class * cls) { int error; @@ -115,18 +146,21 @@ int class_register(struct class * cls) subsys_set_kset(cls,class_subsys); error = subsystem_register(&cls->subsys); - if (error) - return error; - - return 0; + if (!error) { + error = add_class_attrs(class_get(cls)); + class_put(cls); + } + return error; } void class_unregister(struct class * cls) { pr_debug("device class '%s': unregistering\n",cls->name); + remove_class_attrs(cls); subsystem_unregister(&cls->subsys); } + /* Class Device Stuff */ int class_device_create_file(struct class_device * class_dev, @@ -272,6 +306,40 @@ static struct kset_hotplug_ops class_hotplug_ops = { static decl_subsys(class_obj, &ktype_class_device, &class_hotplug_ops); + +static int class_device_add_attrs(struct class_device * cd) +{ + int i; + int error = 0; + struct class * cls = cd->class; + + if (cls->class_dev_attrs) { + for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) { + error = class_device_create_file(cd, + &cls->class_dev_attrs[i]); + if (error) + goto Err; + } + } + Done: + return error; + Err: + while (--i >= 0) + class_device_remove_file(cd,&cls->class_dev_attrs[i]); + goto Done; +} + +static void class_device_remove_attrs(struct class_device * cd) +{ + int i; + struct class * cls = cd->class; + + if (cls->class_dev_attrs) { + for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) + class_device_remove_file(cd,&cls->class_dev_attrs[i]); + } +} + void class_device_initialize(struct class_device *class_dev) { kobj_set_kset_s(class_dev, class_obj_subsys); @@ -311,7 +379,7 @@ int class_device_add(struct class_device *class_dev) class_intf->add(class_dev); up_write(&parent->subsys.rwsem); } - + class_device_add_attrs(class_dev); class_device_dev_link(class_dev); class_device_driver_link(class_dev); @@ -344,7 +412,8 @@ void class_device_del(struct class_device *class_dev) class_device_dev_unlink(class_dev); class_device_driver_unlink(class_dev); - + class_device_remove_attrs(class_dev); + kobject_del(&class_dev->kobj); if (parent) diff --git a/include/linux/device.h b/include/linux/device.h index e125402c948e..f7c2f70c34aa 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -143,6 +143,9 @@ struct class { struct list_head children; struct list_head interfaces; + struct class_attribute * class_attrs; + struct class_device_attribute * class_dev_attrs; + int (*hotplug)(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size); -- cgit v1.2.3 From f9fd83e34644e3972cd6f20daeda84d92689c791 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 2 Jun 2004 21:40:44 -0700 Subject: Driver Model: More cleanup of silly scsi use of the *ATTR macros... Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_debug.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 25c87cc6dcf4..93f65b68a3e0 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1326,7 +1326,7 @@ static ssize_t sdebug_delay_store(struct device_driver * ddp, return -EINVAL; } DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show, - sdebug_delay_store) + sdebug_delay_store); static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf) { @@ -1355,7 +1355,7 @@ opts_done: return count; } DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show, - sdebug_opts_store) + sdebug_opts_store); static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf) { @@ -1373,13 +1373,13 @@ static ssize_t sdebug_num_tgts_store(struct device_driver * ddp, return -EINVAL; } DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show, - sdebug_num_tgts_store) + sdebug_num_tgts_store); static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf) { return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb); } -DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL) +DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL); static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf) { @@ -1398,7 +1398,7 @@ static ssize_t sdebug_every_nth_store(struct device_driver * ddp, return -EINVAL; } DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show, - sdebug_every_nth_store) + sdebug_every_nth_store); static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf) { @@ -1416,13 +1416,13 @@ static ssize_t sdebug_max_luns_store(struct device_driver * ddp, return -EINVAL; } DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show, - sdebug_max_luns_store) + sdebug_max_luns_store); static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf) { return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level); } -DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL) +DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL); static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) { @@ -1459,7 +1459,7 @@ static ssize_t sdebug_add_host_store(struct device_driver * ddp, return count; } DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, - sdebug_add_host_store) + sdebug_add_host_store); static void do_create_driverfs_files() { -- cgit v1.2.3 From c5819000c1bf991f81f86a084a297f5698bc0c94 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 2 Jun 2004 21:42:20 -0700 Subject: Driver Model: Cleanup the i2c driver silly use of the *ATTR macros which just broke Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/asb100.c | 66 ++++++++++++++--------------- drivers/i2c/chips/it87.c | 22 +++++----- drivers/i2c/chips/lm78.c | 22 +++++----- drivers/i2c/chips/lm85.c | 26 ++++++------ drivers/i2c/chips/via686a.c | 18 ++++---- drivers/i2c/chips/w83627hf.c | 98 +++++++++++++++++++++---------------------- drivers/i2c/chips/w83781d.c | 30 ++++++------- drivers/i2c/chips/w83l785ts.c | 4 +- 8 files changed, 143 insertions(+), 143 deletions(-) diff --git a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c index f93b6f67696e..a416e4ee560e 100644 --- a/drivers/i2c/chips/asb100.c +++ b/drivers/i2c/chips/asb100.c @@ -272,7 +272,7 @@ static ssize_t \ return show_in(dev, buf, 0x##offset); \ } \ static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in##offset, NULL) \ + show_in##offset, NULL); \ static ssize_t \ show_in##offset##_min (struct device *dev, char *buf) \ { \ @@ -294,17 +294,17 @@ static ssize_t set_in##offset##_max (struct device *dev, \ return set_in_max(dev, buf, count, 0x##offset); \ } \ static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min) \ + show_in##offset##_min, set_in##offset##_min); \ static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max) + show_in##offset##_max, set_in##offset##_max); -sysfs_in(0) -sysfs_in(1) -sysfs_in(2) -sysfs_in(3) -sysfs_in(4) -sysfs_in(5) -sysfs_in(6) +sysfs_in(0); +sysfs_in(1); +sysfs_in(2); +sysfs_in(3); +sysfs_in(4); +sysfs_in(5); +sysfs_in(6); #define device_create_file_in(client, offset) do { \ device_create_file(&client->dev, &dev_attr_in##offset##_input); \ @@ -410,15 +410,15 @@ static ssize_t set_fan##offset##_div(struct device *dev, const char *buf, \ return set_fan_div(dev, buf, count, offset - 1); \ } \ static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan##offset, NULL) \ + show_fan##offset, NULL); \ static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan##offset##_min, set_fan##offset##_min) \ + show_fan##offset##_min, set_fan##offset##_min); \ static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan##offset##_div, set_fan##offset##_div) + show_fan##offset##_div, set_fan##offset##_div); -sysfs_fan(1) -sysfs_fan(2) -sysfs_fan(3) +sysfs_fan(1); +sysfs_fan(2); +sysfs_fan(3); #define device_create_file_fan(client, offset) do { \ device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ @@ -449,9 +449,9 @@ static ssize_t show_##reg(struct device *dev, char *buf, int nr) \ return sprintf_temp_from_reg(data->reg[nr], buf, nr); \ } -show_temp_reg(temp) -show_temp_reg(temp_max) -show_temp_reg(temp_hyst) +show_temp_reg(temp); +show_temp_reg(temp_max); +show_temp_reg(temp_hyst); #define set_temp_reg(REG, reg) \ static ssize_t set_##reg(struct device *dev, const char *buf, \ @@ -473,15 +473,15 @@ static ssize_t set_##reg(struct device *dev, const char *buf, \ return count; \ } -set_temp_reg(MAX, temp_max) -set_temp_reg(HYST, temp_hyst) +set_temp_reg(MAX, temp_max); +set_temp_reg(HYST, temp_hyst); #define sysfs_temp(num) \ static ssize_t show_temp##num(struct device *dev, char *buf) \ { \ return show_temp(dev, buf, num-1); \ } \ -static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL) \ +static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL); \ static ssize_t show_temp_max##num(struct device *dev, char *buf) \ { \ return show_temp_max(dev, buf, num-1); \ @@ -492,7 +492,7 @@ static ssize_t set_temp_max##num(struct device *dev, const char *buf, \ return set_temp_max(dev, buf, count, num-1); \ } \ static DEVICE_ATTR(temp##num##_max, S_IRUGO | S_IWUSR, \ - show_temp_max##num, set_temp_max##num) \ + show_temp_max##num, set_temp_max##num); \ static ssize_t show_temp_hyst##num(struct device *dev, char *buf) \ { \ return show_temp_hyst(dev, buf, num-1); \ @@ -503,12 +503,12 @@ static ssize_t set_temp_hyst##num(struct device *dev, const char *buf, \ return set_temp_hyst(dev, buf, count, num-1); \ } \ static DEVICE_ATTR(temp##num##_max_hyst, S_IRUGO | S_IWUSR, \ - show_temp_hyst##num, set_temp_hyst##num) + show_temp_hyst##num, set_temp_hyst##num); -sysfs_temp(1) -sysfs_temp(2) -sysfs_temp(3) -sysfs_temp(4) +sysfs_temp(1); +sysfs_temp(2); +sysfs_temp(3); +sysfs_temp(4); /* VID */ #define device_create_file_temp(client, num) do { \ @@ -523,7 +523,7 @@ static ssize_t show_vid(struct device *dev, char *buf) return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid, NULL) +static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid, NULL); #define device_create_file_vid(client) \ device_create_file(&client->dev, &dev_attr_in0_ref) @@ -544,7 +544,7 @@ static ssize_t set_vrm(struct device *dev, const char *buf, size_t count) } /* Alarms */ -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm) +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); #define device_create_file_vrm(client) \ device_create_file(&client->dev, &dev_attr_vrm); @@ -554,7 +554,7 @@ static ssize_t show_alarms(struct device *dev, char *buf) return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms)); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL) +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); #define device_create_file_alarms(client) \ device_create_file(&client->dev, &dev_attr_alarms) @@ -594,9 +594,9 @@ static ssize_t set_pwm_enable1(struct device *dev, const char *buf, return count; } -static DEVICE_ATTR(fan1_pwm, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1) +static DEVICE_ATTR(fan1_pwm, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1); static DEVICE_ATTR(fan1_pwm_enable, S_IRUGO | S_IWUSR, - show_pwm_enable1, set_pwm_enable1) + show_pwm_enable1, set_pwm_enable1); #define device_create_file_pwm1(client) do { \ device_create_file(&new_client->dev, &dev_attr_fan1_pwm); \ device_create_file(&new_client->dev, &dev_attr_fan1_pwm_enable); \ diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c index 061a0b8009b5..f701a17239c6 100644 --- a/drivers/i2c/chips/it87.c +++ b/drivers/i2c/chips/it87.c @@ -275,7 +275,7 @@ static ssize_t \ { \ return show_in(dev, buf, 0x##offset); \ } \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL) +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); #define limit_in_offset(offset) \ static ssize_t \ @@ -299,9 +299,9 @@ static ssize_t set_in##offset##_max (struct device *dev, \ return set_in_max(dev, buf, count, 0x##offset); \ } \ static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min) \ + show_in##offset##_min, set_in##offset##_min); \ static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max) + show_in##offset##_max, set_in##offset##_max); show_in_offset(0); limit_in_offset(0); @@ -382,11 +382,11 @@ static ssize_t set_temp_##offset##_min (struct device *dev, \ { \ return set_temp_min(dev, buf, count, 0x##offset - 1); \ } \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL) \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL); \ static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_max, set_temp_##offset##_max) \ + show_temp_##offset##_max, set_temp_##offset##_max); \ static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_min, set_temp_##offset##_min) + show_temp_##offset##_min, set_temp_##offset##_min); show_temp_offset(1); show_temp_offset(2); @@ -430,8 +430,8 @@ static ssize_t set_sensor_##offset (struct device *dev, \ { \ return set_sensor(dev, buf, count, 0x##offset - 1); \ } \ -static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ - show_sensor_##offset, set_sensor_##offset) +static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ + show_sensor_##offset, set_sensor_##offset); show_sensor_offset(1); show_sensor_offset(2); @@ -525,11 +525,11 @@ static ssize_t set_fan_##offset##_div (struct device *dev, \ { \ return set_fan_div(dev, buf, count, 0x##offset - 1); \ } \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL) \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL); \ static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min) \ + show_fan_##offset##_min, set_fan_##offset##_min); \ static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_div, set_fan_##offset##_div) + show_fan_##offset##_div, set_fan_##offset##_div); show_fan_offset(1); show_fan_offset(2); diff --git a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c index 74a1ca76cc04..b9ffad6c36e4 100644 --- a/drivers/i2c/chips/lm78.c +++ b/drivers/i2c/chips/lm78.c @@ -281,7 +281,7 @@ static ssize_t \ return show_in(dev, buf, 0x##offset); \ } \ static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in##offset, NULL) \ + show_in##offset, NULL); \ static ssize_t \ show_in##offset##_min (struct device *dev, char *buf) \ { \ @@ -303,9 +303,9 @@ static ssize_t set_in##offset##_max (struct device *dev, \ return set_in_max(dev, buf, count, 0x##offset); \ } \ static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min) \ + show_in##offset##_min, set_in##offset##_min); \ static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max) + show_in##offset##_max, set_in##offset##_max); show_in_offset(0); show_in_offset(1); @@ -354,11 +354,11 @@ static ssize_t set_temp_hyst(struct device *dev, const char *buf, size_t count) return count; } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL) +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, - show_temp_over, set_temp_over) + show_temp_over, set_temp_over); static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, - show_temp_hyst, set_temp_hyst) + show_temp_hyst, set_temp_hyst); /* 3 Fans */ static ssize_t show_fan(struct device *dev, char *buf, int nr) @@ -439,9 +439,9 @@ static ssize_t set_fan_##offset##_min (struct device *dev, \ { \ return set_fan_min(dev, buf, count, 0x##offset - 1); \ } \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL) \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min) + show_fan_##offset##_min, set_fan_##offset##_min); static ssize_t set_fan_1_div(struct device *dev, const char *buf, size_t count) @@ -461,10 +461,10 @@ show_fan_offset(3); /* Fan 3 divisor is locked in H/W */ static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, - show_fan_1_div, set_fan_1_div) + show_fan_1_div, set_fan_1_div); static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, - show_fan_2_div, set_fan_2_div) -static DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_3_div, NULL) + show_fan_2_div, set_fan_2_div); +static DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_3_div, NULL); /* VID */ static ssize_t show_vid(struct device *dev, char *buf) diff --git a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c index 795852aa6719..11f85043153b 100644 --- a/drivers/i2c/chips/lm85.c +++ b/drivers/i2c/chips/lm85.c @@ -451,9 +451,9 @@ static ssize_t set_fan_##offset##_min (struct device *dev, \ { \ return set_fan_min(dev, buf, count, 0x##offset - 1); \ } \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL) \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min) + show_fan_##offset##_min, set_fan_##offset##_min); show_fan_offset(1); show_fan_offset(2); @@ -468,7 +468,7 @@ static ssize_t show_vid_reg(struct device *dev, char *buf) return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL) +static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL); static ssize_t show_vrm_reg(struct device *dev, char *buf) { @@ -487,7 +487,7 @@ static ssize_t store_vrm_reg(struct device *dev, const char *buf, size_t count) return count; } -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg) +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); static ssize_t show_alarms_reg(struct device *dev, char *buf) { @@ -495,7 +495,7 @@ static ssize_t show_alarms_reg(struct device *dev, char *buf) return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms)); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL) +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); /* pwm */ @@ -542,8 +542,8 @@ static ssize_t show_pwm_enable##offset (struct device *dev, char *buf) \ return show_pwm_enable(dev, buf, 0x##offset - 1); \ } \ static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, \ - show_pwm_##offset, set_pwm_##offset) \ -static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO, show_pwm_enable##offset, NULL) + show_pwm_##offset, set_pwm_##offset); \ +static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO, show_pwm_enable##offset, NULL); show_pwm_reg(1); show_pwm_reg(2); @@ -617,11 +617,11 @@ static ssize_t set_in_##offset##_max (struct device *dev, \ { \ return set_in_max(dev, buf, count, 0x##offset); \ } \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in_##offset, NULL) \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in_##offset, NULL); \ static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in_##offset##_min, set_in_##offset##_min) \ + show_in_##offset##_min, set_in_##offset##_min); \ static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in_##offset##_max, set_in_##offset##_max) + show_in_##offset##_max, set_in_##offset##_max); show_in_reg(0); show_in_reg(1); @@ -697,11 +697,11 @@ static ssize_t set_temp_##offset##_max (struct device *dev, \ { \ return set_temp_max(dev, buf, count, 0x##offset - 1); \ } \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL) \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL); \ static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_min, set_temp_##offset##_min) \ + show_temp_##offset##_min, set_temp_##offset##_min); \ static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_max, set_temp_##offset##_max) + show_temp_##offset##_max, set_temp_##offset##_max); show_temp_reg(1); show_temp_reg(2); diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c index a5ec359b0f6f..3aa334583b89 100644 --- a/drivers/i2c/chips/via686a.c +++ b/drivers/i2c/chips/via686a.c @@ -405,11 +405,11 @@ static ssize_t set_in##offset##_max (struct device *dev, \ { \ return set_in_max(dev, buf, count, 0x##offset); \ } \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL) \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);\ static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min) \ + show_in##offset##_min, set_in##offset##_min); \ static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max) + show_in##offset##_max, set_in##offset##_max); show_in_offset(0); show_in_offset(1); @@ -473,11 +473,11 @@ static ssize_t set_temp_##offset##_hyst (struct device *dev, \ { \ return set_temp_hyst(dev, buf, count, 0x##offset - 1); \ } \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL) \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\ static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_over, set_temp_##offset##_over) \ + show_temp_##offset##_over, set_temp_##offset##_over); \ static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_hyst, set_temp_##offset##_hyst) + show_temp_##offset##_hyst, set_temp_##offset##_hyst); show_temp_offset(1); show_temp_offset(2); @@ -542,11 +542,11 @@ static ssize_t set_fan_##offset##_div (struct device *dev, \ { \ return set_fan_div(dev, buf, count, 0x##offset - 1); \ } \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL) \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min) \ + show_fan_##offset##_min, set_fan_##offset##_min); \ static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_div, set_fan_##offset##_div) + show_fan_##offset##_div, set_fan_##offset##_div); show_fan_offset(1); show_fan_offset(2); diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c index c38a7f9712b6..0247a433cc6a 100644 --- a/drivers/i2c/chips/w83627hf.c +++ b/drivers/i2c/chips/w83627hf.c @@ -370,7 +370,7 @@ show_regs_in_##offset (struct device *dev, char *buf) \ { \ return show_in(dev, buf, 0x##offset); \ } \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL) +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL); #define sysfs_in_reg_offset(reg, offset) \ static ssize_t show_regs_in_##reg##offset (struct device *dev, char *buf) \ @@ -384,22 +384,22 @@ store_regs_in_##reg##offset (struct device *dev, \ return store_in_##reg (dev, buf, count, 0x##offset); \ } \ static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \ - show_regs_in_##reg##offset, store_regs_in_##reg##offset) + show_regs_in_##reg##offset, store_regs_in_##reg##offset); #define sysfs_in_offsets(offset) \ sysfs_in_offset(offset) \ sysfs_in_reg_offset(min, offset) \ sysfs_in_reg_offset(max, offset) -sysfs_in_offsets(0) -sysfs_in_offsets(1) -sysfs_in_offsets(2) -sysfs_in_offsets(3) -sysfs_in_offsets(4) -sysfs_in_offsets(5) -sysfs_in_offsets(6) -sysfs_in_offsets(7) -sysfs_in_offsets(8) +sysfs_in_offsets(0); +sysfs_in_offsets(1); +sysfs_in_offsets(2); +sysfs_in_offsets(3); +sysfs_in_offsets(4); +sysfs_in_offsets(5); +sysfs_in_offsets(6); +sysfs_in_offsets(7); +sysfs_in_offsets(8); #define device_create_file_in(client, offset) \ do { \ @@ -416,8 +416,8 @@ static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ FAN_FROM_REG(data->reg[nr-1], \ (long)DIV_FROM_REG(data->fan_div[nr-1]))); \ } -show_fan_reg(fan) -show_fan_reg(fan_min) +show_fan_reg(fan); +show_fan_reg(fan_min); static ssize_t store_fan_min(struct device *dev, const char *buf, size_t count, int nr) @@ -440,7 +440,7 @@ static ssize_t show_regs_fan_##offset (struct device *dev, char *buf) \ { \ return show_fan(dev, buf, 0x##offset); \ } \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL) +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL); #define sysfs_fan_min_offset(offset) \ static ssize_t show_regs_fan_min##offset (struct device *dev, char *buf) \ @@ -453,14 +453,14 @@ store_regs_fan_min##offset (struct device *dev, const char *buf, size_t count) \ return store_fan_min(dev, buf, count, 0x##offset); \ } \ static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_regs_fan_min##offset, store_regs_fan_min##offset) + show_regs_fan_min##offset, store_regs_fan_min##offset); -sysfs_fan_offset(1) -sysfs_fan_min_offset(1) -sysfs_fan_offset(2) -sysfs_fan_min_offset(2) -sysfs_fan_offset(3) -sysfs_fan_min_offset(3) +sysfs_fan_offset(1); +sysfs_fan_min_offset(1); +sysfs_fan_offset(2); +sysfs_fan_min_offset(2); +sysfs_fan_offset(3); +sysfs_fan_min_offset(3); #define device_create_file_fan(client, offset) \ do { \ @@ -479,9 +479,9 @@ static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \ } \ } -show_temp_reg(temp) -show_temp_reg(temp_max) -show_temp_reg(temp_max_hyst) +show_temp_reg(temp); +show_temp_reg(temp_max); +show_temp_reg(temp_max_hyst); #define store_temp_reg(REG, reg) \ static ssize_t \ @@ -505,8 +505,8 @@ store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \ \ return count; \ } -store_temp_reg(OVER, max) -store_temp_reg(HYST, max_hyst) +store_temp_reg(OVER, max); +store_temp_reg(HYST, max_hyst); #define sysfs_temp_offset(offset) \ static ssize_t \ @@ -514,7 +514,7 @@ show_regs_temp_##offset (struct device *dev, char *buf) \ { \ return show_temp(dev, buf, 0x##offset); \ } \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL) +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL); #define sysfs_temp_reg_offset(reg, offset) \ static ssize_t show_regs_temp_##reg##offset (struct device *dev, char *buf) \ @@ -528,16 +528,16 @@ store_regs_temp_##reg##offset (struct device *dev, \ return store_temp_##reg (dev, buf, count, 0x##offset); \ } \ static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \ - show_regs_temp_##reg##offset, store_regs_temp_##reg##offset) + show_regs_temp_##reg##offset, store_regs_temp_##reg##offset); #define sysfs_temp_offsets(offset) \ sysfs_temp_offset(offset) \ sysfs_temp_reg_offset(max, offset) \ sysfs_temp_reg_offset(max_hyst, offset) -sysfs_temp_offsets(1) -sysfs_temp_offsets(2) -sysfs_temp_offsets(3) +sysfs_temp_offsets(1); +sysfs_temp_offsets(2); +sysfs_temp_offsets(3); #define device_create_file_temp(client, offset) \ do { \ @@ -552,7 +552,7 @@ show_vid_reg(struct device *dev, char *buf) struct w83627hf_data *data = w83627hf_update_device(dev); return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL) +static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL); #define device_create_file_vid(client) \ device_create_file(&client->dev, &dev_attr_in0_ref) @@ -574,7 +574,7 @@ store_vrm_reg(struct device *dev, const char *buf, size_t count) return count; } -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg) +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); #define device_create_file_vrm(client) \ device_create_file(&client->dev, &dev_attr_vrm) @@ -584,7 +584,7 @@ show_alarms_reg(struct device *dev, char *buf) struct w83627hf_data *data = w83627hf_update_device(dev); return sprintf(buf, "%ld\n", (long) data->alarms); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL) +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); #define device_create_file_alarms(client) \ device_create_file(&client->dev, &dev_attr_alarms) @@ -641,10 +641,10 @@ store_regs_beep_##reg (struct device *dev, const char *buf, size_t count) \ return store_beep_reg(dev, buf, count, BEEP_##REG); \ } \ static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \ - show_regs_beep_##reg, store_regs_beep_##reg) + show_regs_beep_##reg, store_regs_beep_##reg); -sysfs_beep(ENABLE, enable) -sysfs_beep(MASK, mask) +sysfs_beep(ENABLE, enable); +sysfs_beep(MASK, mask); #define device_create_file_beep(client) \ do { \ @@ -707,11 +707,11 @@ store_regs_fan_div_##offset (struct device *dev, \ return store_fan_div_reg(dev, buf, count, offset - 1); \ } \ static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_regs_fan_div_##offset, store_regs_fan_div_##offset) + show_regs_fan_div_##offset, store_regs_fan_div_##offset); -sysfs_fan_div(1) -sysfs_fan_div(2) -sysfs_fan_div(3) +sysfs_fan_div(1); +sysfs_fan_div(2); +sysfs_fan_div(3); #define device_create_file_fan_div(client, offset) \ do { \ @@ -763,11 +763,11 @@ store_regs_pwm_##offset (struct device *dev, const char *buf, size_t count) \ return store_pwm_reg(dev, buf, count, offset); \ } \ static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, \ - show_regs_pwm_##offset, store_regs_pwm_##offset) + show_regs_pwm_##offset, store_regs_pwm_##offset); -sysfs_pwm(1) -sysfs_pwm(2) -sysfs_pwm(3) +sysfs_pwm(1); +sysfs_pwm(2); +sysfs_pwm(3); #define device_create_file_pwm(client, offset) \ do { \ @@ -836,11 +836,11 @@ store_regs_sensor_##offset (struct device *dev, const char *buf, size_t count) \ return store_sensor_reg(dev, buf, count, offset); \ } \ static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ - show_regs_sensor_##offset, store_regs_sensor_##offset) + show_regs_sensor_##offset, store_regs_sensor_##offset); -sysfs_sensor(1) -sysfs_sensor(2) -sysfs_sensor(3) +sysfs_sensor(1); +sysfs_sensor(2); +sysfs_sensor(3); #define device_create_file_sensor(client, offset) \ do { \ diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c index ac378b54b1cd..df30ca18602a 100644 --- a/drivers/i2c/chips/w83781d.c +++ b/drivers/i2c/chips/w83781d.c @@ -320,7 +320,7 @@ show_regs_in_##offset (struct device *dev, char *buf) \ { \ return show_in(dev, buf, 0x##offset); \ } \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL) +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL); #define sysfs_in_reg_offset(reg, offset) \ static ssize_t show_regs_in_##reg##offset (struct device *dev, char *buf) \ @@ -331,7 +331,7 @@ static ssize_t store_regs_in_##reg##offset (struct device *dev, const char *buf, { \ return store_in_##reg (dev, buf, count, 0x##offset); \ } \ -static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset) +static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset); #define sysfs_in_offsets(offset) \ sysfs_in_offset(offset); \ @@ -386,7 +386,7 @@ static ssize_t show_regs_fan_##offset (struct device *dev, char *buf) \ { \ return show_fan(dev, buf, 0x##offset); \ } \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL) +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL); #define sysfs_fan_min_offset(offset) \ static ssize_t show_regs_fan_min##offset (struct device *dev, char *buf) \ @@ -397,7 +397,7 @@ static ssize_t store_regs_fan_min##offset (struct device *dev, const char *buf, { \ return store_fan_min(dev, buf, count, 0x##offset); \ } \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset) +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset); sysfs_fan_offset(1); sysfs_fan_min_offset(1); @@ -466,7 +466,7 @@ show_regs_temp_##offset (struct device *dev, char *buf) \ { \ return show_temp(dev, buf, 0x##offset); \ } \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL) +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL); #define sysfs_temp_reg_offset(reg, offset) \ static ssize_t show_regs_temp_##reg##offset (struct device *dev, char *buf) \ @@ -477,7 +477,7 @@ static ssize_t store_regs_temp_##reg##offset (struct device *dev, const char *bu { \ return store_temp_##reg (dev, buf, count, 0x##offset); \ } \ -static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset) +static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset); #define sysfs_temp_offsets(offset) \ sysfs_temp_offset(offset); \ @@ -503,7 +503,7 @@ show_vid_reg(struct device *dev, char *buf) } static -DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL) +DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL); #define device_create_file_vid(client) \ device_create_file(&client->dev, &dev_attr_in0_ref); static ssize_t @@ -527,7 +527,7 @@ store_vrm_reg(struct device *dev, const char *buf, size_t count) } static -DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg) +DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); #define device_create_file_vrm(client) \ device_create_file(&client->dev, &dev_attr_vrm); static ssize_t @@ -538,7 +538,7 @@ show_alarms_reg(struct device *dev, char *buf) } static -DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL) +DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); #define device_create_file_alarms(client) \ device_create_file(&client->dev, &dev_attr_alarms); static ssize_t show_beep_mask (struct device *dev, char *buf) @@ -598,7 +598,7 @@ static ssize_t store_regs_beep_##reg (struct device *dev, const char *buf, size_ { \ return store_beep_reg(dev, buf, count, BEEP_##REG); \ } \ -static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_regs_beep_##reg) +static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_regs_beep_##reg); sysfs_beep(ENABLE, enable); sysfs_beep(MASK, mask); @@ -665,7 +665,7 @@ static ssize_t store_regs_fan_div_##offset (struct device *dev, const char *buf, { \ return store_fan_div_reg(dev, buf, count, offset - 1); \ } \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset) +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset); sysfs_fan_div(1); sysfs_fan_div(2); @@ -744,7 +744,7 @@ static ssize_t store_regs_pwm_##offset (struct device *dev, const char *buf, siz { \ return store_pwm_reg(dev, buf, count, offset); \ } \ -static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, show_regs_pwm_##offset, store_regs_pwm_##offset) +static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, show_regs_pwm_##offset, store_regs_pwm_##offset); #define sysfs_pwmenable(offset) \ static ssize_t show_regs_pwmenable_##offset (struct device *dev, char *buf) \ @@ -755,7 +755,7 @@ static ssize_t store_regs_pwmenable_##offset (struct device *dev, const char *bu { \ return store_pwmenable_reg(dev, buf, count, offset); \ } \ -static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO | S_IWUSR, show_regs_pwmenable_##offset, store_regs_pwmenable_##offset) +static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO | S_IWUSR, show_regs_pwmenable_##offset, store_regs_pwmenable_##offset); sysfs_pwm(1); sysfs_pwm(2); @@ -833,7 +833,7 @@ static ssize_t store_regs_sensor_##offset (struct device *dev, const char *buf, { \ return store_sensor_reg(dev, buf, count, offset); \ } \ -static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset) +static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset); sysfs_sensor(1); sysfs_sensor(2); @@ -891,7 +891,7 @@ static ssize_t store_regs_rt_##offset (struct device *dev, const char *buf, size { \ return store_rt_reg(dev, buf, count, offset); \ } \ -static DEVICE_ATTR(rt##offset, S_IRUGO | S_IWUSR, show_regs_rt_##offset, store_regs_rt_##offset) +static DEVICE_ATTR(rt##offset, S_IRUGO | S_IWUSR, show_regs_rt_##offset, store_regs_rt_##offset); sysfs_rt(1); sysfs_rt(2); diff --git a/drivers/i2c/chips/w83l785ts.c b/drivers/i2c/chips/w83l785ts.c index 52118f9bf11f..58575861fc78 100644 --- a/drivers/i2c/chips/w83l785ts.c +++ b/drivers/i2c/chips/w83l785ts.c @@ -137,8 +137,8 @@ static ssize_t show_temp_over(struct device *dev, char *buf) return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL) -static DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_over, NULL) +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_over, NULL); /* * Real code -- cgit v1.2.3 From cca247378e51b3244f7fa895ba6b71aec6d272b6 Mon Sep 17 00:00:00 2001 From: "Hanna V. Linder" Date: Wed, 2 Jun 2004 22:38:31 -0700 Subject: [PATCH] Add class support to cpuid.c This patch adds class support to arch/i386/kernel/cpuid.c. This enables udev support. I have tested on a 2-way SMP system and on a 2-way built as UP. Here are the results for the SMP: [hlinder@w-hlinder2 hlinder]$ tree /sys/class/cpuid /sys/class/cpuid |-- cpu0 | `-- dev `-- cpu1 `-- dev 2 directories, 2 files [hlinder@w-hlinder2 hlinder]$ more /sys/class/cpuid/cpu0/dev 203:0 [hlinder@w-hlinder2 hlinder]$ more /sys/class/cpuid/cpu1/dev 203:1 [hlinder@w-hlinder2 hlinder]$ And for the UP: [root@w-hlinder2 root]# tree /sys/class/cpuid /sys/class/cpuid `-- cpu0 `-- dev 1 directory, 1 file Signed-off-by: Greg Kroah-Hartman --- arch/i386/kernel/cpuid.c | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c index 5a997a3716fc..303f4eb42cbd 100644 --- a/arch/i386/kernel/cpuid.c +++ b/arch/i386/kernel/cpuid.c @@ -36,12 +36,15 @@ #include #include #include +#include #include #include #include #include +static struct class_simple *cpuid_class; + #ifdef CONFIG_SMP struct cpuid_command { @@ -155,17 +158,48 @@ static struct file_operations cpuid_fops = { int __init cpuid_init(void) { + int i, err = 0; + struct class_device *class_err; + i = 0; + if (register_chrdev(CPUID_MAJOR, "cpu/cpuid", &cpuid_fops)) { printk(KERN_ERR "cpuid: unable to get major %d for cpuid\n", CPUID_MAJOR); - return -EBUSY; + err = -EBUSY; + goto out; } - - return 0; + cpuid_class = class_simple_create(THIS_MODULE, "cpuid"); + if (IS_ERR(cpuid_class)) { + err = PTR_ERR(cpuid_class); + goto out_chrdev; + } + for_each_online_cpu(i) { + class_err = class_simple_device_add(cpuid_class, MKDEV(CPUID_MAJOR, i), NULL, "cpu%d",i); + if (IS_ERR(class_err)) { + err = PTR_ERR(class_err); + goto out_class; + } + } + err = 0; + goto out; + +out_class: + i = 0; + for_each_online_cpu(i) + class_simple_device_remove(MKDEV(CPUID_MAJOR, i)); + class_simple_destroy(cpuid_class); +out_chrdev: + unregister_chrdev(CPUID_MAJOR, "cpu/cpuid"); +out: + return err; } void __exit cpuid_exit(void) { + int i = 0; + for_each_online_cpu(i) + class_simple_device_remove(MKDEV(CPUID_MAJOR, i)); + class_simple_destroy(cpuid_class); unregister_chrdev(CPUID_MAJOR, "cpu/cpuid"); } -- cgit v1.2.3 From ee831b82a42564517f0c20f010c15efe8ea79832 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Thu, 3 Jun 2004 03:05:41 -0700 Subject: [Driver Model] Add default attributes for struct bus_type. - Similar to default attributes for struct class, this is an array of attributes, terminated with an attribute with a NULL name, that are added when the bus is registered, and removed when the bus is unregistered. --- drivers/base/bus.c | 37 +++++++++++++++++++++++++++++++++++++ include/linux/device.h | 2 ++ 2 files changed, 39 insertions(+) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index b40af6a72afe..d4743b78f986 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -549,6 +549,41 @@ struct bus_type * find_bus(char * name) return k ? to_bus(k) : NULL; } + +/** + * bus_add_attrs - Add default attributes for this bus. + * @bus: Bus that has just been registered. + */ + +static int bus_add_attrs(struct bus_type * bus) +{ + int error = 0; + int i; + + if (bus->bus_attrs) { + for (i = 0; attr_name(bus->bus_attrs[i]); i++) { + if ((error = bus_create_file(bus,&bus->bus_attrs[i]))) + goto Err; + } + } + Done: + return error; + Err: + while (i >= 0) + bus_remove_file(bus,&bus->bus_attrs[i]); + goto Done; +} + +static void bus_remove_attrs(struct bus_type * bus) +{ + int i; + + if (bus->bus_attrs) { + for (i = 0; attr_name(bus->bus_attrs[i]); i++) + bus_remove_file(bus,&bus->bus_attrs[i]); + } +} + /** * bus_register - register a bus with the system. * @bus: bus. @@ -582,6 +617,7 @@ int bus_register(struct bus_type * bus) retval = kset_register(&bus->drivers); if (retval) goto bus_drivers_fail; + bus_add_attrs(bus); pr_debug("bus type '%s' registered\n",bus->name); return 0; @@ -605,6 +641,7 @@ out: void bus_unregister(struct bus_type * bus) { pr_debug("bus %s: unregistering\n",bus->name); + bus_remove_attrs(bus); kset_unregister(&bus->drivers); kset_unregister(&bus->devices); subsystem_unregister(&bus->subsys); diff --git a/include/linux/device.h b/include/linux/device.h index f7c2f70c34aa..ea404ac188d1 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -54,6 +54,8 @@ struct bus_type { struct kset drivers; struct kset devices; + struct bus_attribute * bus_attrs; + int (*match)(struct device * dev, struct device_driver * drv); struct device * (*add) (struct device * parent, char * bus_id); int (*hotplug) (struct device *dev, char **envp, -- cgit v1.2.3 From d58199d42059313cc938100679fa3e4a009ce24c Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Thu, 3 Jun 2004 03:37:14 -0700 Subject: [Driver Model] Add default device attributes to struct bus_type. - Add struct bus_type::dev_attrs, which is an array of device attributes that are added to each device as they are registered. - Also make sure that we don't hang when removing bus attributes if adding one failed.. --- drivers/base/bus.c | 36 +++++++++++++++++++++++++++++++++++- include/linux/device.h | 1 + 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index d4743b78f986..0e5f5ea78e58 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -392,6 +392,38 @@ static void driver_detach(struct device_driver * drv) } +static int device_add_attrs(struct bus_type * bus, struct device * dev) +{ + int error = 0; + int i; + + if (bus->dev_attrs) { + for (i = 0; attr_name(bus->dev_attrs[i]); i++) { + error = device_create_file(dev,&bus->dev_attrs[i]); + if (error) + goto Err; + } + } + Done: + return error; + Err: + while (--i >= 0) + device_remove_file(dev,&bus->dev_attrs[i]); + goto Done; +} + + +static void device_remove_attrs(struct bus_type * bus, struct device * dev) +{ + int i; + + if (bus->dev_attrs) { + for (i = 0; attr_name(bus->dev_attrs[i]); i++) + device_remove_file(dev,&bus->dev_attrs[i]); + } +} + + /** * bus_add_device - add device to bus * @dev: device being added @@ -411,6 +443,7 @@ int bus_add_device(struct device * dev) list_add_tail(&dev->bus_list,&dev->bus->devices.list); device_attach(dev); up_write(&dev->bus->subsys.rwsem); + device_add_attrs(bus,dev); sysfs_create_link(&bus->devices.kobj,&dev->kobj,dev->bus_id); } return error; @@ -429,6 +462,7 @@ void bus_remove_device(struct device * dev) { if (dev->bus) { sysfs_remove_link(&dev->bus->devices.kobj,dev->bus_id); + device_remove_attrs(dev->bus,dev); down_write(&dev->bus->subsys.rwsem); pr_debug("bus %s: remove device %s\n",dev->bus->name,dev->bus_id); device_release_driver(dev); @@ -569,7 +603,7 @@ static int bus_add_attrs(struct bus_type * bus) Done: return error; Err: - while (i >= 0) + while (--i >= 0) bus_remove_file(bus,&bus->bus_attrs[i]); goto Done; } diff --git a/include/linux/device.h b/include/linux/device.h index ea404ac188d1..c91a6b481534 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -55,6 +55,7 @@ struct bus_type { struct kset devices; struct bus_attribute * bus_attrs; + struct device_attribute * dev_attrs; int (*match)(struct device * dev, struct device_driver * drv); struct device * (*add) (struct device * parent, char * bus_id); -- cgit v1.2.3 From 5823eb4052b7382503efc8c7cb6d990955ef274f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 3 Jun 2004 21:09:29 -0700 Subject: Driver Model: And even more cleanup of silly scsi use of the *ATTR macros... Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_sysfs.c | 10 +++++----- drivers/scsi/scsi_transport_spi.c | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index db109921782b..a9ff002bb0a5 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -99,7 +99,7 @@ show_##name (struct class_device *class_dev, char *buf) \ */ #define shost_rd_attr2(name, field, format_string) \ shost_show_function(name, field, format_string) \ -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) +static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); #define shost_rd_attr(field, format_string) \ shost_rd_attr2(field, field, format_string) @@ -228,8 +228,8 @@ sdev_show_##field (struct device *dev, char *buf) \ * read only field. */ #define sdev_rd_attr(field, format_string) \ - sdev_show_function(field, format_string) \ -static DEVICE_ATTR(field, S_IRUGO, sdev_show_##field, NULL) + sdev_show_function(field, format_string) \ +static DEVICE_ATTR(field, S_IRUGO, sdev_show_##field, NULL); /* @@ -247,7 +247,7 @@ sdev_store_##field (struct device *dev, const char *buf, size_t count) \ snscanf (buf, 20, format_string, &sdev->field); \ return count; \ } \ -static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field) +static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field); /* Currently we don't export bit fields, but we might in future, * so leave this code in */ @@ -272,7 +272,7 @@ sdev_store_##field (struct device *dev, const char *buf, size_t count) \ } \ return ret; \ } \ -static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field) +static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field); /* * scsi_sdev_check_buf_bit: return 0 if buf is "0", return 1 if buf is "1", diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index f2cd32a141f1..49ebdfe91e03 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -152,7 +152,7 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \ spi_transport_store_function(field, format_string) \ static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ show_spi_transport_##field, \ - store_spi_transport_##field) + store_spi_transport_##field); /* The Parallel SCSI Tranport Attributes: */ spi_transport_rd_attr(offset, "%d\n"); @@ -173,7 +173,7 @@ store_spi_revalidate(struct class_device *cdev, const char *buf, size_t count) spi_dv_device(sdev); return count; } -static CLASS_DEVICE_ATTR(revalidate, S_IWUSR, NULL, store_spi_revalidate) +static CLASS_DEVICE_ATTR(revalidate, S_IWUSR, NULL, store_spi_revalidate); /* Translate the period into ns according to the current spec * for SDTR/PPR messages */ -- cgit v1.2.3 From e7414910adcbc3406f22766a5cbe14ae1ac3bbc8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 3 Jun 2004 23:24:29 -0700 Subject: PCI: convert to using dev_attrs for all PCI devices. Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-driver.c | 1 + drivers/pci/pci-sysfs.c | 33 +++++++++++++++------------------ drivers/pci/pci.h | 1 + 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 0dea6b1ddd52..9936879eb719 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -539,6 +539,7 @@ struct bus_type pci_bus_type = { .hotplug = pci_hotplug, .suspend = pci_device_suspend, .resume = pci_device_resume, + .dev_attrs = pci_dev_attrs, }; static int __init pci_driver_init(void) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 34161c9f88ff..120a441a88d6 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -23,14 +23,13 @@ /* show configuration fields */ #define pci_config_attr(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, char *buf) \ +field##_show(struct device *dev, char *buf) \ { \ struct pci_dev *pdev; \ \ pdev = to_pci_dev (dev); \ return sprintf (buf, format_string, pdev->field); \ -} \ -static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); +} pci_config_attr(vendor, "0x%04x\n"); pci_config_attr(device, "0x%04x\n"); @@ -41,7 +40,7 @@ pci_config_attr(irq, "%u\n"); /* show resources */ static ssize_t -pci_show_resources(struct device * dev, char * buf) +resource_show(struct device * dev, char * buf) { struct pci_dev * pci_dev = to_pci_dev(dev); char * str = buf; @@ -60,7 +59,16 @@ pci_show_resources(struct device * dev, char * buf) return (str - buf); } -static DEVICE_ATTR(resource,S_IRUGO,pci_show_resources,NULL); +struct device_attribute pci_dev_attrs[] = { + __ATTR_RO(resource), + __ATTR_RO(vendor), + __ATTR_RO(device), + __ATTR_RO(subsystem_vendor), + __ATTR_RO(subsystem_device), + __ATTR_RO(class), + __ATTR_RO(irq), + __ATTR_NULL, +}; static ssize_t pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) @@ -180,21 +188,10 @@ static struct bin_attribute pcie_config_attr = { void pci_create_sysfs_dev_files (struct pci_dev *pdev) { - struct device *dev = &pdev->dev; - - /* current configuration's attributes */ - device_create_file (dev, &dev_attr_vendor); - device_create_file (dev, &dev_attr_device); - device_create_file (dev, &dev_attr_subsystem_vendor); - device_create_file (dev, &dev_attr_subsystem_device); - device_create_file (dev, &dev_attr_class); - device_create_file (dev, &dev_attr_irq); - device_create_file (dev, &dev_attr_resource); - if (pdev->cfg_size < 4096) - sysfs_create_bin_file(&dev->kobj, &pci_config_attr); + sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); else - sysfs_create_bin_file(&dev->kobj, &pcie_config_attr); + sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr); /* add platform-specific attributes */ pcibios_add_platform_entries(pdev); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index e1985b618fc9..a9b243770580 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -62,3 +62,4 @@ extern int pci_visit_dev(struct pci_visit *fn, extern spinlock_t pci_bus_lock; extern int pciehp_msi_quirk; +extern struct device_attribute pci_dev_attrs[]; -- cgit v1.2.3 From c89204015fe02c79a73e33d92de380f0fe653126 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Fri, 4 Jun 2004 00:45:53 -0700 Subject: [PATCH] I2C i2c-piix: Don't treat ServerWorks servers as Laptops I'm sending you this little obvious patch which should enable i2c-piix to work on IBM servers with ServerWorks chipsets. It still will treat any IBM/Intel machine as a laptop and refuse to work, but it's better than before. i2c: Treat only IBM machines with Intel chipsets as IBM laptops. Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-piix4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 31ee54341952..6e22814a7f40 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -138,7 +138,7 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, dev_info(&PIIX4_dev->dev, "Found %s device\n", pci_name(PIIX4_dev)); - if(ibm_dmi_probe()) { + if(ibm_dmi_probe() && PIIX4_dev->vendor == PCI_VENDOR_ID_INTEL) { dev_err(&PIIX4_dev->dev, "IBM Laptop detected; this module " "may corrupt your serial eeprom! Refusing to load " "module!\n"); -- cgit v1.2.3 From c3226112b79451d96adc74a58c96058986b37452 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 4 Jun 2004 00:46:39 -0700 Subject: [PATCH] I2C: update I2C IDs > > Greg, should I send a patch to you with these? > > Sure, if it's needed. Just noticed that I never sent the promised patch. Here it is. I also added a few other IDs, since we have them in our (2.4) i2c CVS repository. Having them in 2.6 as well will at least prevent collisions. Signed-off-by: Greg Kroah-Hartman --- include/linux/i2c-id.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 591e7ad68d30..520fe7220cd3 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -101,6 +101,14 @@ #define I2C_DRIVERID_UDA1342 53 /* UDA1342 audio codec */ #define I2C_DRIVERID_ADV7170 54 /* video encoder */ #define I2C_DRIVERID_RADEON 55 /* I2C bus on Radeon boards */ +#define I2C_DRIVERID_MAX1617 56 /* temp sensor */ +#define I2C_DRIVERID_SAA7191 57 /* video encoder */ +#define I2C_DRIVERID_INDYCAM 58 /* SGI IndyCam */ +#define I2C_DRIVERID_BT832 59 /* CMOS camera video processor */ +#define I2C_DRIVERID_TDA9887 60 /* TDA988x IF-PLL demodulator */ +#define I2C_DRIVERID_OVCAMCHIP 61 /* OmniVision CMOS image sens. */ +#define I2C_DRIVERID_TDA7313 62 /* TDA7313 audio processor */ +#define I2C_DRIVERID_MAX6900 63 /* MAX6900 real-time clock */ #define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */ @@ -264,6 +272,10 @@ #define I2C_HW_SMBUS_SCX200 0x0b #define I2C_HW_SMBUS_NFORCE2 0x0c #define I2C_HW_SMBUS_W9968CF 0x0d +#define I2C_HW_SMBUS_OV511 0x0e /* OV511(+) USB 1.1 webcam ICs */ +#define I2C_HW_SMBUS_OV518 0x0f /* OV518(+) USB 1.1 webcam ICs */ +#define I2C_HW_SMBUS_OV519 0x10 /* OV519 USB 1.1 webcam IC */ +#define I2C_HW_SMBUS_OVFX2 0x11 /* Cypress/OmniVision FX2 webcam */ /* --- ISA pseudo-adapter */ #define I2C_HW_ISA 0x00 -- cgit v1.2.3 From 1248a63797c30ca157d3c90278fe3813f50514de Mon Sep 17 00:00:00 2001 From: "Frank A. Uepping" Date: Fri, 4 Jun 2004 00:53:48 -0700 Subject: [PATCH] Driver Core: fix struct device::release issue Signed-off-by: Greg Kroah-Hartman On Saturday 27 March 2004 02:14, Greg KH wrote: > On Sat, Mar 06, 2004 at 12:47:24PM +0100, Frank A. Uepping wrote: > > Hi, > > if device_add fails (e.g. bus_add_device returns an error) then the release > > method will be called for the device. Is this a bug or a feature? > > Are you sure this will happen? device_initialize() gets a reference > that is still present after device_add() fails, right? So release() > will not get called. At the label PMError, kobject_unregister is called, which decrements the recount by 2, which will result in calling release at label Done (put_device). kobject_unregister should be superseded by kobject_del. Here is a patch: --- drivers/base/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 0eaa2c003e69..afc336876a13 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -245,7 +245,7 @@ int device_add(struct device *dev) BusError: device_pm_remove(dev); PMError: - kobject_unregister(&dev->kobj); + kobject_del(&dev->kobj); Error: if (parent) put_device(parent); -- cgit v1.2.3 From 3f7b0672086b97b2d7f322bdc289cbfa203f10ef Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Fri, 4 Jun 2004 01:54:01 -0700 Subject: [PATCH] Module section offsets in /sys/module So here I am trying to write about how one can apply gdb to a running kernel, and I'd like to tell people how to debug loadable modules. Only with the 2.6 module loader, there's no way to find out where the various sections in the module image ended up, so you can't do much. This patch attempts to fix that by adding a "sections" subdirectory to every module's entry in /sys/module; each attribute in that directory associates a beginning address with the section name. Those attributes can be used by a a simple script to generate an add-symbol-file command for gdb, something like: #!/bin/bash # # gdbline module image # # Outputs an add-symbol-file line suitable for pasting into gdb to examine # a loaded module. # cd /sys/module/$1/sections echo -n add-symbol-file $2 `/bin/cat .text` for section in .[a-z]* *; do if [ $section != ".text" ]; then echo " \\" echo -n " -s" $section `/bin/cat $section` fi done echo Currently, this feature is absent if CONFIG_KALLSYMS is not set. I do wonder if CONFIG_DEBUG_INFO might not be a better choice, now that I think about it. Section names are unmunged, so "ls -a" is needed to see most of them. Signed-off-by: Greg Kroah-Hartman --- include/linux/module.h | 19 ++++++++++ kernel/module.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/include/linux/module.h b/include/linux/module.h index 2709330e8684..2ad187c3bda1 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -225,6 +225,22 @@ struct module_kobject struct module_attribute attr[0]; }; +/* Similar stuff for section attributes. */ +#define MODULE_SECT_NAME_LEN 32 +struct module_sect_attr +{ + struct attribute attr; + char name[MODULE_SECT_NAME_LEN]; + unsigned long address; +}; + +struct module_sections +{ + struct kobject kobj; + struct module_sect_attr attrs[0]; +}; + + struct module { enum module_state state; @@ -298,6 +314,9 @@ struct module Elf_Sym *symtab; unsigned long num_symtab; char *strtab; + + /* Section attributes */ + struct module_sections *sect_attrs; #endif /* Per-cpu data. */ diff --git a/kernel/module.c b/kernel/module.c index e7a73bac2d58..08b14bc7b299 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -981,6 +981,104 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs, return ret; } + +/* + * /sys/module/foo/sections stuff + * J. Corbet + */ +#ifdef CONFIG_KALLSYMS +static void module_sect_attrs_release(struct kobject *kobj) +{ + kfree(container_of(kobj, struct module_sections, kobj)); +} + +static ssize_t module_sect_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct module_sect_attr *sattr = + container_of(attr, struct module_sect_attr, attr); + return sprintf(buf, "0x%lx\n", sattr->address); +} + +static struct sysfs_ops module_sect_ops = { + .show = module_sect_show, +}; + +static struct kobj_type module_sect_ktype = { + .sysfs_ops = &module_sect_ops, + .release = module_sect_attrs_release, +}; + +static void add_sect_attrs(struct module *mod, unsigned int nsect, + char *secstrings, Elf_Shdr *sechdrs) +{ + unsigned int nloaded = 0, i; + struct module_sect_attr *sattr; + + if (!mod->mkobj) + return; + + /* Count loaded sections and allocate structures */ + for (i = 0; i < nsect; i++) + if (sechdrs[i].sh_flags & SHF_ALLOC) + nloaded++; + mod->sect_attrs = kmalloc(sizeof(struct module_sections) + + nloaded*sizeof(mod->sect_attrs->attrs[0]), GFP_KERNEL); + if (! mod->sect_attrs) + return; + + /* sections entry setup */ + memset(mod->sect_attrs, 0, sizeof(struct module_sections)); + if (kobject_set_name(&mod->sect_attrs->kobj, "sections")) + goto out; + mod->sect_attrs->kobj.parent = &mod->mkobj->kobj; + mod->sect_attrs->kobj.ktype = &module_sect_ktype; + if (kobject_register(&mod->sect_attrs->kobj)) + goto out; + + /* And the section attributes. */ + sattr = &mod->sect_attrs->attrs[0]; + for (i = 0; i < nsect; i++) { + if (! (sechdrs[i].sh_flags & SHF_ALLOC)) + continue; + sattr->address = sechdrs[i].sh_addr; + strlcpy(sattr->name, secstrings + sechdrs[i].sh_name, + MODULE_SECT_NAME_LEN); + sattr->attr.name = sattr->name; + sattr->attr.owner = mod; + sattr->attr.mode = S_IRUGO; + (void) sysfs_create_file(&mod->sect_attrs->kobj, &sattr->attr); + sattr++; + } + return; + out: + kfree(mod->sect_attrs); + mod->sect_attrs = NULL; +} + +static void remove_sect_attrs(struct module *mod) +{ + if (mod->sect_attrs) { + kobject_unregister(&mod->sect_attrs->kobj); + mod->sect_attrs = NULL; + } +} + + +#else +static inline void add_sect_attrs(struct module *mod, unsigned int nsect, + char *sectstrings, Elf_Shdr *sechdrs) +{ +} + +static inline void remove_sect_attrs(struct module *mod) +{ +} +#endif /* CONFIG_KALLSYMS */ + + + + #define to_module_attr(n) container_of(n, struct module_attribute, attr); static ssize_t module_attr_show(struct kobject *kobj, @@ -1099,6 +1197,7 @@ static void free_module(struct module *mod) list_del(&mod->list); spin_unlock_irq(&modlist_lock); + remove_sect_attrs(mod); mod_kobject_remove(mod); /* Arch-specific cleanup. */ @@ -1712,6 +1811,7 @@ static struct module *load_module(void __user *umod, / sizeof(struct kernel_param)); if (err < 0) goto arch_cleanup; + add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); /* Get rid of temporary copy */ vfree(hdr); -- cgit v1.2.3 From 03769bf6834267005c00d1aa396b9bd051ea27fb Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 4 Jun 2004 02:48:04 -0700 Subject: Driver core: finally add a MAINTAINERS entry for it. Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5f2455edb156..c544bc5c2f08 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -689,6 +689,12 @@ M: jrv@vanzandt.mv.com L: blinux-list@redhat.com S: Maintained +DRIVER CORE, KOBJECTS, AND SYSFS +P: Greg Kroah-Hartman +M: greg@kroah.com +L: linux-kernel@vger.kernel.org +S: Supported + DRM DRIVERS L: dri-devel@lists.sourceforge.net S: Supported -- cgit v1.2.3 From 74e584091e0f5db560f74dfefe555cb0e483c113 Mon Sep 17 00:00:00 2001 From: "Mark M. Hoffman" Date: Tue, 8 Jun 2004 00:31:15 -0700 Subject: [PATCH] I2C: add alternate VCORE calculations for w83627thf and w83637hf This patch adds support for the alternate in0/VCORE calculation which is available for 2 of 4 chips this driver supports. It also fixes a minor bug in the standard voltage input calculation. Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/w83627hf.c | 94 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c index c38a7f9712b6..79ee74effaac 100644 --- a/drivers/i2c/chips/w83627hf.c +++ b/drivers/i2c/chips/w83627hf.c @@ -199,7 +199,7 @@ superio_exit(void) #define W83627THF_REG_PWM2 0x03 /* 697HF and 637HF too */ #define W83627THF_REG_PWM3 0x11 /* 637HF too */ -#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF too, unused yet */ +#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF too */ static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 }; static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2, @@ -222,7 +222,7 @@ static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; these macros are called: arguments may be evaluated more than once. Fixing this is just not worth it. */ #define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255)) -#define IN_FROM_REG(val) ((val) * 16 + 5) +#define IN_FROM_REG(val) ((val) * 16) static inline u8 FAN_TO_REG(long rpm, int div) { @@ -312,6 +312,7 @@ struct w83627hf_data { Default = 3435. Other Betas unimplemented */ u8 vrm; + u8 vrm_ovt; /* Register value, 627thf & 637hf only */ }; @@ -391,7 +392,6 @@ sysfs_in_offset(offset) \ sysfs_in_reg_offset(min, offset) \ sysfs_in_reg_offset(max, offset) -sysfs_in_offsets(0) sysfs_in_offsets(1) sysfs_in_offsets(2) sysfs_in_offsets(3) @@ -401,6 +401,89 @@ sysfs_in_offsets(6) sysfs_in_offsets(7) sysfs_in_offsets(8) +/* use a different set of functions for in0 */ +static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg) +{ + long in0; + + if ((data->vrm_ovt & 0x01) && + (w83627thf == data->type || w83637hf == data->type)) + + /* use VRM9 calculation */ + in0 = (long)((reg * 488 + 70000 + 50) / 100); + else + /* use VRM8 (standard) calculation */ + in0 = (long)IN_FROM_REG(reg); + + return sprintf(buf,"%ld\n", in0); +} + +static ssize_t show_regs_in_0(struct device *dev, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return show_in_0(data, buf, data->in[0]); +} + +static ssize_t show_regs_in_min0(struct device *dev, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return show_in_0(data, buf, data->in_min[0]); +} + +static ssize_t show_regs_in_max0(struct device *dev, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return show_in_0(data, buf, data->in_max[0]); +} + +static ssize_t store_regs_in_min0(struct device *dev, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + if ((data->vrm_ovt & 0x01) && + (w83627thf == data->type || w83637hf == data->type)) + + /* use VRM9 calculation */ + data->in_min[0] = (u8)(((val * 100) - 70000 + 244) / 488); + else + /* use VRM8 (standard) calculation */ + data->in_min[0] = IN_TO_REG(val); + + w83627hf_write_value(client, W83781D_REG_IN_MIN(0), data->in_min[0]); + return count; +} + +static ssize_t store_regs_in_max0(struct device *dev, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + if ((data->vrm_ovt & 0x01) && + (w83627thf == data->type || w83637hf == data->type)) + + /* use VRM9 calculation */ + data->in_max[0] = (u8)(((val * 100) - 70000 + 244) / 488); + else + /* use VRM8 (standard) calculation */ + data->in_max[0] = IN_TO_REG(val); + + w83627hf_write_value(client, W83781D_REG_IN_MAX(0), data->in_max[0]); + return count; +} + +static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL) +static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, + show_regs_in_min0, store_regs_in_min0) +static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, + show_regs_in_max0, store_regs_in_max0) + #define device_create_file_in(client, offset) \ do { \ device_create_file(&client->dev, &dev_attr_in##offset##_input); \ @@ -1191,6 +1274,11 @@ static void w83627hf_init_client(struct i2c_client *client) data->vid = w83627thf_read_gpio5(client) & 0x1f; } + /* Read VRM & OVT Config only once */ + if (w83627thf == data->type || w83637hf == data->type) + data->vrm_ovt = + w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG); + /* Convert VID to voltage based on default VRM */ data->vrm = DEFAULT_VRM; if (type != w83697hf) -- cgit v1.2.3 From 41ea291a0dcd8883bcd20d1635ba2a669e71c236 Mon Sep 17 00:00:00 2001 From: Jonas Munsin Date: Tue, 8 Jun 2004 00:36:23 -0700 Subject: [PATCH] I2C: drivers/i2c/chips/it87.c cleanup patch Attached is a cleanup patch for the it87 sensor driver, against 2.6.7-rc2. Jean Delvare has reviewed it. Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/it87.c | 48 ++++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c index 061a0b8009b5..bf29e7d9759e 100644 --- a/drivers/i2c/chips/it87.c +++ b/drivers/i2c/chips/it87.c @@ -128,15 +128,15 @@ static int reset; #define IT87_REG_FAN(nr) (0x0d + (nr)) #define IT87_REG_FAN_MIN(nr) (0x10 + (nr)) -#define IT87_REG_FAN_CTRL 0x13 +#define IT87_REG_FAN_MAIN_CTRL 0x13 #define IT87_REG_VIN(nr) (0x20 + (nr)) #define IT87_REG_TEMP(nr) (0x29 + (nr)) #define IT87_REG_VIN_MAX(nr) (0x30 + (nr) * 2) #define IT87_REG_VIN_MIN(nr) (0x31 + (nr) * 2) -#define IT87_REG_TEMP_HIGH(nr) (0x40 + ((nr) * 2)) -#define IT87_REG_TEMP_LOW(nr) (0x41 + ((nr) * 2)) +#define IT87_REG_TEMP_HIGH(nr) (0x40 + (nr) * 2) +#define IT87_REG_TEMP_LOW(nr) (0x41 + (nr) * 2) #define IT87_REG_I2C_ADDR 0x48 @@ -145,8 +145,8 @@ static int reset; #define IT87_REG_CHIPID 0x58 -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) -#define IN_FROM_REG(val) (((val) * 16) / 10) +#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255)) +#define IN_FROM_REG(val) ((val) * 16) static inline u8 FAN_TO_REG(long rpm, int div) { @@ -159,9 +159,9 @@ static inline u8 FAN_TO_REG(long rpm, int div) #define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\ - ((val)+5)/10),0,255)) -#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10) +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-500)/1000):\ + ((val)+500)/1000),-128,127)) +#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000) #define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ 205-(val)*5) @@ -231,19 +231,19 @@ static int it87_id = 0; static ssize_t show_in(struct device *dev, char *buf, int nr) { struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])*10 ); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); } static ssize_t show_in_min(struct device *dev, char *buf, int nr) { struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])*10 ); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); } static ssize_t show_in_max(struct device *dev, char *buf, int nr) { struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])*10 ); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); } static ssize_t set_in_min(struct device *dev, const char *buf, @@ -251,7 +251,7 @@ static ssize_t set_in_min(struct device *dev, const char *buf, { struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10)/10; + unsigned long val = simple_strtoul(buf, NULL, 10); data->in_min[nr] = IN_TO_REG(val); it87_write_value(client, IT87_REG_VIN_MIN(nr), data->in_min[nr]); @@ -262,7 +262,7 @@ static ssize_t set_in_max(struct device *dev, const char *buf, { struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10)/10; + unsigned long val = simple_strtoul(buf, NULL, 10); data->in_max[nr] = IN_TO_REG(val); it87_write_value(client, IT87_REG_VIN_MAX(nr), data->in_max[nr]); @@ -325,24 +325,24 @@ show_in_offset(8); static ssize_t show_temp(struct device *dev, char *buf, int nr) { struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])*100 ); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); } static ssize_t show_temp_max(struct device *dev, char *buf, int nr) { struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])*100); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])); } static ssize_t show_temp_min(struct device *dev, char *buf, int nr) { struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])*100); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])); } static ssize_t set_temp_max(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10)/100; + int val = simple_strtol(buf, NULL, 10); data->temp_high[nr] = TEMP_TO_REG(val); it87_write_value(client, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]); return count; @@ -352,7 +352,7 @@ static ssize_t set_temp_min(struct device *dev, const char *buf, { struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10)/100; + int val = simple_strtol(buf, NULL, 10); data->temp_low[nr] = TEMP_TO_REG(val); it87_write_value(client, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]); return count; @@ -773,9 +773,7 @@ static int it87_detach_client(struct i2c_client *client) We don't want to lock the whole ISA bus, so we lock each client separately. We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, - would slow down the IT87 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ + would slow down the IT87 access and should not be necessary. */ static int it87_read_value(struct i2c_client *client, u8 reg) { struct it87_data *data = i2c_get_clientdata(client); @@ -795,9 +793,7 @@ static int it87_read_value(struct i2c_client *client, u8 reg) We don't want to lock the whole ISA bus, so we lock each client separately. We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, - would slow down the IT87 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ + would slow down the IT87 access and should not be necessary. */ static int it87_write_value(struct i2c_client *client, u8 reg, u8 value) { struct it87_data *data = i2c_get_clientdata(client); @@ -840,11 +836,11 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data) } /* Check if tachometers are reset manually or by some reason */ - tmp = it87_read_value(client, IT87_REG_FAN_CTRL); + tmp = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL); if ((tmp & 0x70) == 0) { /* Enable all fan tachometers */ tmp = (tmp & 0x8f) | 0x70; - it87_write_value(client, IT87_REG_FAN_CTRL, tmp); + it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, tmp); } /* Start monitoring */ -- cgit v1.2.3 From 7851ac39d57c2c2529cc7d4de71e41a1e91281ce Mon Sep 17 00:00:00 2001 From: "Hanna V. Linder" Date: Tue, 8 Jun 2004 02:26:12 -0700 Subject: [PATCH] Add cpu hotplug support to cpuid.c Here is the patch that uses a cpu hotplug callback, to allow dynamic support of cpu id for classes in sysfs. This patch applies on top of the one I sent out earlier that Greg included. I do not have access to hardware that supports cpu hotswapping (virtually or not) so have not been able to test that aspect of the patch. However, the original functionality of listing static cpu's still works. Please consider for testing or inclusion. Signed-off-by: Hanna Linder Signed-off-by: Greg Kroah-Hartman --- arch/i386/kernel/cpuid.c | 59 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c index 303f4eb42cbd..3560c41308b2 100644 --- a/arch/i386/kernel/cpuid.c +++ b/arch/i386/kernel/cpuid.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include #include @@ -156,10 +158,48 @@ static struct file_operations cpuid_fops = { .open = cpuid_open, }; +static void cpuid_class_simple_device_remove(void) +{ + int i = 0; + for_each_online_cpu(i) + class_simple_device_remove(MKDEV(CPUID_MAJOR, i)); + return; +} + +static int cpuid_class_simple_device_add(int i) +{ + int err = 0; + struct class_device *class_err; + + class_err = class_simple_device_add(cpuid_class, MKDEV(CPUID_MAJOR, i), NULL, "cpu%d",i); + if (IS_ERR(class_err)) { + err = PTR_ERR(class_err); + } + return err; +} +static int __devinit cpuid_class_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + + switch(action) { + case CPU_ONLINE: + cpuid_class_simple_device_add(cpu); + break; + case CPU_DEAD: + cpuid_class_simple_device_remove(); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block cpuid_class_cpu_notifier = +{ + .notifier_call = cpuid_class_cpu_callback, +}; + int __init cpuid_init(void) { int i, err = 0; - struct class_device *class_err; i = 0; if (register_chrdev(CPUID_MAJOR, "cpu/cpuid", &cpuid_fops)) { @@ -174,19 +214,17 @@ int __init cpuid_init(void) goto out_chrdev; } for_each_online_cpu(i) { - class_err = class_simple_device_add(cpuid_class, MKDEV(CPUID_MAJOR, i), NULL, "cpu%d",i); - if (IS_ERR(class_err)) { - err = PTR_ERR(class_err); + err = cpuid_class_simple_device_add(i); + if (err != 0) goto out_class; - } } + register_cpu_notifier(&cpuid_class_cpu_notifier); + err = 0; goto out; out_class: - i = 0; - for_each_online_cpu(i) - class_simple_device_remove(MKDEV(CPUID_MAJOR, i)); + cpuid_class_simple_device_remove(); class_simple_destroy(cpuid_class); out_chrdev: unregister_chrdev(CPUID_MAJOR, "cpu/cpuid"); @@ -196,11 +234,10 @@ out: void __exit cpuid_exit(void) { - int i = 0; - for_each_online_cpu(i) - class_simple_device_remove(MKDEV(CPUID_MAJOR, i)); + cpuid_class_simple_device_remove(); class_simple_destroy(cpuid_class); unregister_chrdev(CPUID_MAJOR, "cpu/cpuid"); + unregister_cpu_notifier(&cpuid_class_cpu_notifier); } module_init(cpuid_init); -- cgit v1.2.3 From e13724956849975ef40cbc9898643f3074a1ed8a Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jun 2004 02:28:02 -0700 Subject: [PATCH] Add platform_get_resource() This patch adds management of platform device resources to the device model, allowing drivers to lookup resources, IRQs and DMA numbers in the platform device resource array. We also add a couple of functions which allow platform devices and their resources to be registered. Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/device.h | 5 +++ 2 files changed, 91 insertions(+) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 0d75909a4538..43c7b12870c0 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -18,6 +18,90 @@ struct device platform_bus = { .bus_id = "platform", }; +/** + * platform_get_resource - get a resource for a device + * @dev: platform device + * @type: resource type + * @num: resource index + */ +struct resource * +platform_get_resource(struct platform_device *dev, unsigned int type, + unsigned int num) +{ + int i; + + for (i = 0; i < dev->num_resources; i++) { + struct resource *r = &dev->resource[i]; + + if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM| + IORESOURCE_IRQ|IORESOURCE_DMA)) + == type) + if (num-- == 0) + return r; + } + return NULL; +} + +/** + * platform_get_irq - get an IRQ for a device + * @dev: platform device + * @num: IRQ number index + */ +int platform_get_irq(struct platform_device *dev, unsigned int num) +{ + struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num); + + return r ? r->start : 0; +} + +/** + * platform_add_device - add one platform device + * @dev: platform device + * + * Adds one platform device, claiming the memory resources + */ +int platform_add_device(struct platform_device *dev) +{ + int i; + + for (i = 0; i < dev->num_resources; i++) { + struct resource *p, *r = &dev->resource[i]; + + r->name = dev->dev.bus_id; + + p = NULL; + if (r->flags & IORESOURCE_MEM) + p = &iomem_resource; + else if (r->flags & IORESOURCE_IO) + p = &ioport_resource; + + if (p && request_resource(p, r)) { + printk(KERN_ERR + "%s%d: failed to claim resource %d\n", + dev->name, dev->id, i); + break; + } + } + if (i == dev->num_resources) + platform_device_register(dev); + return 0; +} + +/** + * platform_add_devices - add a numbers of platform devices + * @devs: array of platform devices to add + * @num: number of platform devices in array + */ +int platform_add_devices(struct platform_device **devs, int num) +{ + int i; + + for (i = 0; i < num; i++) + platform_add_device(devs[i]); + + return 0; +} + /** * platform_device_register - add a platform-level device * @dev: platform device we're adding @@ -114,3 +198,5 @@ EXPORT_SYMBOL(platform_bus); EXPORT_SYMBOL(platform_bus_type); EXPORT_SYMBOL(platform_device_register); EXPORT_SYMBOL(platform_device_unregister); +EXPORT_SYMBOL(platform_get_irq); +EXPORT_SYMBOL(platform_get_resource); diff --git a/include/linux/device.h b/include/linux/device.h index c91a6b481534..ed170f81ab60 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -377,6 +377,11 @@ extern void platform_device_unregister(struct platform_device *); extern struct bus_type platform_bus_type; extern struct device platform_bus; +extern struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int); +extern int platform_get_irq(struct platform_device *, unsigned int); +extern int platform_add_device(struct platform_device *); +extern int platform_add_devices(struct platform_device **, int); + /* drivers/base/power.c */ extern void device_shutdown(void); -- cgit v1.2.3 From fce72d4bb592da5890d2b83dd22d6e4a5f46c7e0 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 8 Jun 2004 08:45:12 -0700 Subject: cpuid: fix hotplug cpu remove bug for class device. Signed-off-by: Greg Kroah-Hartman --- arch/i386/kernel/cpuid.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c index 3560c41308b2..32a0984318f6 100644 --- a/arch/i386/kernel/cpuid.c +++ b/arch/i386/kernel/cpuid.c @@ -158,35 +158,27 @@ static struct file_operations cpuid_fops = { .open = cpuid_open, }; -static void cpuid_class_simple_device_remove(void) -{ - int i = 0; - for_each_online_cpu(i) - class_simple_device_remove(MKDEV(CPUID_MAJOR, i)); - return; -} - static int cpuid_class_simple_device_add(int i) { int err = 0; struct class_device *class_err; class_err = class_simple_device_add(cpuid_class, MKDEV(CPUID_MAJOR, i), NULL, "cpu%d",i); - if (IS_ERR(class_err)) { + if (IS_ERR(class_err)) err = PTR_ERR(class_err); - } return err; } + static int __devinit cpuid_class_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; - switch(action) { + switch (action) { case CPU_ONLINE: cpuid_class_simple_device_add(cpu); break; case CPU_DEAD: - cpuid_class_simple_device_remove(); + class_simple_device_remove(MKDEV(CPUID_MAJOR, cpu)); break; } return NOTIFY_OK; @@ -224,7 +216,10 @@ int __init cpuid_init(void) goto out; out_class: - cpuid_class_simple_device_remove(); + i = 0; + for_each_online_cpu(i) { + class_simple_device_remove(MKDEV(CPUID_MAJOR, i)); + } class_simple_destroy(cpuid_class); out_chrdev: unregister_chrdev(CPUID_MAJOR, "cpu/cpuid"); @@ -234,7 +229,10 @@ out: void __exit cpuid_exit(void) { - cpuid_class_simple_device_remove(); + int cpu = 0; + + for_each_online_cpu(cpu) + class_simple_device_remove(MKDEV(CPUID_MAJOR, cpu)); class_simple_destroy(cpuid_class); unregister_chrdev(CPUID_MAJOR, "cpu/cpuid"); unregister_cpu_notifier(&cpuid_class_cpu_notifier); -- cgit v1.2.3 From 75114dccc881e6059c3fcb5fb79860df59b0b1bb Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 8 Jun 2004 20:34:09 -0700 Subject: [PATCH] I2C: w83627hf.c build fix with gcc-2.95: drivers/i2c/chips/w83627hf.c:482: parse error before `static' drivers/i2c/chips/w83627hf.c:502: parse error before `static' drivers/i2c/chips/w83627hf.c: In function `show_regs_fan_1': drivers/i2c/chips/w83627hf.c:541: warning: implicit declaration of function `show_fan' drivers/i2c/chips/w83627hf.c: In function `w83627hf_detect': drivers/i2c/chips/w83627hf.c:1074: `dev_attr_in0_min' undeclared (first use in this function) drivers/i2c/chips/w83627hf.c:1074: (Each undeclared identifier is reported only once drivers/i2c/chips/w83627hf.c:1074: for each function it appears in.) drivers/i2c/chips/w83627hf.c: At top level: drivers/i2c/chips/w83627hf.c:428: warning: `show_regs_in_min0' defined but not used drivers/i2c/chips/w83627hf.c:441: warning: `store_regs_in_min0' defined but not used Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/w83627hf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c index feff121763ee..7419f9541949 100644 --- a/drivers/i2c/chips/w83627hf.c +++ b/drivers/i2c/chips/w83627hf.c @@ -478,11 +478,11 @@ static ssize_t store_regs_in_max0(struct device *dev, return count; } -static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL) +static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL); static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, - show_regs_in_min0, store_regs_in_min0) + show_regs_in_min0, store_regs_in_min0); static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, - show_regs_in_max0, store_regs_in_max0) + show_regs_in_max0, store_regs_in_max0); #define device_create_file_in(client, offset) \ do { \ -- cgit v1.2.3 From 2d586ba5396ae2eed82932af10cde3f27d62140b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 9 Jun 2004 19:25:58 -0700 Subject: [PATCH] Driver Core: Suppress platform device suffixes Do not add numeric suffix to platform device name if device id is set to -1. This can be used when there can be only one instance of a device (like i8042). Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 43c7b12870c0..4f7c5e85af24 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -117,7 +117,10 @@ int platform_device_register(struct platform_device * pdev) pdev->dev.bus = &platform_bus_type; - snprintf(pdev->dev.bus_id,BUS_ID_SIZE,"%s%u",pdev->name,pdev->id); + if (pdev->id != -1) + snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s%u", pdev->name, pdev->id); + else + strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE); pr_debug("Registering platform device '%s'. Parent at %s\n", pdev->dev.bus_id,pdev->dev.parent->bus_id); -- cgit v1.2.3 From bd7d075ad7051c61612995062d666015ea57a2dc Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 9 Jun 2004 19:34:27 -0700 Subject: [PATCH] Driver Core: Whitespace fixes Whitespace and formatting changes (a,b,c -> a, b, c) in drivers/base Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 5 ++- drivers/base/class_simple.c | 12 ++--- drivers/base/core.c | 46 +++++++++---------- drivers/base/driver.c | 16 +++---- drivers/base/firmware.c | 6 +-- drivers/base/firmware_class.c | 10 ++--- drivers/base/init.c | 4 +- drivers/base/interface.c | 18 ++++---- drivers/base/node.c | 14 +++--- drivers/base/platform.c | 18 ++++---- drivers/base/power/main.c | 14 +++--- drivers/base/power/power.h | 8 ++-- drivers/base/power/resume.c | 12 ++--- drivers/base/power/runtime.c | 8 ++-- drivers/base/power/shutdown.c | 18 ++++---- drivers/base/power/suspend.c | 42 ++++++++--------- drivers/base/power/sysfs.c | 18 ++++---- drivers/base/sys.c | 102 +++++++++++++++++++++--------------------- 18 files changed, 186 insertions(+), 185 deletions(-) diff --git a/drivers/base/base.h b/drivers/base/base.h index da16cc5c9e30..8d1e8bd48632 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -6,12 +6,13 @@ extern void bus_remove_driver(struct device_driver *); static inline struct class_device *to_class_dev(struct kobject *obj) { - return container_of(obj,struct class_device,kobj); + return container_of(obj, struct class_device, kobj); } + static inline struct class_device_attribute *to_class_dev_attr(struct attribute *_attr) { - return container_of(_attr,struct class_device_attribute,attr); + return container_of(_attr, struct class_device_attribute, attr); } diff --git a/drivers/base/class_simple.c b/drivers/base/class_simple.c index 20707be0dcd7..3410636de0a5 100644 --- a/drivers/base/class_simple.c +++ b/drivers/base/class_simple.c @@ -3,7 +3,7 @@ * * Copyright (c) 2003-2004 Greg Kroah-Hartman * Copyright (c) 2003-2004 IBM Corp. - * + * * This file is released under the GPLv2 * */ @@ -111,7 +111,7 @@ EXPORT_SYMBOL(class_simple_destroy); /** * class_simple_device_add - adds a class device to sysfs for a character driver - * @cs: pointer to the struct class_simple that this device should be registered to. + * @cs: pointer to the struct class_simple that this device should be registered to. * @dev: the dev_t for the device to be added. * @device: a pointer to a struct device that is assiociated with this class device. * @fmt: string for the class device's name @@ -146,8 +146,8 @@ struct class_device *class_simple_device_add(struct class_simple *cs, dev_t dev, s_dev->dev = dev; s_dev->class_dev.dev = device; s_dev->class_dev.class = &cs->class; - - va_start(args,fmt); + + va_start(args, fmt); vsnprintf(s_dev->class_dev.class_id, BUS_ID_SIZE, fmt, args); va_end(args); retval = class_device_register(&s_dev->class_dev); @@ -173,10 +173,10 @@ EXPORT_SYMBOL(class_simple_device_add); * @cs: pointer to the struct class_simple to hold the pointer * @hotplug: function pointer to the hotplug function * - * Implement and set a hotplug function to add environment variables specific to this + * Implement and set a hotplug function to add environment variables specific to this * class on the hotplug event. */ -int class_simple_set_hotplug(struct class_simple *cs, +int class_simple_set_hotplug(struct class_simple *cs, int (*hotplug)(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size)) { if ((cs == NULL) || (IS_ERR(cs))) diff --git a/drivers/base/core.c b/drivers/base/core.c index afc336876a13..3325810c42ab 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -3,7 +3,7 @@ * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs - * + * * This file is released under the GPLv2 * */ @@ -28,8 +28,8 @@ int (*platform_notify_remove)(struct device * dev) = NULL; * sysfs bindings for devices. */ -#define to_dev(obj) container_of(obj,struct device,kobj) -#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr) +#define to_dev(obj) container_of(obj, struct device, kobj) +#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) extern struct attribute * dev_default_attrs[]; @@ -41,12 +41,12 @@ dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) ssize_t ret = 0; if (dev_attr->show) - ret = dev_attr->show(dev,buf); + ret = dev_attr->show(dev, buf); return ret; } static ssize_t -dev_attr_store(struct kobject * kobj, struct attribute * attr, +dev_attr_store(struct kobject * kobj, struct attribute * attr, const char * buf, size_t count) { struct device_attribute * dev_attr = to_dev_attr(attr); @@ -54,7 +54,7 @@ dev_attr_store(struct kobject * kobj, struct attribute * attr, ssize_t ret = 0; if (dev_attr->store) - ret = dev_attr->store(dev,buf,count); + ret = dev_attr->store(dev, buf, count); return ret; } @@ -153,7 +153,7 @@ int device_create_file(struct device * dev, struct device_attribute * attr) { int error = 0; if (get_device(dev)) { - error = sysfs_create_file(&dev->kobj,&attr->attr); + error = sysfs_create_file(&dev->kobj, &attr->attr); put_device(dev); } return error; @@ -168,7 +168,7 @@ int device_create_file(struct device * dev, struct device_attribute * attr) void device_remove_file(struct device * dev, struct device_attribute * attr) { if (get_device(dev)) { - sysfs_remove_file(&dev->kobj,&attr->attr); + sysfs_remove_file(&dev->kobj, &attr->attr); put_device(dev); } } @@ -179,7 +179,7 @@ void device_remove_file(struct device * dev, struct device_attribute * attr) * @dev: device. * * This prepares the device for use by other layers, - * including adding it to the device hierarchy. + * including adding it to the device hierarchy. * It is the first half of device_register(), if called by * that, though it can also be called separately, so one * may use @dev's fields (e.g. the refcount). @@ -187,7 +187,7 @@ void device_remove_file(struct device * dev, struct device_attribute * attr) void device_initialize(struct device *dev) { - kobj_set_kset_s(dev,devices_subsys); + kobj_set_kset_s(dev, devices_subsys); kobject_init(&dev->kobj); INIT_LIST_HEAD(&dev->node); INIT_LIST_HEAD(&dev->children); @@ -200,7 +200,7 @@ void device_initialize(struct device *dev) * device_add - add device to device hierarchy. * @dev: device. * - * This is part 2 of device_register(), though may be called + * This is part 2 of device_register(), though may be called * separately _iff_ device_initialize() has been called separately. * * This adds it to the kobject hierarchy via kobject_add(), adds it @@ -221,7 +221,7 @@ int device_add(struct device *dev) pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); /* first, register with generic layer. */ - kobject_set_name(&dev->kobj,dev->bus_id); + kobject_set_name(&dev->kobj, dev->bus_id); if (parent) dev->kobj.parent = &parent->kobj; @@ -233,7 +233,7 @@ int device_add(struct device *dev) goto BusError; down_write(&devices_subsys.rwsem); if (parent) - list_add_tail(&dev->node,&parent->children); + list_add_tail(&dev->node, &parent->children); up_write(&devices_subsys.rwsem); /* notify platform of device entry */ @@ -258,9 +258,9 @@ int device_add(struct device *dev) * @dev: pointer to the device structure * * This happens in two clean steps - initialize the device - * and add it to the system. The two steps can be called - * separately, but this is the easiest and most common. - * I.e. you should only call the two helpers separately if + * and add it to the system. The two steps can be called + * separately, but this is the easiest and most common. + * I.e. you should only call the two helpers separately if * have a clearly defined need to use and refcount the device * before it is added to the hierarchy. */ @@ -301,13 +301,13 @@ void put_device(struct device * dev) * device_del - delete device from system. * @dev: device. * - * This is the first part of the device unregistration + * This is the first part of the device unregistration * sequence. This removes the device from the lists we control - * from here, has it removed from the other driver model + * from here, has it removed from the other driver model * subsystems it was added to in device_add(), and removes it * from the kobject hierarchy. * - * NOTE: this should be called manually _iff_ device_add() was + * NOTE: this should be called manually _iff_ device_add() was * also called manually. */ @@ -340,7 +340,7 @@ void device_del(struct device * dev) * we remove it from all the subsystems with device_del(), then * we decrement the reference count via put_device(). If that * is the final reference count, the device will be cleaned up - * via device_release() above. Otherwise, the structure will + * via device_release() above. Otherwise, the structure will * stick around until the final reference to the device is dropped. */ void device_unregister(struct device * dev) @@ -358,7 +358,7 @@ void device_unregister(struct device * dev) * @fn: function to be called for each device. * * Iterate over @dev's child devices, and call @fn for each, - * passing it @data. + * passing it @data. * * We check the return of @fn each time. If it returns anything * other than 0, we break out and return that value. @@ -370,8 +370,8 @@ int device_for_each_child(struct device * dev, void * data, int error = 0; down_read(&devices_subsys.rwsem); - list_for_each_entry(child,&dev->children,node) { - if((error = fn(child,data))) + list_for_each_entry(child, &dev->children, node) { + if((error = fn(child, data))) break; } up_read(&devices_subsys.rwsem); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 0236ba33542b..0604b2b20e6f 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -3,7 +3,7 @@ * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs - * + * * This file is released under the GPLv2 * */ @@ -15,8 +15,8 @@ #include #include "base.h" -#define to_dev(node) container_of(node,struct device,driver_list) -#define to_drv(obj) container_of(obj,struct device_driver,kobj) +#define to_dev(node) container_of(node, struct device, driver_list) +#define to_drv(obj) container_of(obj, struct device_driver, kobj) /** * driver_create_file - create sysfs file for driver. @@ -28,7 +28,7 @@ int driver_create_file(struct device_driver * drv, struct driver_attribute * att { int error; if (get_driver(drv)) { - error = sysfs_create_file(&drv->kobj,&attr->attr); + error = sysfs_create_file(&drv->kobj, &attr->attr); put_driver(drv); } else error = -EINVAL; @@ -45,7 +45,7 @@ int driver_create_file(struct device_driver * drv, struct driver_attribute * att void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr) { if (get_driver(drv)) { - sysfs_remove_file(&drv->kobj,&attr->attr); + sysfs_remove_file(&drv->kobj, &attr->attr); put_driver(drv); } } @@ -76,7 +76,7 @@ void put_driver(struct device_driver * drv) * @drv: driver to register * * We pass off most of the work to the bus_add_driver() call, - * since most of the things we have to do deal with the bus + * since most of the things we have to do deal with the bus * structures. * * The one interesting aspect is that we initialize @drv->unload_sem @@ -99,8 +99,8 @@ int driver_register(struct device_driver * drv) * * Though, once that is done, we attempt to take @drv->unload_sem. * This will block until the driver refcount reaches 0, and it is - * released. Only modular drivers will call this function, and we - * have to guarantee that it won't complete, letting the driver + * released. Only modular drivers will call this function, and we + * have to guarantee that it won't complete, letting the driver * unload until all references are gone. */ diff --git a/drivers/base/firmware.c b/drivers/base/firmware.c index 886d4961498b..0cff0498ea8b 100644 --- a/drivers/base/firmware.c +++ b/drivers/base/firmware.c @@ -3,7 +3,7 @@ * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs - * + * * This file is released under the GPLv2 * */ @@ -12,11 +12,11 @@ #include #include -static decl_subsys(firmware,NULL,NULL); +static decl_subsys(firmware, NULL, NULL); int firmware_register(struct subsystem * s) { - kset_set_kset_s(s,firmware_subsys); + kset_set_kset_s(s, firmware_subsys); return subsystem_register(s); } diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 8ff239f146cf..a57ba84eb2c6 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -68,7 +68,7 @@ firmware_timeout_show(struct class *class, char *buf) * firmware will be provided. * * Note: zero means 'wait for ever' - * + * **/ static ssize_t firmware_timeout_store(struct class *class, const char *buf, size_t count) @@ -121,7 +121,7 @@ firmware_loading_show(struct class_device *class_dev, char *buf) /** * firmware_loading_store: - loading control file * Description: - * The relevant values are: + * The relevant values are: * * 1: Start a load, discarding any previous partial load. * 0: Conclude the load and handle the data to the driver code. @@ -376,7 +376,7 @@ out: return retval; } -/** +/** * request_firmware: - request firmware to hotplug and wait for it * Description: * @firmware will be used to return a firmware image by the name @@ -457,7 +457,7 @@ release_firmware(const struct firmware *fw) /** * register_firmware: - provide a firmware image for later usage - * + * * Description: * Make sure that @data will be available by requesting firmware @name. * @@ -541,7 +541,7 @@ request_firmware_nowait( ret = kernel_thread(request_firmware_work_func, fw_work, CLONE_FS | CLONE_FILES); - + if (ret < 0) { fw_work->cont(NULL, fw_work->context); return ret; diff --git a/drivers/base/init.c b/drivers/base/init.c index fd53f364b1ed..7b86c409c648 100644 --- a/drivers/base/init.c +++ b/drivers/base/init.c @@ -2,7 +2,7 @@ * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs - * + * * This file is released under the GPLv2 * */ @@ -33,7 +33,7 @@ void __init driver_init(void) classes_init(); firmware_init(); - /* These are also core pieces, but must come after the + /* These are also core pieces, but must come after the * core core pieces. */ platform_bus_init(); diff --git a/drivers/base/interface.c b/drivers/base/interface.c index 1e2d4c328ed5..bd515843a0cb 100644 --- a/drivers/base/interface.c +++ b/drivers/base/interface.c @@ -1,10 +1,10 @@ /* - * drivers/base/interface.c - common driverfs interface that's exported to + * drivers/base/interface.c - common driverfs interface that's exported to * the world for all devices. * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs - * + * * This file is released under the GPLv2 * */ @@ -16,33 +16,33 @@ /** * detach_state - control the default power state for the device. - * - * This is the state the device enters when it's driver module is + * + * This is the state the device enters when it's driver module is * unloaded. The value is an unsigned integer, in the range of 0-4. * '0' indicates 'On', so no action will be taken when the driver is * unloaded. This is the default behavior. * '4' indicates 'Off', meaning the driver core will call the driver's * shutdown method to quiesce the device. - * 1-3 indicate a low-power state for the device to enter via the - * driver's suspend method. + * 1-3 indicate a low-power state for the device to enter via the + * driver's suspend method. */ static ssize_t detach_show(struct device * dev, char * buf) { - return sprintf(buf,"%u\n",dev->detach_state); + return sprintf(buf, "%u\n", dev->detach_state); } static ssize_t detach_store(struct device * dev, const char * buf, size_t n) { u32 state; - state = simple_strtoul(buf,NULL,10); + state = simple_strtoul(buf, NULL, 10); if (state > 4) return -EINVAL; dev->detach_state = state; return n; } -static DEVICE_ATTR(detach_state,0644,detach_show,detach_store); +static DEVICE_ATTR(detach_state, 0644, detach_show, detach_store); struct attribute * dev_default_attrs[] = { diff --git a/drivers/base/node.c b/drivers/base/node.c index b5aa9dc6cdb7..fa06de092972 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -29,7 +29,7 @@ static ssize_t node_read_cpumap(struct sys_device * dev, char * buf) return len; } -static SYSDEV_ATTR(cpumap,S_IRUGO,node_read_cpumap,NULL); +static SYSDEV_ATTR(cpumap, S_IRUGO, node_read_cpumap, NULL); /* Can be overwritten by architecture specific code. */ int __attribute__((weak)) hugetlb_report_node_meminfo(int node, char *buf) @@ -54,17 +54,17 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf) "Node %d LowFree: %8lu kB\n", nid, K(i.totalram), nid, K(i.freeram), - nid, K(i.totalram-i.freeram), + nid, K(i.totalram - i.freeram), nid, K(i.totalhigh), nid, K(i.freehigh), - nid, K(i.totalram-i.totalhigh), - nid, K(i.freeram-i.freehigh)); + nid, K(i.totalram - i.totalhigh), + nid, K(i.freeram - i.freehigh)); n += hugetlb_report_node_meminfo(nid, buf + n); return n; } -#undef K -static SYSDEV_ATTR(meminfo,S_IRUGO,node_read_meminfo,NULL); +#undef K +static SYSDEV_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL); static ssize_t node_read_numastat(struct sys_device * dev, char * buf) { @@ -104,7 +104,7 @@ static ssize_t node_read_numastat(struct sys_device * dev, char * buf) local_node, other_node); } -static SYSDEV_ATTR(numastat,S_IRUGO,node_read_numastat,NULL); +static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL); /* * register_node - Setup a driverfs device for a node. diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 4f7c5e85af24..aca1717eddd2 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -3,7 +3,7 @@ * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs - * + * * This file is released under the GPLv2 * * Please see Documentation/driver-model/platform.txt for more @@ -116,14 +116,14 @@ int platform_device_register(struct platform_device * pdev) pdev->dev.parent = &platform_bus; pdev->dev.bus = &platform_bus_type; - + if (pdev->id != -1) snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s%u", pdev->name, pdev->id); else strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE); pr_debug("Registering platform device '%s'. Parent at %s\n", - pdev->dev.bus_id,pdev->dev.parent->bus_id); + pdev->dev.bus_id, pdev->dev.parent->bus_id); return device_register(&pdev->dev); } @@ -139,13 +139,13 @@ void platform_device_unregister(struct platform_device * pdev) * @dev: device. * @drv: driver. * - * Platform device IDs are assumed to be encoded like this: - * "", where is a short description of the - * type of device, like "pci" or "floppy", and is the + * Platform device IDs are assumed to be encoded like this: + * "", where is a short description of the + * type of device, like "pci" or "floppy", and is the * enumerated instance of the device, like '0' or '42'. - * Driver IDs are simply "". - * So, extract the from the platform_device structure, - * and compare it against the name of the driver. Return whether + * Driver IDs are simply "". + * So, extract the from the platform_device structure, + * and compare it against the name of the driver. Return whether * they match or not. */ diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 634c98f5c437..635ea200132e 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -12,10 +12,10 @@ * and add it to the list of power-controlled devices. sysfs entries for * controlling device power management will also be added. * - * A different set of lists than the global subsystem list are used to - * keep track of power info because we use different lists to hold - * devices based on what stage of the power management process they - * are in. The power domain dependencies may also differ from the + * A different set of lists than the global subsystem list are used to + * keep track of power info because we use different lists to hold + * devices based on what stage of the power management process they + * are in. The power domain dependencies may also differ from the * ancestral dependencies that the subsystem list maintains. */ @@ -74,10 +74,10 @@ int device_pm_add(struct device * dev) pr_debug("PM: Adding info for %s:%s\n", dev->bus ? dev->bus->name : "No Bus", dev->kobj.name); - atomic_set(&dev->power.pm_users,0); + atomic_set(&dev->power.pm_users, 0); down(&dpm_sem); - list_add_tail(&dev->power.entry,&dpm_active); - device_pm_set_parent(dev,dev->parent); + list_add_tail(&dev->power.entry, &dpm_active); + device_pm_set_parent(dev, dev->parent); if ((error = dpm_sysfs_add(dev))) list_del(&dev->power.entry); up(&dpm_sem); diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index b930ccef5785..6971cc667b17 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -27,7 +27,7 @@ extern void device_shutdown(void); */ extern struct semaphore dpm_sem; -/* +/* * The PM lists. */ extern struct list_head dpm_active; @@ -37,12 +37,12 @@ extern struct list_head dpm_off_irq; static inline struct dev_pm_info * to_pm_info(struct list_head * entry) { - return container_of(entry,struct dev_pm_info,entry); + return container_of(entry, struct dev_pm_info, entry); } static inline struct device * to_device(struct list_head * entry) { - return container_of(to_pm_info(entry),struct device,power); + return container_of(to_pm_info(entry), struct device, power); } extern int device_pm_add(struct device *); @@ -56,7 +56,7 @@ extern int dpm_sysfs_add(struct device *); extern void dpm_sysfs_remove(struct device *); /* - * resume.c + * resume.c */ extern void dpm_resume(void); diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c index 21d4b56debe0..1d830be4c9bc 100644 --- a/drivers/base/power/resume.c +++ b/drivers/base/power/resume.c @@ -39,7 +39,7 @@ void dpm_resume(void) if (!dev->power.prev_state) resume_device(dev); - list_add_tail(entry,&dpm_active); + list_add_tail(entry, &dpm_active); } } @@ -48,7 +48,7 @@ void dpm_resume(void) * device_resume - Restore state of each device in system. * * Walk the dpm_off list, remove each entry, resume the device, - * then add it to the dpm_active list. + * then add it to the dpm_active list. */ void device_resume(void) @@ -62,14 +62,14 @@ EXPORT_SYMBOL(device_resume); /** - * device_power_up_irq - Power on some devices. + * device_power_up_irq - Power on some devices. * - * Walk the dpm_off_irq list and power each device up. This + * Walk the dpm_off_irq list and power each device up. This * is used for devices that required they be powered down with * interrupts disabled. As devices are powered on, they are moved to * the dpm_suspended list. * - * Interrupts must be disabled when calling this. + * Interrupts must be disabled when calling this. */ void dpm_power_up(void) @@ -78,7 +78,7 @@ void dpm_power_up(void) struct list_head * entry = dpm_off_irq.next; list_del_init(entry); resume_device(to_device(entry)); - list_add_tail(entry,&dpm_active); + list_add_tail(entry, &dpm_active); } } diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 4ff5340e90fb..5e58f68363af 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -24,9 +24,9 @@ static void runtime_resume(struct device * dev) * dpm_runtime_resume - Power one device back on. * @dev: Device. * - * Bring one device back to the on state by first powering it + * Bring one device back to the on state by first powering it * on, then restoring state. We only operate on devices that aren't - * already on. + * already on. * FIXME: We need to handle devices that are in an unknown state. */ @@ -55,7 +55,7 @@ int dpm_runtime_suspend(struct device * dev, u32 state) if (dev->power.power_state) runtime_resume(dev); - if (!(error = suspend_device(dev,state))) + if (!(error = suspend_device(dev, state))) dev->power.power_state = state; Done: up(&dpm_sem); @@ -70,7 +70,7 @@ int dpm_runtime_suspend(struct device * dev, u32 state) * * This is an update mechanism for drivers to notify the core * what power state a device is in. Device probing code may not - * always be able to tell, but we need accurate information to + * always be able to tell, but we need accurate information to * work reliably. */ void dpm_set_power_state(struct device * dev, u32 state) diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c index 6725ffacb518..d1e023fbe169 100644 --- a/drivers/base/power/shutdown.c +++ b/drivers/base/power/shutdown.c @@ -1,9 +1,9 @@ /* * shutdown.c - power management functions for the device tree. - * + * * Copyright (c) 2002-3 Patrick Mochel * 2002-3 Open Source Development Lab - * + * * This file is released under the GPLv2 * */ @@ -14,7 +14,7 @@ #include "power.h" -#define to_dev(node) container_of(node,struct device,kobj.entry) +#define to_dev(node) container_of(node, struct device, kobj.entry) extern struct subsystem devices_subsys; @@ -29,7 +29,7 @@ int device_detach_shutdown(struct device * dev) dev->driver->shutdown(dev); return 0; } - return dpm_runtime_suspend(dev,dev->detach_state); + return dpm_runtime_suspend(dev, dev->detach_state); } @@ -38,8 +38,8 @@ int device_detach_shutdown(struct device * dev) * down last and resume them first. That way, we don't do anything stupid like * shutting down the interrupt controller before any devices.. * - * Note that there are not different stages for power management calls - - * they only get one called once when interrupts are disabled. + * Note that there are not different stages for power management calls - + * they only get one called once when interrupts are disabled. */ extern int sysdev_shutdown(void); @@ -50,10 +50,10 @@ extern int sysdev_shutdown(void); void device_shutdown(void) { struct device * dev; - + down_write(&devices_subsys.rwsem); - list_for_each_entry_reverse(dev,&devices_subsys.kset.list,kobj.entry) { - pr_debug("shutting down %s: ",dev->bus_id); + list_for_each_entry_reverse(dev, &devices_subsys.kset.list, kobj.entry) { + pr_debug("shutting down %s: ", dev->bus_id); if (dev->driver && dev->driver->shutdown) { pr_debug("Ok\n"); dev->driver->shutdown(dev); diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index a2bc41cc9a38..86f9e6ec05a8 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c @@ -1,5 +1,5 @@ /* - * suspend.c - Functions for putting devices to sleep. + * suspend.c - Functions for putting devices to sleep. * * Copyright (c) 2003 Patrick Mochel * Copyright (c) 2003 Open Source Development Labs @@ -10,18 +10,18 @@ #include #include "power.h" - + extern int sysdev_suspend(u32 state); /* * The entries in the dpm_active list are in a depth first order, simply - * because children are guaranteed to be discovered after parents, and - * are inserted at the back of the list on discovery. - * + * because children are guaranteed to be discovered after parents, and + * are inserted at the back of the list on discovery. + * * All list on the suspend path are done in reverse order, so we operate * on the leaves of the device tree (or forests, depending on how you want - * to look at it ;) first. As nodes are removed from the back of the list, - * they are inserted into the front of their destintation lists. + * to look at it ;) first. As nodes are removed from the back of the list, + * they are inserted into the front of their destintation lists. * * Things are the reverse on the resume path - iterations are done in * forward order, and nodes are inserted at the back of their destination @@ -44,7 +44,7 @@ int suspend_device(struct device * dev, u32 state) dev->power.prev_state = dev->power.power_state; if (dev->bus && dev->bus->suspend && !dev->power.power_state) - error = dev->bus->suspend(dev,state); + error = dev->bus->suspend(dev, state); return error; } @@ -52,16 +52,16 @@ int suspend_device(struct device * dev, u32 state) /** * device_suspend - Save state and stop all devices in system. - * @state: Power state to put each device in. + * @state: Power state to put each device in. * * Walk the dpm_active list, call ->suspend() for each device, and move - * it to dpm_off. + * it to dpm_off. * Check the return value for each. If it returns 0, then we move the - * the device to the dpm_off list. If it returns -EAGAIN, we move it to - * the dpm_off_irq list. If we get a different error, try and back out. + * the device to the dpm_off list. If it returns -EAGAIN, we move it to + * the dpm_off_irq list. If we get a different error, try and back out. * * If we hit a failure with any of the devices, call device_resume() - * above to bring the suspended devices back to life. + * above to bring the suspended devices back to life. * * Note this function leaves dpm_sem held to * a) block other devices from registering. @@ -78,14 +78,14 @@ int device_suspend(u32 state) while(!list_empty(&dpm_active)) { struct list_head * entry = dpm_active.prev; struct device * dev = to_device(entry); - error = suspend_device(dev,state); + error = suspend_device(dev, state); if (!error) { list_del(&dev->power.entry); - list_add(&dev->power.entry,&dpm_off); + list_add(&dev->power.entry, &dpm_off); } else if (error == -EAGAIN) { list_del(&dev->power.entry); - list_add(&dev->power.entry,&dpm_off_irq); + list_add(&dev->power.entry, &dpm_off_irq); } else { printk(KERN_ERR "Could not suspend device %s: " "error %d\n", kobject_name(&dev->kobj), error); @@ -108,8 +108,8 @@ EXPORT_SYMBOL(device_suspend); * @state: Power state to enter. * * Walk the dpm_off_irq list, calling ->power_down() for each device that - * couldn't power down the device with interrupts enabled. When we're - * done, power down system devices. + * couldn't power down the device with interrupts enabled. When we're + * done, power down system devices. */ int device_power_down(u32 state) @@ -117,10 +117,10 @@ int device_power_down(u32 state) int error = 0; struct device * dev; - list_for_each_entry_reverse(dev,&dpm_off_irq,power.entry) { - if ((error = suspend_device(dev,state))) + list_for_each_entry_reverse(dev, &dpm_off_irq, power.entry) { + if ((error = suspend_device(dev, state))) break; - } + } if (error) goto Error; if ((error = sysdev_suspend(state))) diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 683dd59b0bff..6ac96349a8e8 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -11,10 +11,10 @@ * * show() returns the current power state of the device. '0' indicates * the device is on. Other values (1-3) indicate the device is in a low - * power state. + * power state. * - * store() sets the current power state, which is an integer value - * between 0-3. If the device is on ('0'), and the value written is + * store() sets the current power state, which is an integer value + * between 0-3. If the device is on ('0'), and the value written is * greater than 0, then the device is placed directly into the low-power * state (via its driver's ->suspend() method). * If the device is currently in a low-power state, and the value is 0, @@ -26,7 +26,7 @@ static ssize_t state_show(struct device * dev, char * buf) { - return sprintf(buf,"%u\n",dev->power.power_state); + return sprintf(buf, "%u\n", dev->power.power_state); } static ssize_t state_store(struct device * dev, const char * buf, size_t n) @@ -35,17 +35,17 @@ static ssize_t state_store(struct device * dev, const char * buf, size_t n) char * rest; int error = 0; - state = simple_strtoul(buf,&rest,10); + state = simple_strtoul(buf, &rest, 10); if (*rest) return -EINVAL; if (state) - error = dpm_runtime_suspend(dev,state); + error = dpm_runtime_suspend(dev, state); else dpm_runtime_resume(dev); return error ? error : n; } -static DEVICE_ATTR(state,0644,state_show,state_store); +static DEVICE_ATTR(state, 0644, state_show, state_store); static struct attribute * power_attrs[] = { @@ -59,10 +59,10 @@ static struct attribute_group pm_attr_group = { int dpm_sysfs_add(struct device * dev) { - return sysfs_create_group(&dev->kobj,&pm_attr_group); + return sysfs_create_group(&dev->kobj, &pm_attr_group); } void dpm_sysfs_remove(struct device * dev) { - sysfs_remove_group(&dev->kobj,&pm_attr_group); + sysfs_remove_group(&dev->kobj, &pm_attr_group); } diff --git a/drivers/base/sys.c b/drivers/base/sys.c index b0d55a930855..9d10500cd961 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -5,8 +5,8 @@ * 2002-3 Open Source Development Lab * * This file is released under the GPLv2 - * - * This exports a 'system' bus type. + * + * This exports a 'system' bus type. * By default, a 'sys' bus gets added to the root of the system. There will * always be core system devices. Devices can use sysdev_register() to * add themselves as children of the system bus. @@ -24,31 +24,31 @@ extern struct subsystem devices_subsys; -#define to_sysdev(k) container_of(k,struct sys_device,kobj) -#define to_sysdev_attr(a) container_of(a,struct sysdev_attribute,attr) +#define to_sysdev(k) container_of(k, struct sys_device, kobj) +#define to_sysdev_attr(a) container_of(a, struct sysdev_attribute, attr) -static ssize_t +static ssize_t sysdev_show(struct kobject * kobj, struct attribute * attr, char * buffer) { struct sys_device * sysdev = to_sysdev(kobj); struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr); if (sysdev_attr->show) - return sysdev_attr->show(sysdev,buffer); + return sysdev_attr->show(sysdev, buffer); return 0; } static ssize_t -sysdev_store(struct kobject * kobj, struct attribute * attr, +sysdev_store(struct kobject * kobj, struct attribute * attr, const char * buffer, size_t count) { struct sys_device * sysdev = to_sysdev(kobj); struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr); if (sysdev_attr->store) - return sysdev_attr->store(sysdev,buffer,count); + return sysdev_attr->store(sysdev, buffer, count); return 0; } @@ -64,22 +64,22 @@ static struct kobj_type ktype_sysdev = { int sysdev_create_file(struct sys_device * s, struct sysdev_attribute * a) { - return sysfs_create_file(&s->kobj,&a->attr); + return sysfs_create_file(&s->kobj, &a->attr); } void sysdev_remove_file(struct sys_device * s, struct sysdev_attribute * a) { - sysfs_remove_file(&s->kobj,&a->attr); + sysfs_remove_file(&s->kobj, &a->attr); } EXPORT_SYMBOL(sysdev_create_file); EXPORT_SYMBOL(sysdev_remove_file); -/* - * declare system_subsys +/* + * declare system_subsys */ -decl_subsys(system,&ktype_sysdev,NULL); +decl_subsys(system, &ktype_sysdev, NULL); int sysdev_class_register(struct sysdev_class * cls) { @@ -87,7 +87,7 @@ int sysdev_class_register(struct sysdev_class * cls) kobject_name(&cls->kset.kobj)); INIT_LIST_HEAD(&cls->drivers); cls->kset.subsys = &system_subsys; - kset_set_kset_s(cls,system_subsys); + kset_set_kset_s(cls, system_subsys); return kset_register(&cls->kset); } @@ -109,19 +109,19 @@ static LIST_HEAD(global_drivers); * @cls: Device class driver belongs to. * @drv: Driver. * - * If @cls is valid, then @drv is inserted into @cls->drivers to be + * If @cls is valid, then @drv is inserted into @cls->drivers to be * called on each operation on devices of that class. The refcount - * of @cls is incremented. - * Otherwise, @drv is inserted into global_drivers, and called for + * of @cls is incremented. + * Otherwise, @drv is inserted into global_drivers, and called for * each device. */ -int sysdev_driver_register(struct sysdev_class * cls, +int sysdev_driver_register(struct sysdev_class * cls, struct sysdev_driver * drv) { down_write(&system_subsys.rwsem); if (cls && kset_get(&cls->kset)) { - list_add_tail(&drv->entry,&cls->drivers); + list_add_tail(&drv->entry, &cls->drivers); /* If devices of this class already exist, tell the driver */ if (drv->add) { @@ -130,7 +130,7 @@ int sysdev_driver_register(struct sysdev_class * cls, drv->add(dev); } } else - list_add_tail(&drv->entry,&global_drivers); + list_add_tail(&drv->entry, &global_drivers); up_write(&system_subsys.rwsem); return 0; } @@ -180,12 +180,12 @@ int sysdev_register(struct sys_device * sysdev) /* But make sure we point to the right type for sysfs translation */ sysdev->kobj.ktype = &ktype_sysdev; - error = kobject_set_name(&sysdev->kobj,"%s%d", - kobject_name(&cls->kset.kobj),sysdev->id); + error = kobject_set_name(&sysdev->kobj, "%s%d", + kobject_name(&cls->kset.kobj), sysdev->id); if (error) return error; - pr_debug("Registering sys device '%s'\n",kobject_name(&sysdev->kobj)); + pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj)); /* Register the object */ error = kobject_register(&sysdev->kobj); @@ -194,18 +194,18 @@ int sysdev_register(struct sys_device * sysdev) struct sysdev_driver * drv; down_write(&system_subsys.rwsem); - /* Generic notification is implicit, because it's that - * code that should have called us. + /* Generic notification is implicit, because it's that + * code that should have called us. */ /* Notify global drivers */ - list_for_each_entry(drv,&global_drivers,entry) { + list_for_each_entry(drv, &global_drivers, entry) { if (drv->add) drv->add(sysdev); } /* Notify class auxillary drivers */ - list_for_each_entry(drv,&cls->drivers,entry) { + list_for_each_entry(drv, &cls->drivers, entry) { if (drv->add) drv->add(sysdev); } @@ -219,12 +219,12 @@ void sysdev_unregister(struct sys_device * sysdev) struct sysdev_driver * drv; down_write(&system_subsys.rwsem); - list_for_each_entry(drv,&global_drivers,entry) { + list_for_each_entry(drv, &global_drivers, entry) { if (drv->remove) drv->remove(sysdev); } - list_for_each_entry(drv,&sysdev->cls->drivers,entry) { + list_for_each_entry(drv, &sysdev->cls->drivers, entry) { if (drv->remove) drv->remove(sysdev); } @@ -241,12 +241,12 @@ void sysdev_unregister(struct sys_device * sysdev) * Loop over each class of system devices, and the devices in each * of those classes. For each device, we call the shutdown method for * each driver registered for the device - the globals, the auxillaries, - * and the class driver. + * and the class driver. * * Note: The list is iterated in reverse order, so that we shut down * child devices before we shut down thier parents. The list ordering * is guaranteed by virtue of the fact that child devices are registered - * after their parents. + * after their parents. */ void sysdev_shutdown(void) @@ -256,25 +256,25 @@ void sysdev_shutdown(void) pr_debug("Shutting Down System Devices\n"); down_write(&system_subsys.rwsem); - list_for_each_entry_reverse(cls,&system_subsys.kset.list, + list_for_each_entry_reverse(cls, &system_subsys.kset.list, kset.kobj.entry) { struct sys_device * sysdev; pr_debug("Shutting down type '%s':\n", kobject_name(&cls->kset.kobj)); - list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) { + list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { struct sysdev_driver * drv; - pr_debug(" %s\n",kobject_name(&sysdev->kobj)); + pr_debug(" %s\n", kobject_name(&sysdev->kobj)); /* Call global drivers first. */ - list_for_each_entry(drv,&global_drivers,entry) { + list_for_each_entry(drv, &global_drivers, entry) { if (drv->shutdown) drv->shutdown(sysdev); } /* Call auxillary drivers next. */ - list_for_each_entry(drv,&cls->drivers,entry) { + list_for_each_entry(drv, &cls->drivers, entry) { if (drv->shutdown) drv->shutdown(sysdev); } @@ -295,7 +295,7 @@ void sysdev_shutdown(void) * We perform an almost identical operation as sys_device_shutdown() * above, though calling ->suspend() instead. Interrupts are disabled * when this called. Devices are responsible for both saving state and - * quiescing or powering down the device. + * quiescing or powering down the device. * * This is only called by the device PM core, so we let them handle * all synchronization. @@ -307,32 +307,32 @@ int sysdev_suspend(u32 state) pr_debug("Suspending System Devices\n"); - list_for_each_entry_reverse(cls,&system_subsys.kset.list, + list_for_each_entry_reverse(cls, &system_subsys.kset.list, kset.kobj.entry) { struct sys_device * sysdev; pr_debug("Suspending type '%s':\n", kobject_name(&cls->kset.kobj)); - list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) { + list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { struct sysdev_driver * drv; - pr_debug(" %s\n",kobject_name(&sysdev->kobj)); + pr_debug(" %s\n", kobject_name(&sysdev->kobj)); /* Call global drivers first. */ - list_for_each_entry(drv,&global_drivers,entry) { + list_for_each_entry(drv, &global_drivers, entry) { if (drv->suspend) - drv->suspend(sysdev,state); + drv->suspend(sysdev, state); } /* Call auxillary drivers next. */ - list_for_each_entry(drv,&cls->drivers,entry) { + list_for_each_entry(drv, &cls->drivers, entry) { if (drv->suspend) - drv->suspend(sysdev,state); + drv->suspend(sysdev, state); } /* Now call the generic one */ if (cls->suspend) - cls->suspend(sysdev,state); + cls->suspend(sysdev, state); } } return 0; @@ -345,7 +345,7 @@ int sysdev_suspend(u32 state) * Similar to sys_device_suspend(), but we iterate the list forwards * to guarantee that parent devices are resumed before their children. * - * Note: Interrupts are disabled when called. + * Note: Interrupts are disabled when called. */ int sysdev_resume(void) @@ -354,28 +354,28 @@ int sysdev_resume(void) pr_debug("Resuming System Devices\n"); - list_for_each_entry(cls,&system_subsys.kset.list,kset.kobj.entry) { + list_for_each_entry(cls, &system_subsys.kset.list, kset.kobj.entry) { struct sys_device * sysdev; pr_debug("Resuming type '%s':\n", kobject_name(&cls->kset.kobj)); - list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) { + list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { struct sysdev_driver * drv; - pr_debug(" %s\n",kobject_name(&sysdev->kobj)); + pr_debug(" %s\n", kobject_name(&sysdev->kobj)); /* First, call the class-specific one */ if (cls->resume) cls->resume(sysdev); /* Call auxillary drivers next. */ - list_for_each_entry(drv,&cls->drivers,entry) { + list_for_each_entry(drv, &cls->drivers, entry) { if (drv->resume) drv->resume(sysdev); } /* Call global drivers. */ - list_for_each_entry(drv,&global_drivers,entry) { + list_for_each_entry(drv, &global_drivers, entry) { if (drv->resume) drv->resume(sysdev); } -- cgit v1.2.3 From 3499c9eb3864996b7345aba4a08f2eaf576349a8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 9 Jun 2004 19:36:26 -0700 Subject: Driver Core: more whitespace fixups This catches the files I had to do by hand as Dmitry's patch differed from my tree. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 129 +++++++++++++++++++++++++-------------------------- drivers/base/class.c | 36 +++++++------- 2 files changed, 82 insertions(+), 83 deletions(-) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 0e5f5ea78e58..02ff97df6dee 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -3,7 +3,7 @@ * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs - * + * * This file is released under the GPLv2 * */ @@ -17,17 +17,17 @@ #include "base.h" #include "power/power.h" -#define to_dev(node) container_of(node,struct device,bus_list) -#define to_drv(node) container_of(node,struct device_driver,kobj.entry) +#define to_dev(node) container_of(node, struct device, bus_list) +#define to_drv(node) container_of(node, struct device_driver, kobj.entry) -#define to_bus_attr(_attr) container_of(_attr,struct bus_attribute,attr) -#define to_bus(obj) container_of(obj,struct bus_type,subsys.kset.kobj) +#define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr) +#define to_bus(obj) container_of(obj, struct bus_type, subsys.kset.kobj) /* * sysfs bindings for drivers */ -#define to_drv_attr(_attr) container_of(_attr,struct driver_attribute,attr) +#define to_drv_attr(_attr) container_of(_attr, struct driver_attribute, attr) #define to_driver(obj) container_of(obj, struct device_driver, kobj) @@ -39,12 +39,12 @@ drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) ssize_t ret = 0; if (drv_attr->show) - ret = drv_attr->show(drv,buf); + ret = drv_attr->show(drv, buf); return ret; } static ssize_t -drv_attr_store(struct kobject * kobj, struct attribute * attr, +drv_attr_store(struct kobject * kobj, struct attribute * attr, const char * buf, size_t count) { struct driver_attribute * drv_attr = to_drv_attr(attr); @@ -52,7 +52,7 @@ drv_attr_store(struct kobject * kobj, struct attribute * attr, ssize_t ret = 0; if (drv_attr->store) - ret = drv_attr->store(drv,buf,count); + ret = drv_attr->store(drv, buf, count); return ret; } @@ -87,12 +87,12 @@ bus_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) ssize_t ret = 0; if (bus_attr->show) - ret = bus_attr->show(bus,buf); + ret = bus_attr->show(bus, buf); return ret; } static ssize_t -bus_attr_store(struct kobject * kobj, struct attribute * attr, +bus_attr_store(struct kobject * kobj, struct attribute * attr, const char * buf, size_t count) { struct bus_attribute * bus_attr = to_bus_attr(attr); @@ -100,7 +100,7 @@ bus_attr_store(struct kobject * kobj, struct attribute * attr, ssize_t ret = 0; if (bus_attr->store) - ret = bus_attr->store(bus,buf,count); + ret = bus_attr->store(bus, buf, count); return ret; } @@ -113,7 +113,7 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) { int error; if (get_bus(bus)) { - error = sysfs_create_file(&bus->subsys.kset.kobj,&attr->attr); + error = sysfs_create_file(&bus->subsys.kset.kobj, &attr->attr); put_bus(bus); } else error = -EINVAL; @@ -123,7 +123,7 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) { if (get_bus(bus)) { - sysfs_remove_file(&bus->subsys.kset.kobj,&attr->attr); + sysfs_remove_file(&bus->subsys.kset.kobj, &attr->attr); put_bus(bus); } } @@ -133,7 +133,7 @@ static struct kobj_type ktype_bus = { }; -decl_subsys(bus,&ktype_bus,NULL); +decl_subsys(bus, &ktype_bus, NULL); /** * bus_for_each_dev - device iterator. @@ -151,10 +151,10 @@ decl_subsys(bus,&ktype_bus,NULL); * * NOTE: The device that returns a non-zero value is not retained * in any way, nor is its refcount incremented. If the caller needs - * to retain this data, it should do, and increment the reference + * to retain this data, it should do, and increment the reference * count in the supplied callback. */ -int bus_for_each_dev(struct bus_type * bus, struct device * start, +int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, int (*fn)(struct device *, void *)) { struct device *dev; @@ -170,7 +170,7 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start, down_read(&bus->subsys.rwsem); list_for_each_entry_continue(dev, head, bus_list) { get_device(dev); - error = fn(dev,data); + error = fn(dev, data); put_device(dev); if (error) break; @@ -193,7 +193,7 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start, * and return it. If @start is not NULL, we use it as the head * of the list. * - * NOTE: we don't return the driver that returns a non-zero + * NOTE: we don't return the driver that returns a non-zero * value, nor do we leave the reference count incremented for that * driver. If the caller needs to know that info, it must set it * in the callback. It must also be sure to increment the refcount @@ -216,7 +216,7 @@ int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, down_read(&bus->subsys.rwsem); list_for_each_entry_continue(drv, head, kobj.entry) { get_driver(drv); - error = fn(drv,data); + error = fn(drv, data); put_driver(drv); if(error) break; @@ -233,8 +233,8 @@ int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, * Allow manual attachment of a driver to a deivce. * Caller must have already set @dev->driver. * - * Note that this does not modify the bus reference count - * nor take the bus's rwsem. Please verify those are accounted + * Note that this does not modify the bus reference count + * nor take the bus's rwsem. Please verify those are accounted * for before calling this. (It is ok to call with no other effort * from a driver's probe() method.) */ @@ -242,9 +242,9 @@ int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, void device_bind_driver(struct device * dev) { pr_debug("bound device '%s' to driver '%s'\n", - dev->bus_id,dev->driver->name); - list_add_tail(&dev->driver_list,&dev->driver->devices); - sysfs_create_link(&dev->driver->kobj,&dev->kobj, + dev->bus_id, dev->driver->name); + list_add_tail(&dev->driver_list, &dev->driver->devices); + sysfs_create_link(&dev->driver->kobj, &dev->kobj, kobject_name(&dev->kobj)); } @@ -255,18 +255,18 @@ void device_bind_driver(struct device * dev) * @drv: driver. * * First, we call the bus's match function, which should compare - * the device IDs the driver supports with the device IDs of the - * device. Note we don't do this ourselves because we don't know + * the device IDs the driver supports with the device IDs of the + * device. Note we don't do this ourselves because we don't know * the format of the ID structures, nor what is to be considered * a match and what is not. - * - * If we find a match, we call @drv->probe(@dev) if it exists, and + * + * If we find a match, we call @drv->probe(@dev) if it exists, and * call attach() above. */ static int bus_match(struct device * dev, struct device_driver * drv) { int error = -ENODEV; - if (dev->bus->match(dev,drv)) { + if (dev->bus->match(dev, drv)) { dev->driver = drv; if (drv->probe) { if ((error = drv->probe(dev))) { @@ -285,7 +285,7 @@ static int bus_match(struct device * dev, struct device_driver * drv) * device_attach - try to attach device to a driver. * @dev: device. * - * Walk the list of drivers that the bus has and call bus_match() + * Walk the list of drivers that the bus has and call bus_match() * for each pair. If a compatible pair is found, break out and return. */ static int device_attach(struct device * dev) @@ -300,15 +300,15 @@ static int device_attach(struct device * dev) } if (bus->match) { - list_for_each(entry,&bus->drivers.list) { + list_for_each(entry, &bus->drivers.list) { struct device_driver * drv = to_drv(entry); - error = bus_match(dev,drv); - if (!error ) + error = bus_match(dev, drv); + if (!error) /* success, driver matched */ - return 1; - if (error != -ENODEV) + return 1; + if (error != -ENODEV) /* driver matched but the probe failed */ - printk(KERN_WARNING + printk(KERN_WARNING "%s: probe of %s failed with error %d\n", drv->name, dev->bus_id, error); } @@ -327,7 +327,7 @@ static int device_attach(struct device * dev) * If bus_match() returns 0 and the @dev->driver is set, we've found * a compatible pair. * - * Note that we ignore the -ENODEV error from bus_match(), since it's + * Note that we ignore the -ENODEV error from bus_match(), since it's * perfectly valid for a driver not to bind to any devices. */ void driver_attach(struct device_driver * drv) @@ -339,13 +339,13 @@ void driver_attach(struct device_driver * drv) if (!bus->match) return; - list_for_each(entry,&bus->devices.list) { - struct device * dev = container_of(entry,struct device,bus_list); + list_for_each(entry, &bus->devices.list) { + struct device * dev = container_of(entry, struct device, bus_list); if (!dev->driver) { - error = bus_match(dev,drv); + error = bus_match(dev, drv); if (error && (error != -ENODEV)) /* driver matched but the probe failed */ - printk(KERN_WARNING + printk(KERN_WARNING "%s: probe of %s failed with error %d\n", drv->name, dev->bus_id, error); } @@ -367,7 +367,7 @@ void device_release_driver(struct device * dev) { struct device_driver * drv = dev->driver; if (drv) { - sysfs_remove_link(&drv->kobj,kobject_name(&dev->kobj)); + sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); list_del_init(&dev->driver_list); device_detach_shutdown(dev); if (drv->remove) @@ -385,11 +385,10 @@ void device_release_driver(struct device * dev) static void driver_detach(struct device_driver * drv) { struct list_head * entry, * next; - list_for_each_safe(entry,next,&drv->devices) { - struct device * dev = container_of(entry,struct device,driver_list); + list_for_each_safe(entry, next, &drv->devices) { + struct device * dev = container_of(entry, struct device, driver_list); device_release_driver(dev); } - } static int device_add_attrs(struct bus_type * bus, struct device * dev) @@ -439,12 +438,12 @@ int bus_add_device(struct device * dev) if (bus) { down_write(&dev->bus->subsys.rwsem); - pr_debug("bus %s: add device %s\n",bus->name,dev->bus_id); - list_add_tail(&dev->bus_list,&dev->bus->devices.list); + pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id); + list_add_tail(&dev->bus_list, &dev->bus->devices.list); device_attach(dev); up_write(&dev->bus->subsys.rwsem); - device_add_attrs(bus,dev); - sysfs_create_link(&bus->devices.kobj,&dev->kobj,dev->bus_id); + device_add_attrs(bus, dev); + sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id); } return error; } @@ -461,10 +460,10 @@ int bus_add_device(struct device * dev) void bus_remove_device(struct device * dev) { if (dev->bus) { - sysfs_remove_link(&dev->bus->devices.kobj,dev->bus_id); - device_remove_attrs(dev->bus,dev); + sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id); + device_remove_attrs(dev->bus, dev); down_write(&dev->bus->subsys.rwsem); - pr_debug("bus %s: remove device %s\n",dev->bus->name,dev->bus_id); + pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); device_release_driver(dev); list_del_init(&dev->bus_list); up_write(&dev->bus->subsys.rwsem); @@ -484,8 +483,8 @@ int bus_add_driver(struct device_driver * drv) int error = 0; if (bus) { - pr_debug("bus %s: add driver %s\n",bus->name,drv->name); - error = kobject_set_name(&drv->kobj,drv->name); + pr_debug("bus %s: add driver %s\n", bus->name, drv->name); + error = kobject_set_name(&drv->kobj, drv->name); if (error) { put_bus(bus); return error; @@ -518,7 +517,7 @@ void bus_remove_driver(struct device_driver * drv) { if (drv->bus) { down_write(&drv->bus->subsys.rwsem); - pr_debug("bus %s: remove driver %s\n",drv->bus->name,drv->name); + pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); driver_detach(drv); up_write(&drv->bus->subsys.rwsem); kobject_unregister(&drv->kobj); @@ -560,7 +559,7 @@ int bus_rescan_devices(struct bus_type * bus) struct bus_type * get_bus(struct bus_type * bus) { - return bus ? container_of(subsys_get(&bus->subsys),struct bus_type,subsys) : NULL; + return bus ? container_of(subsys_get(&bus->subsys), struct bus_type, subsys) : NULL; } void put_bus(struct bus_type * bus) @@ -579,7 +578,7 @@ void put_bus(struct bus_type * bus) struct bus_type * find_bus(char * name) { - struct kobject * k = kset_find_obj(&bus_subsys.kset,name); + struct kobject * k = kset_find_obj(&bus_subsys.kset, name); return k ? to_bus(k) : NULL; } @@ -624,19 +623,19 @@ static void bus_remove_attrs(struct bus_type * bus) * * Once we have that, we registered the bus with the kobject * infrastructure, then register the children subsystems it has: - * the devices and drivers that belong to the bus. + * the devices and drivers that belong to the bus. */ int bus_register(struct bus_type * bus) { int retval; - retval = kobject_set_name(&bus->subsys.kset.kobj,bus->name); + retval = kobject_set_name(&bus->subsys.kset.kobj, bus->name); if (retval) goto out; - subsys_set_kset(bus,bus_subsys); + subsys_set_kset(bus, bus_subsys); retval = subsystem_register(&bus->subsys); - if (retval) + if (retval) goto out; kobject_set_name(&bus->devices.kobj, "devices"); @@ -653,7 +652,7 @@ int bus_register(struct bus_type * bus) goto bus_drivers_fail; bus_add_attrs(bus); - pr_debug("bus type '%s' registered\n",bus->name); + pr_debug("bus type '%s' registered\n", bus->name); return 0; bus_drivers_fail: @@ -666,7 +665,7 @@ out: /** - * bus_unregister - remove a bus from the system + * bus_unregister - remove a bus from the system * @bus: bus. * * Unregister the child subsystems and the bus itself. @@ -674,7 +673,7 @@ out: */ void bus_unregister(struct bus_type * bus) { - pr_debug("bus %s: unregistering\n",bus->name); + pr_debug("bus %s: unregistering\n", bus->name); bus_remove_attrs(bus); kset_unregister(&bus->drivers); kset_unregister(&bus->devices); diff --git a/drivers/base/class.c b/drivers/base/class.c index b9973e92f9fa..2693bb5455f4 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -5,7 +5,7 @@ * Copyright (c) 2002-3 Open Source Development Labs * Copyright (c) 2003-2004 Greg Kroah-Hartman * Copyright (c) 2003-2004 IBM Corp. - * + * * This file is released under the GPLv2 * */ @@ -17,8 +17,8 @@ #include #include "base.h" -#define to_class_attr(_attr) container_of(_attr,struct class_attribute,attr) -#define to_class(obj) container_of(obj,struct class,subsys.kset.kobj) +#define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) +#define to_class(obj) container_of(obj, struct class, subsys.kset.kobj) static ssize_t class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) @@ -28,12 +28,12 @@ class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) ssize_t ret = 0; if (class_attr->show) - ret = class_attr->show(dc,buf); + ret = class_attr->show(dc, buf); return ret; } static ssize_t -class_attr_store(struct kobject * kobj, struct attribute * attr, +class_attr_store(struct kobject * kobj, struct attribute * attr, const char * buf, size_t count) { struct class_attribute * class_attr = to_class_attr(attr); @@ -41,7 +41,7 @@ class_attr_store(struct kobject * kobj, struct attribute * attr, ssize_t ret = 0; if (class_attr->store) - ret = class_attr->store(dc,buf,count); + ret = class_attr->store(dc, buf, count); return ret; } @@ -69,14 +69,14 @@ static struct kobj_type ktype_class = { }; /* Hotplug events for classes go to the class_obj subsys */ -static decl_subsys(class,&ktype_class,NULL); +static decl_subsys(class, &ktype_class, NULL); int class_create_file(struct class * cls, const struct class_attribute * attr) { int error; if (cls) { - error = sysfs_create_file(&cls->subsys.kset.kobj,&attr->attr); + error = sysfs_create_file(&cls->subsys.kset.kobj, &attr->attr); } else error = -EINVAL; return error; @@ -85,13 +85,13 @@ int class_create_file(struct class * cls, const struct class_attribute * attr) void class_remove_file(struct class * cls, const struct class_attribute * attr) { if (cls) - sysfs_remove_file(&cls->subsys.kset.kobj,&attr->attr); + sysfs_remove_file(&cls->subsys.kset.kobj, &attr->attr); } struct class * class_get(struct class * cls) { if (cls) - return container_of(subsys_get(&cls->subsys),struct class,subsys); + return container_of(subsys_get(&cls->subsys), struct class, subsys); return NULL; } @@ -135,15 +135,15 @@ int class_register(struct class * cls) { int error; - pr_debug("device class '%s': registering\n",cls->name); + pr_debug("device class '%s': registering\n", cls->name); INIT_LIST_HEAD(&cls->children); INIT_LIST_HEAD(&cls->interfaces); - error = kobject_set_name(&cls->subsys.kset.kobj,cls->name); + error = kobject_set_name(&cls->subsys.kset.kobj, cls->name); if (error) return error; - subsys_set_kset(cls,class_subsys); + subsys_set_kset(cls, class_subsys); error = subsystem_register(&cls->subsys); if (!error) { @@ -155,7 +155,7 @@ int class_register(struct class * cls) void class_unregister(struct class * cls) { - pr_debug("device class '%s': unregistering\n",cls->name); + pr_debug("device class '%s': unregistering\n", cls->name); remove_class_attrs(cls); subsystem_unregister(&cls->subsys); } @@ -215,12 +215,12 @@ class_device_attr_show(struct kobject * kobj, struct attribute * attr, ssize_t ret = 0; if (class_dev_attr->show) - ret = class_dev_attr->show(cd,buf); + ret = class_dev_attr->show(cd, buf); return ret; } static ssize_t -class_device_attr_store(struct kobject * kobj, struct attribute * attr, +class_device_attr_store(struct kobject * kobj, struct attribute * attr, const char * buf, size_t count) { struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr); @@ -228,7 +228,7 @@ class_device_attr_store(struct kobject * kobj, struct attribute * attr, ssize_t ret = 0; if (class_dev_attr->store) - ret = class_dev_attr->store(cd,buf,count); + ret = class_dev_attr->store(cd, buf, count); return ret; } @@ -242,7 +242,7 @@ static void class_dev_release(struct kobject * kobj) struct class_device *cd = to_class_dev(kobj); struct class * cls = cd->class; - pr_debug("device class '%s': release.\n",cd->class_id); + pr_debug("device class '%s': release.\n", cd->class_id); if (cls->release) cls->release(cd); -- cgit v1.2.3 From d30f0c9d742b849b0ef8ff89d5c151a8c07ebf02 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 9 Jun 2004 22:52:02 -0700 Subject: I2C: sparse cleanups for drivers/i2c/* Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/it87.c | 5 ++++- drivers/i2c/i2c-dev.c | 7 +++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c index 3bf10383f386..407ce3a3dfe1 100644 --- a/drivers/i2c/chips/it87.c +++ b/drivers/i2c/chips/it87.c @@ -170,8 +170,11 @@ static inline u8 FAN_TO_REG(long rpm, int div) static int DIV_TO_REG(int val) { int answer = 0; - while ((val >>= 1)) + val >>= 1; + while (val) { answer++; + val >>= 1; + } return answer; } #define DIV_FROM_REG(val) (1 << (val)) diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index a0a4aa15aa97..4e5a3671d6e3 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -181,7 +181,7 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, struct i2c_smbus_ioctl_data data_arg; union i2c_smbus_data temp; struct i2c_msg *rdwr_pa; - u8 **data_ptrs; + u8 __user **data_ptrs; int i,datasize,res; unsigned long funcs; @@ -238,8 +238,7 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, return -EFAULT; } - data_ptrs = (u8 **) kmalloc(rdwr_arg.nmsgs * sizeof(u8 *), - GFP_KERNEL); + data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); if (data_ptrs == NULL) { kfree(rdwr_pa); return -ENOMEM; @@ -252,7 +251,7 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, res = -EINVAL; break; } - data_ptrs[i] = rdwr_pa[i].buf; + data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL); if(rdwr_pa[i].buf == NULL) { res = -ENOMEM; -- cgit v1.2.3 From 5b472ff2bc947f49a8a5eaeb098d17e7d45e376c Mon Sep 17 00:00:00 2001 From: "Hanna V. Linder" Date: Fri, 11 Jun 2004 03:22:14 -0700 Subject: [PATCH] Driver Model: Add class support to msr.c This patch enables class support in arch/i386/kernel/msr.c. Very simliar to cpuid (with the fixes Zwane/Greg made, thanks). [root@w-hlinder2 root]# tree /sys/class/msr /sys/class/msr | -- msr0 | `-- dev `-- msr1 `-- dev 2 directories, 2 files Thanks to Randy Dunlap for pointing out the unnecessary tabs. Fixed. Signed-off-by Hanna Linder Signed-off-by: Greg Kroah-Hartman --- arch/i386/kernel/msr.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c index 1a1093e4a4c2..670a71efafb3 100644 --- a/arch/i386/kernel/msr.c +++ b/arch/i386/kernel/msr.c @@ -35,12 +35,17 @@ #include #include #include +#include +#include +#include #include #include #include #include +static struct class_simple *msr_class; + /* Note: "err" is handled in a funny way below. Otherwise one version of gcc or another breaks. */ @@ -255,20 +260,82 @@ static struct file_operations msr_fops = { .open = msr_open, }; +static int msr_class_simple_device_add(int i) +{ + int err = 0; + struct class_device *class_err; + + class_err = class_simple_device_add(msr_class, MKDEV(MSR_MAJOR, i), NULL, "msr%d",i); + if (IS_ERR(class_err)) + err = PTR_ERR(class_err); + return err; +} + +static int __devinit msr_class_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + + switch (action) { + case CPU_ONLINE: + msr_class_simple_device_add(cpu); + break; + case CPU_DEAD: + class_simple_device_remove(MKDEV(MSR_MAJOR, cpu)); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block msr_class_cpu_notifier = +{ + .notifier_call = msr_class_cpu_callback, +}; + int __init msr_init(void) { + int i, err = 0; + i = 0; + if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) { printk(KERN_ERR "msr: unable to get major %d for msr\n", MSR_MAJOR); - return -EBUSY; + err = -EBUSY; + goto out; + } + msr_class = class_simple_create(THIS_MODULE, "msr"); + if (IS_ERR(msr_class)) { + err = PTR_ERR(msr_class); + goto out_chrdev; } + for_each_online_cpu(i) { + err = msr_class_simple_device_add(i); + if (err != 0) + goto out_class; + } + register_cpu_notifier(&msr_class_cpu_notifier); - return 0; + err = 0; + goto out; + +out_class: + i = 0; + for_each_online_cpu(i) + class_simple_device_remove(MKDEV(MSR_MAJOR, i)); + class_simple_destroy(msr_class); +out_chrdev: + unregister_chrdev(MSR_MAJOR, "cpu/msr"); +out: + return err; } void __exit msr_exit(void) { + int cpu = 0; + for_each_online_cpu(cpu) + class_simple_device_remove(MKDEV(MSR_MAJOR, cpu)); + class_simple_destroy(msr_class); unregister_chrdev(MSR_MAJOR, "cpu/msr"); + unregister_cpu_notifier(&msr_class_cpu_notifier); } module_init(msr_init); -- cgit v1.2.3 From 2b118bd48598f5ea65f9ffab73040636db32860d Mon Sep 17 00:00:00 2001 From: Sebastian Henschel Date: Fri, 11 Jun 2004 03:22:53 -0700 Subject: [PATCH] sysfs: fs/sysfs/inode.c: modify parents ctime and mtime on creation When a node is added to sysfs (e.g. a device plugged in via USB), the filesystem fails to make this change visible in the parent directory's ctime/mtime. This is in contrast to removing a device, because in that case, sysfs makes use of the function simple_unlink from fs/libfs.c which takes care of that. Instead of using simple_link from fs/libfs.c on creation, sysfs implements its own mechanism. This patch hooks into the function sysfs_create and sets the ctime and the mtime of the parent to CURRENT_TIME. Signed-off-by: Sebastian Henschel Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/inode.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index ac5c0b962ba9..d0030a4b151a 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -46,8 +46,13 @@ int sysfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *)) struct inode * inode = NULL; if (dentry) { if (!dentry->d_inode) { - if ((inode = sysfs_new_inode(mode))) + if ((inode = sysfs_new_inode(mode))) { + if (dentry->d_parent && dentry->d_parent->d_inode) { + struct inode *p_inode = dentry->d_parent->d_inode; + p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; + } goto Proceed; + } else error = -ENOMEM; } else -- cgit v1.2.3 From dece0b32aa49686a38560c87aa4de1f53ee528d8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 13 Jun 2004 19:45:55 -0700 Subject: I2C: sparse cleanups again, based on comments from lkml This is more like the original code. Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/it87.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c index 407ce3a3dfe1..ef656298779a 100644 --- a/drivers/i2c/chips/it87.c +++ b/drivers/i2c/chips/it87.c @@ -170,11 +170,8 @@ static inline u8 FAN_TO_REG(long rpm, int div) static int DIV_TO_REG(int val) { int answer = 0; - val >>= 1; - while (val) { + while ((val >>= 1) != 0) answer++; - val >>= 1; - } return answer; } #define DIV_FROM_REG(val) (1 << (val)) -- cgit v1.2.3 From ade1271a0c9ec0d29169eced83ec6d67adb98fb4 Mon Sep 17 00:00:00 2001 From: "Mark M. Hoffman" Date: Sun, 13 Jun 2004 20:50:59 -0700 Subject: [PATCH] I2C: add alternate VCORE calculations for w83627thf and w83637hf Pick a VRM (for VID interpretation) based on the VRM & OVT config, if available. Props to Jean Delvare for the idea & code fragment. Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/w83627hf.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c index 7419f9541949..649bf80203bd 100644 --- a/drivers/i2c/chips/w83627hf.c +++ b/drivers/i2c/chips/w83627hf.c @@ -1275,12 +1275,15 @@ static void w83627hf_init_client(struct i2c_client *client) } /* Read VRM & OVT Config only once */ - if (w83627thf == data->type || w83637hf == data->type) + if (w83627thf == data->type || w83637hf == data->type) { data->vrm_ovt = w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG); + data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82; + } else { + /* Convert VID to voltage based on default VRM */ + data->vrm = DEFAULT_VRM; + } - /* Convert VID to voltage based on default VRM */ - data->vrm = DEFAULT_VRM; if (type != w83697hf) vid = vid_from_reg(vid, data->vrm); -- cgit v1.2.3 From 77ca20f2f42b526733d7aa39fe41247dc5d4ce97 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 14 Jun 2004 08:27:27 -0400 Subject: [libata] don't probe from workqueue Since we want the probe phase to call other workqueues, this is required to eliminate future deadlocks. Other methods would include starting a single-shot thread just for probing, but overall, using a separate thread for probing is pointless since we are already in process context when we probe. So, we simply call ata_bus_probe directly. --- drivers/scsi/libata-core.c | 136 ++++++--------------------------------------- include/linux/libata.h | 15 ----- 2 files changed, 18 insertions(+), 133 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f7cf90b9e170..e0a907b48caa 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -65,37 +65,6 @@ MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("Library module for ATA devices"); MODULE_LICENSE("GPL"); -static const char * thr_state_name[] = { - "THR_UNKNOWN", - "THR_PORT_RESET", - "THR_AWAIT_DEATH", - "THR_PROBE_FAILED", - "THR_IDLE", - "THR_PROBE_SUCCESS", - "THR_PROBE_START", -}; - -/** - * ata_thr_state_name - convert thread state enum to string - * @thr_state: thread state to be converted to string - * - * Converts the specified thread state id to a constant C string. - * - * LOCKING: - * None. - * - * RETURNS: - * The THR_xxx-prefixed string naming the specified thread - * state id, or the string "". - */ - -static const char *ata_thr_state_name(unsigned int thr_state) -{ - if (thr_state < ARRAY_SIZE(thr_state_name)) - return thr_state_name[thr_state]; - return ""; -} - /** * ata_tf_load_pio - send taskfile registers to host controller * @ap: Port to which output is sent @@ -1150,13 +1119,16 @@ err_out: } /** - * ata_port_reset - - * @ap: + * ata_bus_probe - Reset and probe ATA bus + * @ap: Bus to probe * * LOCKING: + * + * RETURNS: + * Zero on success, non-zero on error. */ -static void ata_port_reset(struct ata_port *ap) +static int ata_bus_probe(struct ata_port *ap) { unsigned int i, found = 0; @@ -1180,14 +1152,12 @@ static void ata_port_reset(struct ata_port *ap) if (ap->flags & ATA_FLAG_PORT_DISABLED) goto err_out_disable; - ap->thr_state = THR_PROBE_SUCCESS; - - return; + return 0; err_out_disable: ap->ops->port_disable(ap); err_out: - ap->thr_state = THR_PROBE_FAILED; + return -1; } /** @@ -2718,62 +2688,6 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) return IRQ_RETVAL(handled); } -/** - * ata_thread_iter - - * @ap: - * - * LOCKING: - * - * RETURNS: - * - */ - -static unsigned long ata_thread_iter(struct ata_port *ap) -{ - long timeout = 0; - - DPRINTK("ata%u: thr_state %s\n", - ap->id, ata_thr_state_name(ap->thr_state)); - - switch (ap->thr_state) { - case THR_UNKNOWN: - ap->thr_state = THR_PORT_RESET; - break; - - case THR_PROBE_START: - ap->thr_state = THR_PORT_RESET; - break; - - case THR_PORT_RESET: - ata_port_reset(ap); - break; - - case THR_PROBE_SUCCESS: - up(&ap->probe_sem); - ap->thr_state = THR_IDLE; - break; - - case THR_PROBE_FAILED: - up(&ap->probe_sem); - ap->thr_state = THR_AWAIT_DEATH; - break; - - case THR_AWAIT_DEATH: - case THR_IDLE: - timeout = -1; - break; - - default: - printk(KERN_DEBUG "ata%u: unknown thr state %s\n", - ap->id, ata_thr_state_name(ap->thr_state)); - break; - } - - DPRINTK("ata%u: new thr_state %s, returning %ld\n", - ap->id, ata_thr_state_name(ap->thr_state), timeout); - return timeout; -} - /** * atapi_packet_task - Write CDB bytes to hardware * @_data: Port to which ATAPI device is attached. @@ -2855,21 +2769,6 @@ void ata_port_stop (struct ata_port *ap) pci_free_consistent(pdev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma); } -static void ata_probe_task(void *_data) -{ - struct ata_port *ap = _data; - long timeout; - - timeout = ata_thread_iter(ap); - if (timeout < 0) - return; - - if (timeout > 0) - queue_delayed_work(ata_wq, &ap->probe_task, timeout); - else - queue_work(ata_wq, &ap->probe_task); -} - /** * ata_host_remove - Unregister SCSI host structure with upper layers * @ap: Port to unregister @@ -2926,7 +2825,6 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, ap->udma_mask = ent->udma_mask; ap->flags |= ent->host_flags; ap->ops = ent->port_ops; - ap->thr_state = THR_PROBE_START; ap->cbl = ATA_CBL_NONE; ap->device[0].flags = ATA_DFLAG_MASTER; ap->active_tag = ATA_TAG_POISON; @@ -2934,13 +2832,10 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, INIT_WORK(&ap->packet_task, atapi_packet_task, ap); INIT_WORK(&ap->pio_task, ata_pio_task, ap); - INIT_WORK(&ap->probe_task, ata_probe_task, ap); for (i = 0; i < ATA_MAX_DEVICES; i++) ap->device[i].devno = i; - init_MUTEX_LOCKED(&ap->probe_sem); - #ifdef ATA_IRQ_TRAP ap->stats.unhandled_irq = 1; ap->stats.idle_irq = 1; @@ -3063,12 +2958,17 @@ int ata_device_add(struct ata_probe_ent *ent) ap = host_set->ports[i]; DPRINTK("ata%u: probe begin\n", ap->id); - queue_work(ata_wq, &ap->probe_task); /* start probe */ + rc = ata_bus_probe(ap); + DPRINTK("ata%u: probe end\n", ap->id); - DPRINTK("ata%u: probe-wait begin\n", ap->id); - down(&ap->probe_sem); /* wait for end */ - - DPRINTK("ata%u: probe-wait end\n", ap->id); + if (rc) { + /* FIXME: do something useful here? + * Current libata behavior will + * tear down everything when + * the module is removed + * or the h/w is unplugged. + */ + } rc = scsi_add_host(ap->host, &pdev->dev); if (rc) { diff --git a/include/linux/libata.h b/include/linux/libata.h index 18c90a0c1cfd..b2fd0adbe5b6 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -133,15 +133,6 @@ enum { BUS_IDENTIFY = 8, BUS_PACKET = 9, - /* thread states */ - THR_UNKNOWN = 0, - THR_PORT_RESET = (THR_UNKNOWN + 1), - THR_AWAIT_DEATH = (THR_PORT_RESET + 1), - THR_PROBE_FAILED = (THR_AWAIT_DEATH + 1), - THR_IDLE = (THR_PROBE_FAILED + 1), - THR_PROBE_SUCCESS = (THR_IDLE + 1), - THR_PROBE_START = (THR_PROBE_SUCCESS + 1), - /* SATA port states */ PORT_UNKNOWN = 0, PORT_ENABLED = 1, @@ -294,18 +285,12 @@ struct ata_port { struct ata_host_stats stats; struct ata_host_set *host_set; - struct semaphore probe_sem; - - unsigned int thr_state; - struct work_struct packet_task; struct work_struct pio_task; unsigned int pio_task_state; unsigned long pio_task_timeout; - struct work_struct probe_task; - void *private_data; }; -- cgit v1.2.3 From c23562121ec2a36db28c1b0f8507f2d534700e69 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 14 Jun 2004 14:40:59 -0400 Subject: [libata] PCI IDE DMA code shuffling PCI IDE DMA standard (or "bmdma") helper routines ata_bmdma_stop, ata_bmdma_ack_irq, and ata_bmdma_status are added to linux/libata.h, and used in libata-core. There is a minor behavior change, such that, the Alt Status register is read before acknowledging the bmdma interrupt. This should be ok, and furthermore there will be more significant behavior changes in this area coming soon. --- drivers/scsi/libata-core.c | 45 ++++----------------------------------------- include/linux/libata.h | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 41 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index e0a907b48caa..95c0ea11150a 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2115,22 +2115,6 @@ static void ata_pio_task(void *_data) } } -/** - * ata_check_bmdma - read PCI IDE BMDMA status - * @ap: struct ata_port - */ - -static u8 ata_check_bmdma(struct ata_port *ap) -{ - u8 host_stat; - if (ap->flags & ATA_FLAG_MMIO) { - void *mmio = (void *) ap->ioaddr.bmdma_addr; - host_stat = readb(mmio + ATA_DMA_STATUS); - } else - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - return host_stat; -} - /** * ata_eng_timeout - Handle timeout of queued command * @ap: Port on which timed-out command is active @@ -2174,7 +2158,7 @@ void ata_eng_timeout(struct ata_port *ap) switch (qc->tf.protocol) { case ATA_PROT_DMA: - host_stat = ata_check_bmdma(ap); + host_stat = ata_bmdma_status(ap); printk(KERN_ERR "ata%u: DMA timeout, stat 0x%x\n", ap->id, host_stat); @@ -2546,29 +2530,8 @@ static void ata_dma_complete(struct ata_queued_cmd *qc, u8 host_stat) struct ata_port *ap = qc->ap; VPRINTK("ENTER\n"); - if (ap->flags & ATA_FLAG_MMIO) { - void *mmio = (void *) ap->ioaddr.bmdma_addr; - - /* clear start/stop bit */ - writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START, - mmio + ATA_DMA_CMD); - - /* ack intr, err bits */ - writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, - mmio + ATA_DMA_STATUS); - } else { - /* clear start/stop bit */ - outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, - ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - - /* ack intr, err bits */ - outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, - ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - } - - - /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ - ata_altstatus(ap); /* dummy read */ + ata_bmdma_stop(ap); + ata_bmdma_ack_irq(ap); DPRINTK("host %u, host_stat==0x%X, drv_stat==0x%X\n", ap->id, (u32) host_stat, (u32) ata_chk_status(ap)); @@ -2604,7 +2567,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap, /* BMDMA completion */ case ATA_PROT_DMA: case ATA_PROT_ATAPI_DMA: - host_stat = ata_check_bmdma(ap); + host_stat = ata_bmdma_status(ap); VPRINTK("BUS_DMA (host_stat 0x%X)\n", host_stat); if (!(host_stat & ATA_DMA_INTR)) { diff --git a/include/linux/libata.h b/include/linux/libata.h index b2fd0adbe5b6..c9713d0d30af 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -541,4 +541,44 @@ static inline unsigned int sata_dev_present(struct ata_port *ap) return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0; } +static inline void ata_bmdma_stop(struct ata_port *ap) +{ + if (ap->flags & ATA_FLAG_MMIO) { + void *mmio = (void *) ap->ioaddr.bmdma_addr; + + /* clear start/stop bit */ + writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START, + mmio + ATA_DMA_CMD); + } else { + /* clear start/stop bit */ + outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, + ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + } + + /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ + ata_altstatus(ap); /* dummy read */ +} + +static inline void ata_bmdma_ack_irq(struct ata_port *ap) +{ + if (ap->flags & ATA_FLAG_MMIO) { + void *mmio = ((void *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS; + writeb(readb(mmio), mmio); + } else { + unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS; + outb(inb(addr), addr); + } +} + +static inline u8 ata_bmdma_status(struct ata_port *ap) +{ + u8 host_stat; + if (ap->flags & ATA_FLAG_MMIO) { + void *mmio = (void *) ap->ioaddr.bmdma_addr; + host_stat = readb(mmio + ATA_DMA_STATUS); + } else + host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + return host_stat; +} + #endif /* __LINUX_LIBATA_H__ */ -- cgit v1.2.3 From 5ae20cc7a8f268c28b987b716b11b4dab4d14142 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 14 Jun 2004 15:54:02 -0400 Subject: [libata] PCI IDE command-end/irq-acknowledge cleanup Restruct default irq handler (used for many PCI IDE-like SATA controllers) to obtain device status and acknowledge interrupts a bit differently. In an attempt to better attack the "ich5 screaming interrupt" problem, acknowledge and clear the device's INTRQ by reading the Status register _before_ ack'ing the controller's irq status. This is a deviation from how the Linux IDE driver acknowledges interrupts, but it may be the best method, since the ICH5 appears to continue to assert the interrupt bit in the BMDMA until the device INTRQ line is cleared. Of course, SATA has no INTRQ line per se, so ICH5 essentially has new interrupt behavior not seen before in the PCI IDE world, while pretending that it's compatible with PCI IDE. Sigh. This change affects all SATA controllers (for which there are libata drivers) except for sata_promise and sata_sx4. --- drivers/scsi/libata-core.c | 140 ++++++++++++++++++--------------------------- 1 file changed, 57 insertions(+), 83 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 95c0ea11150a..e2c593c130c4 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -50,7 +50,6 @@ static unsigned int ata_busy_sleep (struct ata_port *ap, unsigned long tmout_pat, unsigned long tmout); static void __ata_dev_select (struct ata_port *ap, unsigned int device); -static void ata_dma_complete(struct ata_queued_cmd *qc, u8 host_stat); static void ata_host_set_pio(struct ata_port *ap); static void ata_host_set_udma(struct ata_port *ap); static void ata_dev_set_pio(struct ata_port *ap, unsigned int device); @@ -2136,7 +2135,7 @@ static void ata_pio_task(void *_data) void ata_eng_timeout(struct ata_port *ap) { - u8 host_stat, drv_stat; + u8 host_stat = 0, drv_stat; struct ata_queued_cmd *qc; DPRINTK("ENTER\n"); @@ -2157,30 +2156,28 @@ void ata_eng_timeout(struct ata_port *ap) qc->scsidone = scsi_finish_command; switch (qc->tf.protocol) { + case ATA_PROT_DMA: + case ATA_PROT_ATAPI_DMA: host_stat = ata_bmdma_status(ap); - printk(KERN_ERR "ata%u: DMA timeout, stat 0x%x\n", - ap->id, host_stat); + /* before we do anything else, clear DMA-Start bit */ + ata_bmdma_stop(ap); - ata_dma_complete(qc, host_stat); - break; + /* fall through */ case ATA_PROT_NODATA: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - - printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); - - ata_qc_complete(qc, drv_stat); - break; - default: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + ata_altstatus(ap); + drv_stat = ata_chk_status(ap); + + /* ack bmdma irq events */ + ata_bmdma_ack_irq(ap); - printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); + printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n", + ap->id, qc->tf.command, drv_stat, host_stat); + /* complete taskfile transaction */ ata_qc_complete(qc, drv_stat); break; } @@ -2412,7 +2409,7 @@ void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); - u8 host_stat, dmactl; + u8 dmactl; void *mmio = (void *) ap->ioaddr.bmdma_addr; /* load PRD table addr. */ @@ -2426,10 +2423,6 @@ void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc) dmactl |= ATA_DMA_WR; writeb(dmactl, mmio + ATA_DMA_CMD); - /* clear interrupt, error bits */ - host_stat = readb(mmio + ATA_DMA_STATUS); - writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, mmio + ATA_DMA_STATUS); - /* issue r/w command */ ap->ops->exec_command(ap, &qc->tf); } @@ -2477,7 +2470,7 @@ void ata_bmdma_setup_pio (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); - u8 host_stat, dmactl; + u8 dmactl; /* load PRD table addr. */ outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); @@ -2489,11 +2482,6 @@ void ata_bmdma_setup_pio (struct ata_queued_cmd *qc) dmactl |= ATA_DMA_WR; outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - /* clear interrupt, error bits */ - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, - ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - /* issue r/w command */ ap->ops->exec_command(ap, &qc->tf); } @@ -2517,29 +2505,6 @@ void ata_bmdma_start_pio (struct ata_queued_cmd *qc) ap->ioaddr.bmdma_addr + ATA_DMA_CMD); } -/** - * ata_dma_complete - Complete an active ATA BMDMA command - * @qc: Command to complete - * @host_stat: BMDMA status register contents - * - * LOCKING: - */ - -static void ata_dma_complete(struct ata_queued_cmd *qc, u8 host_stat) -{ - struct ata_port *ap = qc->ap; - VPRINTK("ENTER\n"); - - ata_bmdma_stop(ap); - ata_bmdma_ack_irq(ap); - - DPRINTK("host %u, host_stat==0x%X, drv_stat==0x%X\n", - ap->id, (u32) host_stat, (u32) ata_chk_status(ap)); - - /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap)); -} - /** * ata_host_intr - Handle host interrupt for given (port, task) * @ap: Port on which interrupt arrived (possibly...) @@ -2560,55 +2525,60 @@ inline unsigned int ata_host_intr (struct ata_port *ap, struct ata_queued_cmd *qc) { u8 status, host_stat; - unsigned int handled = 0; switch (qc->tf.protocol) { - /* BMDMA completion */ case ATA_PROT_DMA: case ATA_PROT_ATAPI_DMA: + /* check status of DMA engine */ host_stat = ata_bmdma_status(ap); VPRINTK("BUS_DMA (host_stat 0x%X)\n", host_stat); - if (!(host_stat & ATA_DMA_INTR)) { - ap->stats.idle_irq++; - break; - } + /* if it's not our irq... */ + if (!(host_stat & ATA_DMA_INTR)) + goto idle_irq; - ata_dma_complete(qc, host_stat); - handled = 1; - break; + /* before we do anything else, clear DMA-Start bit */ + ata_bmdma_stop(ap); + + /* fall through */ - /* command completion, but no data xfer */ - /* FIXME: a shared interrupt _will_ cause a non-data command - * to be completed prematurely, with an error. - * - * This doesn't matter right now, since we aren't sending - * non-data commands down this pipe except in development - * situations. - */ - case ATA_PROT_ATAPI: case ATA_PROT_NODATA: - status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status); + /* check altstatus */ + status = ata_altstatus(ap); + if (status & ATA_BUSY) + goto idle_irq; + + /* check main status, clearing INTRQ */ + status = ata_chk_status(ap); + if (unlikely(status & ATA_BUSY)) + goto idle_irq; + DPRINTK("BUS_NODATA (dev_stat 0x%X)\n", status); + + /* ack bmdma irq events */ + ata_bmdma_ack_irq(ap); + + /* complete taskfile transaction */ ata_qc_complete(qc, status); - handled = 1; break; default: - ap->stats.idle_irq++; + goto idle_irq; + } + + return 1; /* irq handled */ + +idle_irq: + ap->stats.idle_irq++; #ifdef ATA_IRQ_TRAP - if ((ap->stats.idle_irq % 1000) == 0) { - handled = 1; - ata_irq_ack(ap, 0); /* debug trap */ - printk(KERN_WARNING "ata%d: irq trap\n", ap->id); - } -#endif - break; + if ((ap->stats.idle_irq % 1000) == 0) { + handled = 1; + ata_irq_ack(ap, 0); /* debug trap */ + printk(KERN_WARNING "ata%d: irq trap\n", ap->id); } - - return handled; +#endif + return 0; /* irq not handled */ } /** @@ -2642,7 +2612,7 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) qc = ata_qc_from_tag(ap, ap->active_tag); if (qc && (!(qc->tf.ctl & ATA_NIEN))) - handled += ata_host_intr(ap, qc); + handled |= ata_host_intr(ap, qc); } } @@ -2907,6 +2877,10 @@ int ata_device_add(struct ata_probe_ent *ent) return 0; } + /* TODO: ack irq here, to ensure it won't scream + * when we enable it? + */ + /* obtain irq, that is shared between channels */ if (request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags, DRV_NAME, host_set)) -- cgit v1.2.3 From 2b13abe5a557a62c0ebb9ab24157d178fa23df20 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 14 Jun 2004 16:29:37 -0400 Subject: [libata] ->qc_prep hook Rename ->fill_sg hook to ->qc_prep, and call it unconditionally (as opposed to ->fill_sg, which was called only when the flag ATA_QCFLAG_SG was set). --- drivers/scsi/ata_piix.c | 4 ++-- drivers/scsi/libata-core.c | 50 ++++++++++++++++++++++++++------------------- drivers/scsi/sata_promise.c | 8 ++++---- drivers/scsi/sata_sil.c | 2 +- drivers/scsi/sata_sis.c | 2 +- drivers/scsi/sata_svw.c | 2 +- drivers/scsi/sata_sx4.c | 9 +++++--- drivers/scsi/sata_via.c | 2 +- drivers/scsi/sata_vsc.c | 2 +- include/linux/libata.h | 4 ++-- 10 files changed, 48 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index a6588b0f8c98..e02e33c17404 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -138,7 +138,7 @@ static struct ata_port_operations piix_pata_ops = { .bmdma_setup = ata_bmdma_setup_pio, .bmdma_start = ata_bmdma_start_pio, - .fill_sg = ata_fill_sg, + .qc_prep = ata_qc_prep, .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, @@ -161,7 +161,7 @@ static struct ata_port_operations piix_sata_ops = { .bmdma_setup = ata_bmdma_setup_pio, .bmdma_start = ata_bmdma_start_pio, - .fill_sg = ata_fill_sg, + .qc_prep = ata_qc_prep, .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index e2c593c130c4..e0f59b47cc71 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1775,13 +1775,13 @@ static void ata_sg_clean(struct ata_queued_cmd *qc) } /** - * ata_fill_sg - - * @qc: + * ata_fill_sg - Fill PCI IDE PRD table + * @qc: Metadata associated with taskfile to be transferred * * LOCKING: * */ -void ata_fill_sg(struct ata_queued_cmd *qc) +static void ata_fill_sg(struct ata_queued_cmd *qc) { struct scatterlist *sg = qc->sg; struct ata_port *ap = qc->ap; @@ -1822,6 +1822,21 @@ void ata_fill_sg(struct ata_queued_cmd *qc) ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); } +/** + * ata_qc_prep - Prepare taskfile for submission + * @qc: Metadata associated with taskfile to be prepared + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ +void ata_qc_prep(struct ata_queued_cmd *qc) +{ + if (!(qc->flags & ATA_QCFLAG_SG)) + return; + + ata_fill_sg(qc); +} + /** * ata_sg_setup_one - * @qc: @@ -1839,7 +1854,6 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc) struct scsi_cmnd *cmd = qc->scsicmd; int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); struct scatterlist *sg = qc->sg; - unsigned int have_sg = (qc->flags & ATA_QCFLAG_SG); dma_addr_t dma_address; assert(sg == &qc->sgent); @@ -1849,9 +1863,6 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc) sg->offset = (unsigned long) cmd->request_buffer & ~PAGE_MASK; sg_dma_len(sg) = cmd->request_bufflen; - if (!have_sg) - return 0; - dma_address = pci_map_single(ap->host_set->pdev, cmd->request_buffer, cmd->request_bufflen, dir); if (pci_dma_mapping_error(dma_address)) @@ -1881,22 +1892,19 @@ static int ata_sg_setup(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; struct scsi_cmnd *cmd = qc->scsicmd; struct scatterlist *sg; - int n_elem; - unsigned int have_sg = (qc->flags & ATA_QCFLAG_SG); + int n_elem, dir; VPRINTK("ENTER, ata%u, use_sg %d\n", ap->id, cmd->use_sg); assert(cmd->use_sg > 0); sg = (struct scatterlist *)cmd->request_buffer; - if (have_sg) { - int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); - n_elem = pci_map_sg(ap->host_set->pdev, sg, cmd->use_sg, dir); - if (n_elem < 1) - return -1; - DPRINTK("%d sg elements mapped\n", n_elem); - } else { - n_elem = cmd->use_sg; - } + dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + n_elem = pci_map_sg(ap->host_set->pdev, sg, cmd->use_sg, dir); + if (n_elem < 1) + return -1; + + DPRINTK("%d sg elements mapped\n", n_elem); + qc->n_elem = n_elem; return 0; @@ -2325,10 +2333,10 @@ int ata_qc_issue(struct ata_queued_cmd *qc) if (ata_sg_setup_one(qc)) goto err_out; } - - ap->ops->fill_sg(qc); } + ap->ops->qc_prep(qc); + qc->ap->active_tag = qc->tag; qc->flags |= ATA_QCFLAG_ACTIVE; @@ -3325,7 +3333,7 @@ EXPORT_SYMBOL_GPL(ata_exec_command_mmio); EXPORT_SYMBOL_GPL(ata_port_start); EXPORT_SYMBOL_GPL(ata_port_stop); EXPORT_SYMBOL_GPL(ata_interrupt); -EXPORT_SYMBOL_GPL(ata_fill_sg); +EXPORT_SYMBOL_GPL(ata_qc_prep); EXPORT_SYMBOL_GPL(ata_bmdma_setup_pio); EXPORT_SYMBOL_GPL(ata_bmdma_start_pio); EXPORT_SYMBOL_GPL(ata_bmdma_setup_mmio); diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index 268b2c345728..ae6d77c96786 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -81,7 +81,7 @@ static void pdc_eng_timeout(struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); static void pdc_port_stop(struct ata_port *ap); static void pdc_phy_reset(struct ata_port *ap); -static void pdc_fill_sg(struct ata_queued_cmd *qc); +static void pdc_qc_prep(struct ata_queued_cmd *qc); static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); static inline void pdc_dma_complete (struct ata_port *ap, @@ -114,7 +114,7 @@ static struct ata_port_operations pdc_sata_ops = { .phy_reset = pdc_phy_reset, .bmdma_setup = pdc_dma_setup, .bmdma_start = pdc_dma_start, - .fill_sg = pdc_fill_sg, + .qc_prep = pdc_qc_prep, .eng_timeout = pdc_eng_timeout, .irq_handler = pdc_interrupt, .scr_read = pdc_sata_scr_read, @@ -261,14 +261,14 @@ static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); } -static void pdc_fill_sg(struct ata_queued_cmd *qc) +static void pdc_qc_prep(struct ata_queued_cmd *qc) { struct pdc_port_priv *pp = qc->ap->private_data; unsigned int i; VPRINTK("ENTER\n"); - ata_fill_sg(qc); + ata_qc_prep(qc); i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma, qc->dev->devno, pp->pkt); diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index 33ae676e2d78..49ce4d02c1fd 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -131,7 +131,7 @@ static struct ata_port_operations sil_ops = { .post_set_mode = sil_post_set_mode, .bmdma_setup = ata_bmdma_setup_mmio, .bmdma_start = ata_bmdma_start_mmio, - .fill_sg = ata_fill_sg, + .qc_prep = ata_qc_prep, .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, .scr_read = sil_scr_read, diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c index 8965ee281839..a2106d2ebb18 100644 --- a/drivers/scsi/sata_sis.c +++ b/drivers/scsi/sata_sis.c @@ -100,7 +100,7 @@ static struct ata_port_operations sis_ops = { .phy_reset = sata_phy_reset, .bmdma_setup = ata_bmdma_setup_pio, .bmdma_start = ata_bmdma_start_pio, - .fill_sg = ata_fill_sg, + .qc_prep = ata_qc_prep, .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, .scr_read = sis_scr_read, diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c index 60841abc4398..af28b1f7a95f 100644 --- a/drivers/scsi/sata_svw.c +++ b/drivers/scsi/sata_svw.c @@ -233,7 +233,7 @@ static struct ata_port_operations k2_sata_ops = { .phy_reset = sata_phy_reset, .bmdma_setup = ata_bmdma_setup_mmio, .bmdma_start = ata_bmdma_start_mmio, - .fill_sg = ata_fill_sg, + .qc_prep = ata_qc_prep, .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, .scr_read = k2_sata_scr_read, diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index 3268fdf7e583..ea8ddcc78a6d 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -153,7 +153,7 @@ static void pdc_eng_timeout(struct ata_port *ap); static void pdc_20621_phy_reset (struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); static void pdc_port_stop(struct ata_port *ap); -static void pdc20621_fill_sg(struct ata_queued_cmd *qc); +static void pdc20621_qc_prep(struct ata_queued_cmd *qc); static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc20621_host_stop(struct ata_host_set *host_set); @@ -200,7 +200,7 @@ static struct ata_port_operations pdc_20621_ops = { .phy_reset = pdc_20621_phy_reset, .bmdma_setup = pdc20621_dma_setup, .bmdma_start = pdc20621_dma_start, - .fill_sg = pdc20621_fill_sg, + .qc_prep = pdc20621_qc_prep, .eng_timeout = pdc_eng_timeout, .irq_handler = pdc20621_interrupt, .port_start = pdc_port_start, @@ -434,7 +434,7 @@ static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf, buf32[dw + 3]); } -static void pdc20621_fill_sg(struct ata_queued_cmd *qc) +static void pdc20621_qc_prep(struct ata_queued_cmd *qc) { struct scatterlist *sg = qc->sg; struct ata_port *ap = qc->ap; @@ -446,6 +446,9 @@ static void pdc20621_fill_sg(struct ata_queued_cmd *qc) unsigned int i, last, idx, total_len = 0, sgt_len; u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ]; + if (!(qc->flags & ATA_QCFLAG_SG)) + return; + VPRINTK("ata%u: ENTER\n", ap->id); /* hard-code chip #0 */ diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c index 46d385128842..84ee429471ce 100644 --- a/drivers/scsi/sata_via.c +++ b/drivers/scsi/sata_via.c @@ -108,7 +108,7 @@ static struct ata_port_operations svia_sata_ops = { .bmdma_setup = ata_bmdma_setup_pio, .bmdma_start = ata_bmdma_start_pio, - .fill_sg = ata_fill_sg, + .qc_prep = ata_qc_prep, .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index e0ad17121850..a09f03ee0ef0 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -215,7 +215,7 @@ static struct ata_port_operations vsc_sata_ops = { .phy_reset = sata_phy_reset, .bmdma_setup = ata_bmdma_setup_mmio, .bmdma_start = ata_bmdma_start_mmio, - .fill_sg = ata_fill_sg, + .qc_prep = ata_qc_prep, .eng_timeout = ata_eng_timeout, .irq_handler = vsc_sata_interrupt, .scr_read = vsc_sata_scr_read, diff --git a/include/linux/libata.h b/include/linux/libata.h index c9713d0d30af..a5cbca376a92 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -315,7 +315,7 @@ struct ata_port_operations { void (*bmdma_setup) (struct ata_queued_cmd *qc); void (*bmdma_start) (struct ata_queued_cmd *qc); - void (*fill_sg) (struct ata_queued_cmd *qc); + void (*qc_prep) (struct ata_queued_cmd *qc); void (*eng_timeout) (struct ata_port *ap); irqreturn_t (*irq_handler)(int, void *, struct pt_regs *); @@ -375,7 +375,7 @@ extern void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); extern int ata_port_start (struct ata_port *ap); extern void ata_port_stop (struct ata_port *ap); extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs); -extern void ata_fill_sg(struct ata_queued_cmd *qc); +extern void ata_qc_prep(struct ata_queued_cmd *qc); extern void ata_dev_id_string(struct ata_device *dev, unsigned char *s, unsigned int ofs, unsigned int len); extern void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc); -- cgit v1.2.3 From 13ffe5f82ac23303e6c21ac842269bb4a48a6473 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Tue, 15 Jun 2004 03:48:14 -0700 Subject: [ARM] Timer cleanup Signed-off-by: Deepak Saxena --- arch/arm/Kconfig | 5 + arch/arm/common/Makefile | 1 + arch/arm/common/time-acorn.c | 67 +++++++ arch/arm/kernel/Makefile | 3 +- arch/arm/kernel/setup.c | 3 + arch/arm/kernel/time-acorn.c | 66 ------- arch/arm/kernel/time.c | 27 ++- arch/arm/mach-clps711x/autcpu12.c | 2 + arch/arm/mach-clps711x/cdb89712.c | 2 + arch/arm/mach-clps711x/ceiva.c | 2 + arch/arm/mach-clps711x/clep7312.c | 2 + arch/arm/mach-clps711x/edb7211-arch.c | 2 + arch/arm/mach-clps711x/fortunet.c | 2 + arch/arm/mach-clps711x/p720t.c | 2 + arch/arm/mach-clps711x/time.c | 32 ++- arch/arm/mach-clps7500/core.c | 41 +++- arch/arm/mach-ebsa110/core.c | 102 ++++++++++ arch/arm/mach-ebsa110/time.c | 118 +++++++++++ arch/arm/mach-epxa10db/arch.c | 3 + arch/arm/mach-epxa10db/time.c | 46 ++++- arch/arm/mach-footbridge/Makefile | 2 +- arch/arm/mach-footbridge/arch.c | 6 + arch/arm/mach-footbridge/time.c | 305 +++++++++++++++++++++++++++++ arch/arm/mach-ftvpci/core.c | 47 +++++ arch/arm/mach-integrator/integrator_ap.c | 6 + arch/arm/mach-integrator/integrator_cp.c | 6 + arch/arm/mach-integrator/time.c | 146 ++++++++++++++ arch/arm/mach-iop3xx/arch.c | 2 + arch/arm/mach-iop3xx/iop321-time.c | 13 +- arch/arm/mach-ixp4xx/common.c | 15 +- arch/arm/mach-ixp4xx/coyote-setup.c | 1 + arch/arm/mach-ixp4xx/ixdp425-setup.c | 3 + arch/arm/mach-ixp4xx/prpmc1100-setup.c | 1 + arch/arm/mach-lh7a40x/Makefile | 2 +- arch/arm/mach-lh7a40x/arch-kev7a400.c | 2 + arch/arm/mach-lh7a40x/arch-lpd7a40x.c | 2 + arch/arm/mach-lh7a40x/time.c | 70 +++++++ arch/arm/mach-omap/Makefile | 2 +- arch/arm/mach-omap/board-generic.c | 7 + arch/arm/mach-omap/board-innovator.c | 1 + arch/arm/mach-omap/board-osk.c | 1 + arch/arm/mach-omap/board-perseus2.c | 1 + arch/arm/mach-omap/common.h | 1 + arch/arm/mach-omap/time.c | 214 ++++++++++++++++++++ arch/arm/mach-pxa/Makefile | 2 +- arch/arm/mach-pxa/generic.h | 1 + arch/arm/mach-pxa/idp.c | 1 + arch/arm/mach-pxa/lubbock.c | 1 + arch/arm/mach-pxa/mainstone.c | 1 + arch/arm/mach-pxa/time.c | 128 ++++++++++++ arch/arm/mach-rpc/riscpc.c | 31 +++ arch/arm/mach-s3c2410/Makefile | 2 +- arch/arm/mach-s3c2410/mach-bast.c | 6 + arch/arm/mach-s3c2410/mach-h1940.c | 6 + arch/arm/mach-s3c2410/mach-smdk2410.c | 6 + arch/arm/mach-s3c2410/mach-vr1000.c | 6 + arch/arm/mach-s3c2410/s3c2410.h | 2 + arch/arm/mach-s3c2410/time.c | 181 +++++++++++++++++ arch/arm/mach-sa1100/adsbitsy.c | 1 + arch/arm/mach-sa1100/assabet.c | 1 + arch/arm/mach-sa1100/badge4.c | 1 + arch/arm/mach-sa1100/brutus.c | 1 + arch/arm/mach-sa1100/cerf.c | 1 + arch/arm/mach-sa1100/empeg.c | 1 + arch/arm/mach-sa1100/flexanet.c | 1 + arch/arm/mach-sa1100/freebird.c | 1 + arch/arm/mach-sa1100/generic.h | 1 + arch/arm/mach-sa1100/graphicsclient.c | 1 + arch/arm/mach-sa1100/graphicsmaster.c | 1 + arch/arm/mach-sa1100/h3600.c | 3 + arch/arm/mach-sa1100/hackkit.c | 1 + arch/arm/mach-sa1100/huw_webpanel.c | 1 + arch/arm/mach-sa1100/itsy.c | 1 + arch/arm/mach-sa1100/jornada720.c | 1 + arch/arm/mach-sa1100/lart.c | 1 + arch/arm/mach-sa1100/nanoengine.c | 1 + arch/arm/mach-sa1100/omnimeter.c | 1 + arch/arm/mach-sa1100/pangolin.c | 1 + arch/arm/mach-sa1100/pfs168.c | 1 + arch/arm/mach-sa1100/pleb.c | 1 + arch/arm/mach-sa1100/shannon.c | 1 + arch/arm/mach-sa1100/sherman.c | 1 + arch/arm/mach-sa1100/simpad.c | 1 + arch/arm/mach-sa1100/stork.c | 1 + arch/arm/mach-sa1100/system3.c | 1 + arch/arm/mach-sa1100/time.c | 116 +++++++++++ arch/arm/mach-sa1100/trizeps.c | 1 + arch/arm/mach-sa1100/xp860.c | 1 + arch/arm/mach-sa1100/yopy.c | 1 + arch/arm/mach-shark/core.c | 40 ++++ arch/arm/mach-tbox/core.c | 27 +++ arch/arm/mach-versatile/core.c | 147 ++++++++++++++ include/asm-arm/arch-adifcc/time.h | 9 - include/asm-arm/arch-cl7500/time.h | 43 ---- include/asm-arm/arch-ebsa110/time.h | 118 ----------- include/asm-arm/arch-ebsa285/time.h | 287 --------------------------- include/asm-arm/arch-epxa10db/time.h | 60 ------ include/asm-arm/arch-integrator/platform.h | 4 + include/asm-arm/arch-ixp4xx/platform.h | 1 + include/asm-arm/arch-lh7a40x/time.h | 53 ----- include/asm-arm/arch-omap/time.h | 212 -------------------- include/asm-arm/arch-pxa/time.h | 105 ---------- include/asm-arm/arch-rpc/time.h | 37 ---- include/asm-arm/arch-s3c2410/time.h | 173 ---------------- include/asm-arm/arch-sa1100/time.h | 111 ----------- include/asm-arm/arch-shark/time.h | 39 ---- include/asm-arm/arch-tbox/time.h | 39 ---- include/asm-arm/mach/arch.h | 5 + 108 files changed, 2022 insertions(+), 1394 deletions(-) create mode 100644 arch/arm/common/time-acorn.c delete mode 100644 arch/arm/kernel/time-acorn.c create mode 100644 arch/arm/mach-ebsa110/time.c create mode 100644 arch/arm/mach-footbridge/time.c create mode 100644 arch/arm/mach-lh7a40x/time.c create mode 100644 arch/arm/mach-omap/time.c create mode 100644 arch/arm/mach-pxa/time.c create mode 100644 arch/arm/mach-s3c2410/time.c create mode 100644 arch/arm/mach-sa1100/time.c delete mode 100644 include/asm-arm/arch-adifcc/time.h delete mode 100644 include/asm-arm/arch-cl7500/time.h delete mode 100644 include/asm-arm/arch-ebsa110/time.h delete mode 100644 include/asm-arm/arch-ebsa285/time.h delete mode 100644 include/asm-arm/arch-epxa10db/time.h delete mode 100644 include/asm-arm/arch-lh7a40x/time.h delete mode 100644 include/asm-arm/arch-omap/time.h delete mode 100644 include/asm-arm/arch-pxa/time.h delete mode 100644 include/asm-arm/arch-rpc/time.h delete mode 100644 include/asm-arm/arch-s3c2410/time.h delete mode 100644 include/asm-arm/arch-sa1100/time.h delete mode 100644 include/asm-arm/arch-shark/time.h delete mode 100644 include/asm-arm/arch-tbox/time.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 03b9d5bc6b70..4e6ee6be1447 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -191,6 +191,11 @@ config ARCH_ACORN depends on ARCH_RPC default y +config TIMER_ACORN + bool + depends on ARCH_ACORN || ARCH_CLPS7500 + default y + ##################################################################### # Footbridge support config FOOTBRIDGE diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index f326bac694fd..6f6393a5c230 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_SA1111) += sa1111.o obj-$(CONFIG_PCI_HOST_PLX90X0) += plx90x0.o obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o obj-$(CONFIG_DMABOUNCE) += dmabounce.o +obj-$(CONFIG_TIMER_ACORN) += time-acorn.o diff --git a/arch/arm/common/time-acorn.c b/arch/arm/common/time-acorn.c new file mode 100644 index 000000000000..eb06282962eb --- /dev/null +++ b/arch/arm/common/time-acorn.c @@ -0,0 +1,67 @@ +/* + * linux/arch/arm/common/time-acorn.c + * + * Copyright (c) 1996-2000 Russell King. + * + * This program 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. + * + * Changelog: + * 24-Sep-1996 RMK Created + * 10-Oct-1996 RMK Brought up to date with arch-sa110eval + * 04-Dec-1997 RMK Updated for new arch/arm/time.c + * 13=Jun-2004 DS Moved to arch/arm/common b/c shared w/CLPS7500 + */ +#include +#include + +#include +#include +#include + +#include + +static unsigned long ioctime_gettimeoffset(void) +{ + unsigned int count1, count2, status; + long offset; + + ioc_writeb (0, IOC_T0LATCH); + barrier (); + count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); + barrier (); + status = ioc_readb(IOC_IRQREQA); + barrier (); + ioc_writeb (0, IOC_T0LATCH); + barrier (); + count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); + + offset = count2; + if (count2 < count1) { + /* + * We have not had an interrupt between reading count1 + * and count2. + */ + if (status & (1 << 5)) + offset -= LATCH; + } else if (count2 > count1) { + /* + * We have just had another interrupt between reading + * count1 and count2. + */ + offset -= LATCH; + } + + offset = (LATCH - offset) * (tick_nsec / 1000); + return (offset + LATCH/2) / LATCH; +} + +void __init ioctime_init(void) +{ + ioc_writeb(LATCH & 255, IOC_T0LTCHL); + ioc_writeb(LATCH >> 8, IOC_T0LTCHH); + ioc_writeb(0, IOC_T0GO); + + gettimeoffset = ioctime_gettimeoffset; +} diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 991c219b347c..1a85e39d79be 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -11,8 +11,7 @@ obj-y := arch.o compat.o dma.o entry-armv.o entry-common.o irq.o \ time.o traps.o obj-$(CONFIG_APM) += apm.o -obj-$(CONFIG_ARCH_ACORN) += ecard.o time-acorn.o -obj-$(CONFIG_ARCH_CLPS7500) += time-acorn.o +obj-$(CONFIG_ARCH_ACORN) += ecard.o obj-$(CONFIG_FOOTBRIDGE) += isa.o obj-$(CONFIG_FIQ) += fiq.o obj-$(CONFIG_MODULES) += armksyms.o module.o diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 1cff09a5537a..d159659677b0 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -34,6 +35,7 @@ #include #include +#include #ifndef MEM_SIZE #define MEM_SIZE (16*1024*1024) @@ -727,6 +729,7 @@ void __init setup_arch(char **cmdline_p) * Set up various architecture-specific pointers */ init_arch_irq = mdesc->init_irq; + init_arch_time = mdesc->init_time; init_machine = mdesc->init_machine; #ifdef CONFIG_VT diff --git a/arch/arm/kernel/time-acorn.c b/arch/arm/kernel/time-acorn.c deleted file mode 100644 index a4dd9f0557ff..000000000000 --- a/arch/arm/kernel/time-acorn.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * linux/arch/arm/kernel/time-acorn.c - * - * Copyright (c) 1996-2000 Russell King. - * - * This program 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. - * - * Changelog: - * 24-Sep-1996 RMK Created - * 10-Oct-1996 RMK Brought up to date with arch-sa110eval - * 04-Dec-1997 RMK Updated for new arch/arm/time.c - */ -#include -#include - -#include -#include -#include - -extern unsigned long (*gettimeoffset)(void); - -static unsigned long ioctime_gettimeoffset(void) -{ - unsigned int count1, count2, status; - long offset; - - ioc_writeb (0, IOC_T0LATCH); - barrier (); - count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); - barrier (); - status = ioc_readb(IOC_IRQREQA); - barrier (); - ioc_writeb (0, IOC_T0LATCH); - barrier (); - count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); - - offset = count2; - if (count2 < count1) { - /* - * We have not had an interrupt between reading count1 - * and count2. - */ - if (status & (1 << 5)) - offset -= LATCH; - } else if (count2 > count1) { - /* - * We have just had another interrupt between reading - * count1 and count2. - */ - offset -= LATCH; - } - - offset = (LATCH - offset) * (tick_nsec / 1000); - return (offset + LATCH/2) / LATCH; -} - -void __init ioctime_init(void) -{ - ioc_writeb(LATCH & 255, IOC_T0LTCHL); - ioc_writeb(LATCH >> 8, IOC_T0LTCHH); - ioc_writeb(0, IOC_T0GO); - - gettimeoffset = ioctime_gettimeoffset; -} diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index bfed0f453304..f8c164e94733 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -27,12 +27,15 @@ #include #include #include +#include #include #include #include #include +#include + u64 jiffies_64 = INITIAL_JIFFIES; EXPORT_SYMBOL(jiffies_64); @@ -83,7 +86,7 @@ unsigned long long __attribute__((weak)) sched_clock(void) /* * Handle kernel profile stuff... */ -static inline void do_profile(struct pt_regs *regs) +void do_profile(struct pt_regs *regs) { profile_hook(regs); @@ -113,7 +116,7 @@ static unsigned long next_rtc_update; * called as close as possible to 500 ms before the new second * starts. */ -static inline void do_set_rtc(void) +void do_set_rtc(void) { if (time_status & STA_UNSYNC || set_rtc == NULL) return; @@ -237,8 +240,7 @@ device_initcall(leds_init); EXPORT_SYMBOL(leds_event); #endif -#ifdef CONFIG_LEDS_TIMER -static void do_leds(void) +void do_leds(void) { static unsigned int count = 50; @@ -247,9 +249,6 @@ static void do_leds(void) leds_event(led_timer); } } -#else -#define do_leds() -#endif void do_gettimeofday(struct timeval *tv) { @@ -316,12 +315,10 @@ int do_settimeofday(struct timespec *tv) EXPORT_SYMBOL(do_settimeofday); -static struct irqaction timer_irq = { - .name = "timer", - .flags = SA_INTERRUPT, -}; +void (*init_arch_time)(void); + +void __init time_init(void) +{ + init_arch_time(); +} -/* - * Include architecture specific code - */ -#include diff --git a/arch/arm/mach-clps711x/autcpu12.c b/arch/arm/mach-clps711x/autcpu12.c index e05549a1bd25..f79b05fa5d29 100644 --- a/arch/arm/mach-clps711x/autcpu12.c +++ b/arch/arm/mach-clps711x/autcpu12.c @@ -37,6 +37,7 @@ extern void clps711x_map_io(void); extern void clps711x_init_irq(void); +extern void clps711x_init_time(void); /* * The on-chip registers are given a size of 1MB so that a section can @@ -65,5 +66,6 @@ MACHINE_START(AUTCPU12, "autronix autcpu12") BOOT_PARAMS(0xc0020000) MAPIO(autcpu12_map_io) INITIRQ(clps711x_init_irq) + INITTIME(clp711x_init_time) MACHINE_END diff --git a/arch/arm/mach-clps711x/cdb89712.c b/arch/arm/mach-clps711x/cdb89712.c index d51668d267fa..3da47264430f 100644 --- a/arch/arm/mach-clps711x/cdb89712.c +++ b/arch/arm/mach-clps711x/cdb89712.c @@ -34,6 +34,7 @@ extern void clps711x_init_irq(void); extern void clps711x_map_io(void); +extern void clps711x-init_time(void); /* * Map the CS89712 Ethernet port. That should be moved to the @@ -55,6 +56,7 @@ MACHINE_START(CDB89712, "Cirrus-CDB89712") BOOT_PARAMS(0xc0000100) MAPIO(cdb89712_map_io) INITIRQ(clps711x_init_irq) + INITTIME(clps711x_init_time) MACHINE_END static int cdb89712_hw_init(void) diff --git a/arch/arm/mach-clps711x/ceiva.c b/arch/arm/mach-clps711x/ceiva.c index e9ef76e18544..44d4e5b8d04b 100644 --- a/arch/arm/mach-clps711x/ceiva.c +++ b/arch/arm/mach-clps711x/ceiva.c @@ -35,6 +35,7 @@ #include extern void clps711x_init_irq(void); +extern void clps711x_init_time(void); static struct map_desc ceiva_io_desc[] __initdata = { /* virtual, physical, length, type */ @@ -58,4 +59,5 @@ MACHINE_START(CEIVA, "CEIVA/Polaroid Photo MAX Digital Picture Frame") BOOT_PARAMS(0xc0000100) MAPIO(ceiva_map_io) INITIRQ(clps711x_init_irq) + INITTIME(clps711x_init_time) MACHINE_END diff --git a/arch/arm/mach-clps711x/clep7312.c b/arch/arm/mach-clps711x/clep7312.c index f74f43583c9a..14fb9788cdd1 100644 --- a/arch/arm/mach-clps711x/clep7312.c +++ b/arch/arm/mach-clps711x/clep7312.c @@ -25,6 +25,7 @@ extern void clps711x_init_irq(void); extern void clps711x_map_io(void); +extern void clps711x_init_time(void); static void __init fixup_clep7312(struct machine_desc *desc, struct tag *tags, @@ -44,5 +45,6 @@ MACHINE_START(CLEP7212, "Cirrus Logic 7212/7312") FIXUP(fixup_clep7312) MAPIO(clps711x_map_io) INITIRQ(clps711x_init_irq) + INITTIME(clps711x_init_time) MACHINE_END diff --git a/arch/arm/mach-clps711x/edb7211-arch.c b/arch/arm/mach-clps711x/edb7211-arch.c index 1402447a8ad5..11aa05c24924 100644 --- a/arch/arm/mach-clps711x/edb7211-arch.c +++ b/arch/arm/mach-clps711x/edb7211-arch.c @@ -27,6 +27,7 @@ extern void clps711x_init_irq(void); extern void edb7211_map_io(void); +extern void clps711x_init_time(void); static void __init fixup_edb7211(struct machine_desc *desc, struct tag *tags, @@ -56,4 +57,5 @@ MACHINE_START(EDB7211, "CL-EDB7211 (EP7211 eval board)") FIXUP(fixup_edb7211) MAPIO(edb7211_map_io) INITIRQ(clps711x_init_irq) + INITTIME(clps711x_init_time) MACHINE_END diff --git a/arch/arm/mach-clps711x/fortunet.c b/arch/arm/mach-clps711x/fortunet.c index 268e42baa66a..7a4ba27df7b8 100644 --- a/arch/arm/mach-clps711x/fortunet.c +++ b/arch/arm/mach-clps711x/fortunet.c @@ -33,6 +33,7 @@ extern void clps711x_map_io(void); extern void clps711x_init_irq(void); +extern void clps711x_init_time(void); struct meminfo memmap = { .nr_banks = 1, @@ -82,4 +83,5 @@ MACHINE_START(FORTUNET, "ARM-FortuNet") FIXUP(fortunet_fixup) MAPIO(clps711x_map_io) INITIRQ(clps711x_init_irq) + INITTIME(clps711x_init_time) MACHINE_END diff --git a/arch/arm/mach-clps711x/p720t.c b/arch/arm/mach-clps711x/p720t.c index b99cccfb773b..eb75ae6678ef 100644 --- a/arch/arm/mach-clps711x/p720t.c +++ b/arch/arm/mach-clps711x/p720t.c @@ -36,6 +36,7 @@ extern void clps711x_init_irq(void); extern void clps711x_map_io(void); +extern void clps711x_init_time(void); /* * Map the P720T system PLD. It occupies two address spaces: @@ -86,6 +87,7 @@ MACHINE_START(P720T, "ARM-Prospector720T") FIXUP(fixup_p720t) MAPIO(p720t_map_io) INITIRQ(clps711x_init_irq) + INITTIME(clps711x_init_time) MACHINE_END static int p720t_hw_init(void) diff --git a/arch/arm/mach-clps711x/time.c b/arch/arm/mach-clps711x/time.c index 8a02e18a899a..9c732d18ddc0 100644 --- a/arch/arm/mach-clps711x/time.c +++ b/arch/arm/mach-clps711x/time.c @@ -18,12 +18,17 @@ */ #include #include +#include +#include #include +#include +#include #include #include -extern unsigned long (*gettimeoffset)(void); +#include + /* * gettimeoffset() returns time since last timer tick, in usecs. @@ -38,19 +43,38 @@ static unsigned long clps711x_gettimeoffset(void) return (hwticks * (tick_nsec / 1000)) / LATCH; } -void __init clps711x_setup_timer(void) +/* + * IRQ handler for the timer + */ +static irqreturn_t +p720t_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + do_leds(); + do_timer(regs); + do_profile(regs); + return IRQ_HANDLED; +} + +static struct irqaction clps711x_timer_irq = { + .name = "CLPS711x Timer Tick", + .flags = SA_INTERRUPT, + .handler = p720t_timer_interrupt +}; + +void __init clps711x_init_time(void) { struct timespec tv; unsigned int syscon; - gettimeoffset = clps711x_gettimeoffset; - syscon = clps_readl(SYSCON1); syscon |= SYSCON1_TC2S | SYSCON1_TC2M; clps_writel(syscon, SYSCON1); clps_writel(LATCH-1, TC2D); /* 512kHz / 100Hz - 1 */ + setup_irq(IRQ_TC2OI, &clps711x_timer_irq); + gettimeoffset = clps711x_gettimeoffset; + tv.tv_nsec = 0; tv.tv_sec = clps_readl(RTCDR); do_settimeofday(&tv); diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c index 628264bf50bc..2214f739768a 100644 --- a/arch/arm/mach-clps7500/core.c +++ b/arch/arm/mach-clps7500/core.c @@ -10,12 +10,13 @@ #include #include #include -#include +#include #include #include #include #include +#include #include #include @@ -265,10 +266,48 @@ static void __init clps7500_map_io(void) iotable_init(cl7500_io_desc, ARRAY_SIZE(cl7500_io_desc)); } +extern void ioctime_init(void); + +static irqreturn_t +clps7500_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + do_timer(regs); + do_set_rtc(); + do_profile(regs); + + { + /* Twinkle the lights. */ + static int count, state = 0xff00; + if (count-- == 0) { + state ^= 0x100; + count = 25; + *((volatile unsigned int *)LED_ADDRESS) = state; + } + } + return IRQ_HANDLED; +} + +static struct irqaction clps7500_timer_irq = { + .name = "CLPS7500 Timer Tick", + .flags = SA_INTERRUPT, + .handler = clps7500_timer_interrupt +}; + +/* + * Set up timer interrupt. + */ +void __init clps7500_init_time(void) +{ + ioctime_init(); + + setup_irq(IRQ_TIMER, &clps7500_timer_irq); +} + MACHINE_START(CLPS7500, "CL-PS7500") MAINTAINER("Philip Blundell") BOOT_MEM(0x10000000, 0x03000000, 0xe0000000) MAPIO(clps7500_map_io) INITIRQ(clps7500_init_irq) + INITTIME(clps7500_init_time) MACHINE_END diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c index 5c14e04eae1b..eddce7348095 100644 --- a/arch/arm/mach-ebsa110/core.c +++ b/arch/arm/mach-ebsa110/core.c @@ -26,6 +26,8 @@ #include #include +#include + #define IRQ_MASK 0xfe000000 /* read */ #define IRQ_MSET 0xfe000000 /* write */ #define IRQ_STAT 0xff000000 /* read */ @@ -89,6 +91,105 @@ static void __init ebsa110_map_io(void) iotable_init(ebsa110_io_desc, ARRAY_SIZE(ebsa110_io_desc)); } + +#define PIT_CTRL (PIT_BASE + 0x0d) +#define PIT_T2 (PIT_BASE + 0x09) +#define PIT_T1 (PIT_BASE + 0x05) +#define PIT_T0 (PIT_BASE + 0x01) + +/* + * This is the rate at which your MCLK signal toggles (in Hz) + * This was measured on a 10 digit frequency counter sampling + * over 1 second. + */ +#define MCLK 47894000 + +/* + * This is the rate at which the PIT timers get clocked + */ +#define CLKBY7 (MCLK / 7) + +/* + * This is the counter value. We tick at 200Hz on this platform. + */ +#define COUNT ((CLKBY7 + (HZ / 2)) / HZ) + +/* + * Get the time offset from the system PIT. Note that if we have missed an + * interrupt, then the PIT counter will roll over (ie, be negative). + * This actually works out to be convenient. + */ +static unsigned long ebsa110_gettimeoffset(void) +{ + unsigned long offset, count; + + __raw_writeb(0x40, PIT_CTRL); + count = __raw_readb(PIT_T1); + count |= __raw_readb(PIT_T1) << 8; + + /* + * If count > COUNT, make the number negative. + */ + if (count > COUNT) + count |= 0xffff0000; + + offset = COUNT; + offset -= count; + + /* + * `offset' is in units of timer counts. Convert + * offset to units of microseconds. + */ + offset = offset * (1000000 / HZ) / COUNT; + + return offset; +} + +static irqreturn_t +ebsa110_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 count; + + /* latch and read timer 1 */ + __raw_writeb(0x40, PIT_CTRL); + count = __raw_readb(PIT_T1); + count |= __raw_readb(PIT_T1) << 8; + + count += COUNT; + + __raw_writeb(count & 0xff, PIT_T1); + __raw_writeb(count >> 8, PIT_T1); + + do_leds(); + do_timer(regs); + do_profile(regs); + + return IRQ_HANDLED; +} + +static struct irqaction ebsa110_timer_irq = { + .name = "EBSA110 Timer Tick", + .flags = SA_INTERRUPT, + .handler = ebsa110_timer_interrupt +}; + +/* + * Set up timer interrupt. + */ +void __init ebsa110_time_init(void) +{ + /* + * Timer 1, mode 2, LSB/MSB + */ + __raw_writeb(0x70, PIT_CTRL); + __raw_writeb(COUNT & 0xff, PIT_T1); + __raw_writeb(COUNT >> 8, PIT_T1); + + gettimeoffset = ebsa110_gettimeoffset; + + setup_irq(IRQ_EBSA110_TIMER0, &ebsa110_timer_irq); +} + MACHINE_START(EBSA110, "EBSA110") MAINTAINER("Russell King") BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000) @@ -98,4 +199,5 @@ MACHINE_START(EBSA110, "EBSA110") SOFT_REBOOT MAPIO(ebsa110_map_io) INITIRQ(ebsa110_init_irq) + INITTIME(ebsa110_init_time) MACHINE_END diff --git a/arch/arm/mach-ebsa110/time.c b/arch/arm/mach-ebsa110/time.c new file mode 100644 index 000000000000..c482e372b012 --- /dev/null +++ b/arch/arm/mach-ebsa110/time.c @@ -0,0 +1,118 @@ +/* + * linux/include/asm-arm/arch-ebsa110/time.h + * + * Copyright (C) 1996,1997,1998 Russell King. + * + * This program 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. + * + * No real time clock on the evalulation board! + * + * Changelog: + * 10-Oct-1996 RMK Created + * 04-Dec-1997 RMK Updated for new arch/arm/kernel/time.c + * 07-Aug-1998 RMK Updated for arch/arm/kernel/leds.c + * 28-Dec-1998 APH Made leds code optional + */ + +#include +#include + +extern unsigned long (*gettimeoffset)(void); + +#define PIT_CTRL (PIT_BASE + 0x0d) +#define PIT_T2 (PIT_BASE + 0x09) +#define PIT_T1 (PIT_BASE + 0x05) +#define PIT_T0 (PIT_BASE + 0x01) + +/* + * This is the rate at which your MCLK signal toggles (in Hz) + * This was measured on a 10 digit frequency counter sampling + * over 1 second. + */ +#define MCLK 47894000 + +/* + * This is the rate at which the PIT timers get clocked + */ +#define CLKBY7 (MCLK / 7) + +/* + * This is the counter value. We tick at 200Hz on this platform. + */ +#define COUNT ((CLKBY7 + (HZ / 2)) / HZ) + +/* + * Get the time offset from the system PIT. Note that if we have missed an + * interrupt, then the PIT counter will roll over (ie, be negative). + * This actually works out to be convenient. + */ +static unsigned long ebsa110_gettimeoffset(void) +{ + unsigned long offset, count; + + __raw_writeb(0x40, PIT_CTRL); + count = __raw_readb(PIT_T1); + count |= __raw_readb(PIT_T1) << 8; + + /* + * If count > COUNT, make the number negative. + */ + if (count > COUNT) + count |= 0xffff0000; + + offset = COUNT; + offset -= count; + + /* + * `offset' is in units of timer counts. Convert + * offset to units of microseconds. + */ + offset = offset * (1000000 / HZ) / COUNT; + + return offset; +} + +static irqreturn_t +timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 count; + + /* latch and read timer 1 */ + __raw_writeb(0x40, PIT_CTRL); + count = __raw_readb(PIT_T1); + count |= __raw_readb(PIT_T1) << 8; + + count += COUNT; + + __raw_writeb(count & 0xff, PIT_T1); + __raw_writeb(count >> 8, PIT_T1); + + do_leds(); + do_timer(regs); + do_profile(regs); + + return IRQ_HANDLED; +} + +/* + * Set up timer interrupt. + */ +void __init time_init(void) +{ + /* + * Timer 1, mode 2, LSB/MSB + */ + __raw_writeb(0x70, PIT_CTRL); + __raw_writeb(COUNT & 0xff, PIT_T1); + __raw_writeb(COUNT >> 8, PIT_T1); + + gettimeoffset = ebsa110_gettimeoffset; + + timer_irq.handler = timer_interrupt; + + setup_irq(IRQ_EBSA110_TIMER0, &timer_irq); +} + + diff --git a/arch/arm/mach-epxa10db/arch.c b/arch/arm/mach-epxa10db/arch.c index 71c2257dfd50..ae9f7c864b45 100644 --- a/arch/arm/mach-epxa10db/arch.c +++ b/arch/arm/mach-epxa10db/arch.c @@ -29,10 +29,13 @@ extern void epxa10db_map_io(void); extern void epxa10db_init_irq(void); +extern void epxa10db_init_time(void); MACHINE_START(CAMELOT, "Altera Epxa10db") MAINTAINER("Altera Corporation") BOOT_MEM(0x00000000, 0x7fffc000, 0xffffc000) MAPIO(epxa10db_map_io) INITIRQ(epxa10db_init_irq) + INITTIME(epxa10db_init_time) MACHINE_END + diff --git a/arch/arm/mach-epxa10db/time.c b/arch/arm/mach-epxa10db/time.c index 0c8b9cf7c7b7..1b3766a46069 100644 --- a/arch/arm/mach-epxa10db/time.c +++ b/arch/arm/mach-epxa10db/time.c @@ -10,11 +10,17 @@ */ #include #include +#include +#include #include +#include +#include +#include -extern int (*set_rtc)(void); +#define TIMER00_TYPE (volatile unsigned int*) +#include static int epxa10db_set_rtc(void) { @@ -29,3 +35,41 @@ static int epxa10db_rtc_init(void) } __initcall(epxa10db_rtc_init); + + +/* + * IRQ handler for the timer + */ +static irqreturn_t +epxa10db_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + + // ...clear the interrupt + *TIMER0_CR(IO_ADDRESS(EXC_TIMER00_BASE))|=TIMER0_CR_CI_MSK; + + do_leds(); + do_timer(regs); + do_profile(regs); + + return IRQ_HANDLED; +} + +static struct irqaction epxa10db_timer_irq = { + .name = "Excalibur Timer Tick", + .flags = SA_INTERRUPT, + .handler = epxa10db_timer_interrupt +}; + +/* + * Set up timer interrupt, and return the current time in seconds. + */ +void __init epxa10db_init_time(void) +{ + /* Start the timer */ + *TIMER0_LIMIT(IO_ADDRESS(EXC_TIMER00_BASE))=(unsigned int)(EXC_AHB2_CLK_FREQUENCY/200); + *TIMER0_PRESCALE(IO_ADDRESS(EXC_TIMER00_BASE))=1; + *TIMER0_CR(IO_ADDRESS(EXC_TIMER00_BASE))=TIMER0_CR_IE_MSK | TIMER0_CR_S_MSK; + + setup_irq(IRQ_TIMER0, &epxa10db_timer_irq); +} + diff --git a/arch/arm/mach-footbridge/Makefile b/arch/arm/mach-footbridge/Makefile index d011b2df2dbe..e0a2890522cd 100644 --- a/arch/arm/mach-footbridge/Makefile +++ b/arch/arm/mach-footbridge/Makefile @@ -4,7 +4,7 @@ # Object file lists. -obj-y := arch.o dc21285.o dma.o irq.o isa-irq.o mm.o +obj-y := arch.o dc21285.o dma.o irq.o isa-irq.o mm.o time.o obj-m := obj-n := obj- := diff --git a/arch/arm/mach-footbridge/arch.c b/arch/arm/mach-footbridge/arch.c index 91e34a8440ef..76119883661e 100644 --- a/arch/arm/mach-footbridge/arch.c +++ b/arch/arm/mach-footbridge/arch.c @@ -22,6 +22,7 @@ extern void footbridge_map_io(void); extern void footbridge_init_irq(void); +extern void footbridge_init_time(void); unsigned int mem_fclk_21285 = 50000000; @@ -43,6 +44,7 @@ MACHINE_START(EBSA285, "EBSA285") VIDEO(0x000a0000, 0x000bffff) MAPIO(footbridge_map_io) INITIRQ(footbridge_init_irq) + INITTIME(footbridge_init_time) MACHINE_END #endif @@ -78,6 +80,7 @@ MACHINE_START(NETWINDER, "Rebel-NetWinder") FIXUP(fixup_netwinder) MAPIO(footbridge_map_io) INITIRQ(footbridge_init_irq) + INITTIME(footbridge_init_time) MACHINE_END #endif @@ -103,6 +106,7 @@ MACHINE_START(CATS, "Chalice-CATS") FIXUP(fixup_cats) MAPIO(footbridge_map_io) INITIRQ(footbridge_init_irq) + INITTIME(footbridge_init_time) MACHINE_END #endif @@ -129,6 +133,7 @@ MACHINE_START(CO285, "co-EBSA285") FIXUP(fixup_coebsa285) MAPIO(footbridge_map_io) INITIRQ(footbridge_init_irq) + INITTIME(footbridge_init_time) MACHINE_END #endif @@ -139,5 +144,6 @@ MACHINE_START(PERSONAL_SERVER, "Compaq-PersonalServer") BOOT_PARAMS(0x00000100) MAPIO(footbridge_map_io) INITIRQ(footbridge_init_irq) + INITTIME(footbridge_init_time) MACHINE_END #endif diff --git a/arch/arm/mach-footbridge/time.c b/arch/arm/mach-footbridge/time.c new file mode 100644 index 000000000000..c32dd9a5c9b9 --- /dev/null +++ b/arch/arm/mach-footbridge/time.c @@ -0,0 +1,305 @@ +/* + * linux/include/asm-arm/arch-ebsa285/time.h + * + * Copyright (C) 1998 Russell King. + * Copyright (C) 1998 Phil Blundell + * + * CATS has a real-time clock, though the evaluation board doesn't. + * + * Changelog: + * 21-Mar-1998 RMK Created + * 27-Aug-1998 PJB CATS support + * 28-Dec-1998 APH Made leds optional + * 20-Jan-1999 RMK Started merge of EBSA285, CATS and NetWinder + * 16-Mar-1999 RMK More support for EBSA285-like machines with RTCs in + */ + +#define RTC_PORT(x) (rtc_base+(x)) +#define RTC_ALWAYS_BCD 0 + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +static int rtc_base; + +#define mSEC_10_from_14 ((14318180 + 100) / 200) + +static unsigned long isa_gettimeoffset(void) +{ + int count; + + static int count_p = (mSEC_10_from_14/6); /* for the first call after boot */ + static unsigned long jiffies_p = 0; + + /* + * cache volatile jiffies temporarily; we have IRQs turned off. + */ + unsigned long jiffies_t; + + /* timer count may underflow right here */ + outb_p(0x00, 0x43); /* latch the count ASAP */ + + count = inb_p(0x40); /* read the latched count */ + + /* + * We do this guaranteed double memory access instead of a _p + * postfix in the previous port access. Wheee, hackady hack + */ + jiffies_t = jiffies; + + count |= inb_p(0x40) << 8; + + /* Detect timer underflows. If we haven't had a timer tick since + the last time we were called, and time is apparently going + backwards, the counter must have wrapped during this routine. */ + if ((jiffies_t == jiffies_p) && (count > count_p)) + count -= (mSEC_10_from_14/6); + else + jiffies_p = jiffies_t; + + count_p = count; + + count = (((mSEC_10_from_14/6)-1) - count) * (tick_nsec / 1000); + count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6); + + return count; +} + +static irqreturn_t +isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + if (machine_is_netwinder()) + do_leds(); + + do_timer(regs); + do_set_rtc(); + do_profile(regs); + + return IRQ_HANDLED; +} + +static unsigned long __init get_isa_cmos_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + int i; + + // check to see if the RTC makes sense..... + if ((CMOS_READ(RTC_VALID) & RTC_VRT) == 0) + return mktime(1970, 1, 1, 0, 0, 0); + + /* The Linux interpretation of the CMOS clock register contents: + * When the Update-In-Progress (UIP) flag goes from 1 to 0, the + * RTC registers show the second which has precisely just started. + * Let's hope other operating systems interpret the RTC the same way. + */ + /* read RTC exactly on falling edge of update flag */ + for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ + if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) + break; + + for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ + if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) + break; + + do { /* Isn't this overkill ? UIP above should guarantee consistency */ + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + } while (sec != CMOS_READ(RTC_SECONDS)); + + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } + if ((year += 1900) < 1970) + year += 100; + return mktime(year, mon, day, hour, min, sec); +} + +static int +set_isa_cmos_time(void) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + unsigned char save_control, save_freq_select; + unsigned long nowtime = xtime.tv_sec; + + save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + cmos_minutes = CMOS_READ(RTC_MINUTES); + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + BCD_TO_BIN(cmos_minutes); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + } + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else + retval = -1; + + /* The following flags have to be released exactly in this order, + * otherwise the DS12887 (popular MC146818A clone with integrated + * battery and quartz) will not reset the oscillator and will not + * update precisely 500 ms later. You won't find this mentioned in + * the Dallas Semiconductor data sheets, but who believes data + * sheets anyway ... -- Markus Kuhn + */ + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + + return retval; +} + + +static unsigned long timer1_latch; + +static unsigned long timer1_gettimeoffset (void) +{ + unsigned long value = timer1_latch - *CSR_TIMER1_VALUE; + + return ((tick_nsec / 1000) * value) / timer1_latch; +} + +static irqreturn_t +timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + *CSR_TIMER1_CLR = 0; + + /* Do the LEDs things */ + do_leds(); + do_timer(regs); + do_set_rtc(); + do_profile(regs); + + return IRQ_HANDLED; +} + +static struct irqaction footbridge_timer_irq = { + .flags = SA_INTERRUPT +}; + +/* + * Set up timer interrupt. + */ +void __init footbridge_init_time(void) +{ + if (machine_is_co285() || + machine_is_personal_server()) + /* + * Add-in 21285s shouldn't access the RTC + */ + rtc_base = 0; + else + rtc_base = 0x70; + + if (rtc_base) { + int reg_d, reg_b; + + /* + * Probe for the RTC. + */ + reg_d = CMOS_READ(RTC_REG_D); + + /* + * make sure the divider is set + */ + CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_REG_A); + + /* + * Set control reg B + * (24 hour mode, update enabled) + */ + reg_b = CMOS_READ(RTC_REG_B) & 0x7f; + reg_b |= 2; + CMOS_WRITE(reg_b, RTC_REG_B); + + if ((CMOS_READ(RTC_REG_A) & 0x7f) == RTC_REF_CLCK_32KHZ && + CMOS_READ(RTC_REG_B) == reg_b) { + struct timespec tv; + + /* + * We have a RTC. Check the battery + */ + if ((reg_d & 0x80) == 0) + printk(KERN_WARNING "RTC: *** warning: CMOS battery bad\n"); + + tv.tv_nsec = 0; + tv.tv_sec = get_isa_cmos_time(); + do_settimeofday(&tv); + set_rtc = set_isa_cmos_time; + } else + rtc_base = 0; + } + + if (machine_is_ebsa285() || + machine_is_co285() || + machine_is_personal_server()) { + gettimeoffset = timer1_gettimeoffset; + + timer1_latch = (mem_fclk_21285 + 8 * HZ) / (16 * HZ); + + *CSR_TIMER1_CLR = 0; + *CSR_TIMER1_LOAD = timer1_latch; + *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16; + + footbridge_timer_irq.name = "Timer1 Timer Tick"; + footbrdige_timer_irq.handler = timer1_interrupt; + + setup_irq(IRQ_TIMER1, &footbridge_timer_irq); + + } else { + /* enable PIT timer */ + /* set for periodic (4) and LSB/MSB write (0x30) */ + outb(0x34, 0x43); + outb((mSEC_10_from_14/6) & 0xFF, 0x40); + outb((mSEC_10_from_14/6) >> 8, 0x40); + + gettimeoffset = isa_gettimeoffset; + + footbridge_timer_irq.name = "ISA Timer Tick"; + footbrdige_timer_irq.handler = isa_timer_interrupt; + + setup_irq(IRQ_ISA, &footbridge_timer_irq); + } +} diff --git a/arch/arm/mach-ftvpci/core.c b/arch/arm/mach-ftvpci/core.c index ea6d5c34e87f..67d936260d03 100644 --- a/arch/arm/mach-ftvpci/core.c +++ b/arch/arm/mach-ftvpci/core.c @@ -88,6 +88,53 @@ static void __init ftvpci_map_io(void) iotable_init(ftvpci_io_desc, ARRAY_SIZE(ftvpci_io_desc)); } +static irqreturn_t +ftvpci_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + static int count = 25; + unsigned char stat = __raw_readb(DUART_BASE + 0x14); + if (!(stat & 0x10)) + return; /* Not for us */ + + /* Reset counter */ + __raw_writeb(0x90, DUART_BASE + 8); + + if (--count == 0) { + static int state = 1; + state ^= 1; + __raw_writeb(0x1a + state, INTCONT_BASE); + __raw_writeb(0x18 + state, INTCONT_BASE); + count = 50; + } + + /* Wait for slow rise time */ + __raw_readb(DUART_BASE + 0x14); + __raw_readb(DUART_BASE + 0x14); + __raw_readb(DUART_BASE + 0x14); + __raw_readb(DUART_BASE + 0x14); + __raw_readb(DUART_BASE + 0x14); + __raw_readb(DUART_BASE + 0x14); + + do_timer(regs); + + return IRQ_HANDLED; +} + +void __init ftvpci_time_init(void) +{ + int tick = 3686400 / 16 / 2 / 100; + + __raw_writeb(tick & 0xff, DUART_BASE + 0x1c); + __raw_writeb(tick >> 8, DUART_BASE + 0x18); + __raw_writeb(0x80, DUART_BASE + 8); + __raw_writeb(0x10, DUART_BASE + 0x14); + + timer_irq.handler = timer_interrupt; + timer_irq.flags = SA_SHIRQ; + + set_timer_irq_handler(IRQ_TIMER, timer_interrupt); +} + MACHINE_START(NEXUSPCI, "FTV/PCI") MAINTAINER("Philip Blundell") BOOT_MEM(0x40000000, 0x10000000, 0xe0000000) diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 1d59766652d3..4fee881855f1 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -281,11 +281,17 @@ static void __init ap_init(void) } } +static void ap_time_init(void) +{ + integrator_time_init(1000000 * TICKS_PER_uSEC / HZ, 0); +} + MACHINE_START(INTEGRATOR, "ARM-Integrator") MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd") BOOT_MEM(0x00000000, 0x16000000, 0xf1600000) BOOT_PARAMS(0x00000100) MAPIO(ap_map_io) INITIRQ(ap_init_irq) + INITTIME(ap_time_init) INIT_MACHINE(ap_init) MACHINE_END diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 751941059c14..d64522d10110 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -357,11 +357,17 @@ static void __init intcp_init(void) } } +static void __init intcp_init_time(void) +{ + integrator_time_init(1000000 / HZ, TIMER_CTRL_IE); +} + MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP") MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd") BOOT_MEM(0x00000000, 0x16000000, 0xf1600000) BOOT_PARAMS(0x00000100) MAPIO(intcp_map_io) INITIRQ(intcp_init_irq) + INITTIME(intcp_init_time) INIT_MACHINE(intcp_init) MACHINE_END diff --git a/arch/arm/mach-integrator/time.c b/arch/arm/mach-integrator/time.c index 39606096fbd6..d791f1e41896 100644 --- a/arch/arm/mach-integrator/time.c +++ b/arch/arm/mach-integrator/time.c @@ -10,9 +10,16 @@ #include #include #include +#include +#include #include #include +#include +#include +#include + +#include #define RTC_DR (IO_ADDRESS(INTEGRATOR_RTC_BASE) + 0) #define RTC_MR (IO_ADDRESS(INTEGRATOR_RTC_BASE) + 4) @@ -44,3 +51,142 @@ static int integrator_rtc_init(void) } __initcall(integrator_rtc_init); + + +/* + * Where is the timer (VA)? + */ +#define TIMER0_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000000) +#define TIMER1_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000100) +#define TIMER2_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000200) +#define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) + +/* + * How long is the timer interval? + */ +#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) +#if TIMER_INTERVAL >= 0x100000 +#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) +#elif TIMER_INTERVAL >= 0x10000 +#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) +#else +#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) +#endif + +#define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable */ + +/* + * What does it look like? + */ +typedef struct TimerStruct { + unsigned long TimerLoad; + unsigned long TimerValue; + unsigned long TimerControl; + unsigned long TimerClear; +} TimerStruct_t; + +extern unsigned long (*gettimeoffset)(void); + +static unsigned long timer_reload; + +/* + * Returns number of ms since last clock interrupt. Note that interrupts + * will have been disabled by do_gettimeoffset() + */ +static unsigned long integrator_gettimeoffset(void) +{ + volatile TimerStruct_t *timer1 = (TimerStruct_t *)TIMER1_VA_BASE; + unsigned long ticks1, ticks2, status; + + /* + * Get the current number of ticks. Note that there is a race + * condition between us reading the timer and checking for + * an interrupt. We get around this by ensuring that the + * counter has not reloaded between our two reads. + */ + ticks2 = timer1->TimerValue & 0xffff; + do { + ticks1 = ticks2; + status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS); + ticks2 = timer1->TimerValue & 0xffff; + } while (ticks2 > ticks1); + + /* + * Number of ticks since last interrupt. + */ + ticks1 = timer_reload - ticks2; + + /* + * Interrupt pending? If so, we've reloaded once already. + */ + if (status & (1 << IRQ_TIMERINT1)) + ticks1 += timer_reload; + + /* + * Convert the ticks to usecs + */ + return TICKS2USECS(ticks1); +} + +/* + * IRQ handler for the timer + */ +static irqreturn_t +integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE; + + // ...clear the interrupt + timer1->TimerClear = 1; + + do_leds(); + do_timer(regs); + do_profile(regs); + + return IRQ_HANDLED; +} + +static struct irqaction integrator_timer_irq = { + .name = "Integrator Timer Tick", + .flags = SA_INTERRUPT, + .handler = integrator_timer_interrupt +}; + +/* + * Set up timer interrupt, and return the current time in seconds. + */ +void __init integrator_time_init(unsigned long reload, unsigned int ctrl) +{ + volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; + volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE; + volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE; + unsigned int timer_ctrl = 0x80 | 0x40; /* periodic */ + + timer_reload = reload; + timer_ctrl |= ctrl; + + if (timer_reload > 0x100000) { + timer_reload >>= 8; + timer_ctrl |= 0x08; /* /256 */ + } else if (timer_reload > 0x010000) { + timer_reload >>= 4; + timer_ctrl |= 0x04; /* /16 */ + } + + /* + * Initialise to a known state (all timers off) + */ + timer0->TimerControl = 0; + timer1->TimerControl = 0; + timer2->TimerControl = 0; + + timer1->TimerLoad = timer_reload; + timer1->TimerValue = timer_reload; + timer1->TimerControl = timer_ctrl; + + /* + * Make irqs happen for the system timer + */ + setup_irq(IRQ_TIMERINT1, &integrator_timer_irq); + gettimeoffset = integrator_gettimeoffset; +} diff --git a/arch/arm/mach-iop3xx/arch.c b/arch/arm/mach-iop3xx/arch.c index eb3bab2db9c4..3df5e454c772 100644 --- a/arch/arm/mach-iop3xx/arch.c +++ b/arch/arm/mach-iop3xx/arch.c @@ -29,6 +29,7 @@ extern void iq80310_init_irq(void); #ifdef CONFIG_ARCH_IQ80321 extern void iq80321_map_io(void); extern void iop321_init_irq(void); +extern void iop321_init_time(void); #endif #ifdef CONFIG_ARCH_IQ80310 @@ -67,6 +68,7 @@ MACHINE_START(IQ80321, "Intel IQ80321") FIXUP(fixup_iop321) MAPIO(iq80321_map_io) INITIRQ(iop321_init_irq) + INITTIME(iop321_init_time) MACHINE_END #else diff --git a/arch/arm/mach-iop3xx/iop321-time.c b/arch/arm/mach-iop3xx/iop321-time.c index a10a9b9533d1..3af8823cda37 100644 --- a/arch/arm/mach-iop3xx/iop321-time.c +++ b/arch/arm/mach-iop3xx/iop321-time.c @@ -23,7 +23,9 @@ #include #include #include + #include +#include static unsigned long iop321_gettimeoffset(void) { @@ -66,22 +68,21 @@ iop321_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -extern unsigned long (*gettimeoffset)(void); - -static struct irqaction timer_irq = { - .name = "timer", +static struct irqaction iop321_timer_irq = { + .name = "IOP321 Timer Tick", .handler = iop321_timer_interrupt, + .flags = SA_INTERRUPT }; extern int setup_arm_irq(int, struct irqaction*); -void __init time_init(void) +void __init iop321_init_time(void) { u32 timer_ctl; u32 latch = LATCH; gettimeoffset = iop321_gettimeoffset; - setup_irq(IRQ_IOP321_TIMER0, &timer_irq); + setup_irq(IRQ_IOP321_TIMER0, &iop321_timer_irq); timer_ctl = IOP321_TMR_EN | IOP321_TMR_PRIVILEGED | IOP321_TMR_RELOAD | IOP321_TMR_RATIO_1_1; diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index f0166508d5bb..986f2d43db28 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -36,6 +36,7 @@ #include #include +#include /************************************************************************* @@ -234,17 +235,15 @@ static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id, struct pt_regs return IRQ_HANDLED; } -extern unsigned long (*gettimeoffset)(void); - -static struct irqaction timer_irq = { - .name = "IXP4xx Timer Tick", - .flags = SA_INTERRUPT +static struct irqaction ixp4xx_timer_irq = { + .name = "IXP4xx Timer Tick", + .flags = SA_INTERRUPT, + .handler = ixp4xx_timer_interrupt }; -void __init time_init(void) +void __init ixp4xx_init_time(void) { gettimeoffset = ixp4xx_gettimeoffset; - timer_irq.handler = ixp4xx_timer_interrupt; /* Clear Pending Interrupt by writing '1' to it */ *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND; @@ -257,7 +256,7 @@ void __init time_init(void) last_jiffy_time = 0; /* Connect the interrupt handler and enable the interrupt */ - setup_irq(IRQ_IXP4XX_TIMER1, &timer_irq); + setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq); } diff --git a/arch/arm/mach-ixp4xx/coyote-setup.c b/arch/arm/mach-ixp4xx/coyote-setup.c index bc6e0d0427a2..3d616bc6aff4 100644 --- a/arch/arm/mach-ixp4xx/coyote-setup.c +++ b/arch/arm/mach-ixp4xx/coyote-setup.c @@ -84,6 +84,7 @@ MACHINE_START(ADI_COYOTE, "ADI Engineering IXP4XX Coyote Development Platform") IXP4XX_PERIPHERAL_BASE_VIRT) MAPIO(coyote_map_io) INITIRQ(ixp4xx_init_irq) + INITTIME(ixp4xx_init_time) BOOT_PARAMS(0x0100) INIT_MACHINE(coyote_init) MACHINE_END diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c index 160117c67764..ec289c866ae7 100644 --- a/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -113,6 +113,7 @@ MACHINE_START(IXDP425, "Intel IXDP425 Development Platform") IXP4XX_PERIPHERAL_BASE_VIRT) MAPIO(ixdp425_map_io) INITIRQ(ixp4xx_init_irq) + INITTIME(ixp4xx_init_time) BOOT_PARAMS(0x0100) INIT_MACHINE(ixdp425_init) MACHINE_END @@ -123,6 +124,7 @@ MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform") IXP4XX_PERIPHERAL_BASE_VIRT) MAPIO(ixdp425_map_io) INITIRQ(ixp4xx_init_irq) + INITTIME(ixp4xx_init_time) BOOT_PARAMS(0x0100) INIT_MACHINE(ixdp425_init) MACHINE_END @@ -140,6 +142,7 @@ MACHINE_START(AVILA, "Gateworks Avila Network Platform") IXP4XX_PERIPHERAL_BASE_VIRT) MAPIO(ixdp425_map_io) INITIRQ(ixp4xx_init_irq) + INITTIME(ixp4xx_init_time) BOOT_PARAMS(0x0100) INIT_MACHINE(ixdp425_init) MACHINE_END diff --git a/arch/arm/mach-ixp4xx/prpmc1100-setup.c b/arch/arm/mach-ixp4xx/prpmc1100-setup.c index b0603205d070..ee092b1771cc 100644 --- a/arch/arm/mach-ixp4xx/prpmc1100-setup.c +++ b/arch/arm/mach-ixp4xx/prpmc1100-setup.c @@ -84,6 +84,7 @@ MACHINE_START(PRPMC1100, "Motorola PrPMC1100") IXP4XX_PERIPHERAL_BASE_VIRT) MAPIO(prpmc1100_map_io) INITIRQ(ixp4xx_init_irq) + INITTIME(ixp4xx_init_time) BOOT_PARAMS(0x0100) INIT_MACHINE(prpmc1100_init) MACHINE_END diff --git a/arch/arm/mach-lh7a40x/Makefile b/arch/arm/mach-lh7a40x/Makefile index db3be5a23a8a..6b361f788a22 100644 --- a/arch/arm/mach-lh7a40x/Makefile +++ b/arch/arm/mach-lh7a40x/Makefile @@ -4,7 +4,7 @@ # Object file lists. -obj-y := fiq.o +obj-y := fiq.o time.o # generic.o obj-$(CONFIG_MACH_KEV7A400) += arch-kev7a400.o irq-lh7a400.o obj-$(CONFIG_MACH_LPD7A400) += arch-lpd7a40x.o ide-lpd7a40x.o irq-lh7a400.o diff --git a/arch/arm/mach-lh7a40x/arch-kev7a400.c b/arch/arm/mach-lh7a40x/arch-kev7a400.c index 73d8b6b56e4c..6fa2a981ee80 100644 --- a/arch/arm/mach-lh7a40x/arch-kev7a400.c +++ b/arch/arm/mach-lh7a40x/arch-kev7a400.c @@ -25,6 +25,7 @@ /* This function calls the board specific IRQ initialization function. */ extern void lh7a400_init_irq (void); +extern void lh7a40x_init_time (void); static struct map_desc kev7a400_io_desc[] __initdata = { { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE }, @@ -108,4 +109,5 @@ MACHINE_START (KEV7A400, "Sharp KEV7a400") BOOT_PARAMS (0xc0000100) MAPIO (kev7a400_map_io) INITIRQ (lh7a400_init_irq) + INITTIME (lh7a40x_init_time) MACHINE_END diff --git a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c index 75dba98360c0..33eb4b8dd358 100644 --- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c +++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c @@ -280,6 +280,7 @@ MACHINE_END #ifdef CONFIG_MACH_LPD7A404 extern void lh7a404_init_irq (void); +extern void lh7a40x_init_time (void); MACHINE_START (LPD7A404, "Logic Product Development LPD7A404-10") MAINTAINER ("Marc Singer") @@ -287,6 +288,7 @@ MACHINE_START (LPD7A404, "Logic Product Development LPD7A404-10") BOOT_PARAMS (0xc0000100) MAPIO (lpd7a400_map_io) INITIRQ (lh7a404_init_irq) + INITTIME (lh7a40x_init_time) INIT_MACHINE (lpd7a40x_init) MACHINE_END diff --git a/arch/arm/mach-lh7a40x/time.c b/arch/arm/mach-lh7a40x/time.c new file mode 100644 index 000000000000..52c20c3bf248 --- /dev/null +++ b/arch/arm/mach-lh7a40x/time.c @@ -0,0 +1,70 @@ +/* + * arch/arm/mach-lh7a40x/time.c + * + * Copyright (C) 2004 Logic Product Development + * + * This program 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. + * + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#if HZ < 100 +# define TIMER_CONTROL TIMER_CONTROL1 +# define TIMER_LOAD TIMER_LOAD1 +# define TIMER_CONSTANT (508469/HZ) +# define TIMER_MODE (TIMER_C_ENABLE | TIMER_C_PERIODIC | TIMER_C_508KHZ) +# define TIMER_EOI TIMER_EOI1 +# define TIMER_IRQ IRQ_T1UI +#else +# define TIMER_CONTROL TIMER_CONTROL3 +# define TIMER_LOAD TIMER_LOAD3 +# define TIMER_CONSTANT (3686400/HZ) +# define TIMER_MODE (TIMER_C_ENABLE | TIMER_C_PERIODIC) +# define TIMER_EOI TIMER_EOI3 +# define TIMER_IRQ IRQ_T3UI +#endif + +static irqreturn_t +lh7a40x_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + TIMER_EOI = 0; + do_profile (regs); + do_leds(); + do_set_rtc(); + do_timer (regs); + + return IRQ_HANDLED; +} + +static struct irqaction lh7a40x_timer_irq = { + .name = "LHA740x Timer Tick", + .flags = SA_INTERRUPT, + .handler = lh7a40x_timer_interrupt +}; + +void __init lh7a40x_init_time(void) +{ + /* Stop/disable all timers */ + TIMER_CONTROL1 = 0; + TIMER_CONTROL2 = 0; + TIMER_CONTROL3 = 0; + + setup_irq (TIMER_IRQ, &lh7a40x_timer_irq); + + TIMER_LOAD = TIMER_CONSTANT; + TIMER_CONTROL = TIMER_MODE; +} + diff --git a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile index 272535091bc4..5fcb1e5c7627 100644 --- a/arch/arm/mach-omap/Makefile +++ b/arch/arm/mach-omap/Makefile @@ -3,7 +3,7 @@ # # Common support -obj-y := common.o irq.o dma.o clocks.o mux.o bus.o gpio.o +obj-y := common.o irq.o dma.o clocks.o mux.o bus.o gpio.o time.o obj-m := obj-n := obj- := diff --git a/arch/arm/mach-omap/board-generic.c b/arch/arm/mach-omap/board-generic.c index bf739b5df465..25648f58daca 100644 --- a/arch/arm/mach-omap/board-generic.c +++ b/arch/arm/mach-omap/board-generic.c @@ -64,6 +64,11 @@ static void __init omap_generic_map_io(void) omap_map_io(); } +static void __init omap_generic_init_time(void) +{ + omap_init_time(); +} + MACHINE_START(OMAP_GENERIC, "Generic OMAP-1510/1610") MAINTAINER("Tony Lindgren ") BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000) @@ -71,4 +76,6 @@ MACHINE_START(OMAP_GENERIC, "Generic OMAP-1510/1610") MAPIO(omap_generic_map_io) INITIRQ(omap_generic_init_irq) INIT_MACHINE(omap_generic_init) + INITTIME(omap_generic_init_time) MACHINE_END + diff --git a/arch/arm/mach-omap/board-innovator.c b/arch/arm/mach-omap/board-innovator.c index c118801230bf..900466430524 100644 --- a/arch/arm/mach-omap/board-innovator.c +++ b/arch/arm/mach-omap/board-innovator.c @@ -153,5 +153,6 @@ MACHINE_START(OMAP_INNOVATOR, "TI-Innovator") BOOT_PARAMS(0x10000100) MAPIO(innovator_map_io) INITIRQ(innovator_init_irq) + INITTIME(omap_init_time) INIT_MACHINE(innovator_init) MACHINE_END diff --git a/arch/arm/mach-omap/board-osk.c b/arch/arm/mach-omap/board-osk.c index 521683496e73..268c4603c291 100644 --- a/arch/arm/mach-omap/board-osk.c +++ b/arch/arm/mach-omap/board-osk.c @@ -93,5 +93,6 @@ MACHINE_START(OMAP_OSK, "TI-OSK") BOOT_PARAMS(0x10000100) MAPIO(osk_map_io) INITIRQ(osk_init_irq) + INITTIME(omap_init_time) INIT_MACHINE(osk_init) MACHINE_END diff --git a/arch/arm/mach-omap/board-perseus2.c b/arch/arm/mach-omap/board-perseus2.c index 3843d6a6d4f2..78773f038297 100644 --- a/arch/arm/mach-omap/board-perseus2.c +++ b/arch/arm/mach-omap/board-perseus2.c @@ -107,5 +107,6 @@ MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2") BOOT_PARAMS(0x10000100) MAPIO(omap_perseus2_map_io) INITIRQ(omap_perseus2_init_irq) + INITTIME(omap_init_time) INIT_MACHINE(omap_perseus2_init) MACHINE_END diff --git a/arch/arm/mach-omap/common.h b/arch/arm/mach-omap/common.h index 1cc559dd2f81..96dcb3c53973 100644 --- a/arch/arm/mach-omap/common.h +++ b/arch/arm/mach-omap/common.h @@ -28,6 +28,7 @@ #define __ARCH_ARM_MACH_OMAP_COMMON_H extern void omap_map_io(void); +extern void omap_init_time(void); #endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */ diff --git a/arch/arm/mach-omap/time.c b/arch/arm/mach-omap/time.c new file mode 100644 index 000000000000..35548f1004b1 --- /dev/null +++ b/arch/arm/mach-omap/time.c @@ -0,0 +1,214 @@ +/* + * arch/arm/mach-omap/time.c + * + * OMAP Timer Tick + * + * Copyright (C) 2000 RidgeRun, Inc. + * Author: Greg Lonnon + * + * 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; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __instrument +#define __instrument +#define __noinstrument __attribute__ ((no_instrument_function)) +#endif + +typedef struct { + u32 cntl; /* CNTL_TIMER, R/W */ + u32 load_tim; /* LOAD_TIM, W */ + u32 read_tim; /* READ_TIM, R */ +} mputimer_regs_t; + +#define mputimer_base(n) \ + ((volatile mputimer_regs_t*)IO_ADDRESS(OMAP_MPUTIMER_BASE + \ + (n)*OMAP_MPUTIMER_OFF)) + +static inline unsigned long timer32k_read(int reg) { + unsigned long val; + val = omap_readw(reg + OMAP_32kHz_TIMER_BASE); + return val; +} +static inline void timer32k_write(int reg,int val) { + omap_writew(val, reg + OMAP_32kHz_TIMER_BASE); +} + +/* + * How long is the timer interval? 100 HZ, right... + * IRQ rate = (TVR + 1) / 32768 seconds + * TVR = 32768 * IRQ_RATE -1 + * IRQ_RATE = 1/100 + * TVR = 326 + */ +#define TIMER32k_PERIOD 326 +//#define TIMER32k_PERIOD 0x7ff + +static inline void start_timer32k(void) { + timer32k_write(TIMER32k_CR, + TIMER32k_TSS | TIMER32k_TRB | + TIMER32k_INT | TIMER32k_ARL); +} + +#ifdef CONFIG_MACH_OMAP_PERSEUS2 +/* + * After programming PTV with 0 and setting the MPUTIM_CLOCK_ENABLE + * (external clock enable) bit, the timer count rate is 6.5 MHz (13 + * MHZ input/2). !! The divider by 2 is undocumented !! + */ +#define MPUTICKS_PER_SEC (13000000/2) +#else +/* + * After programming PTV with 0, the timer count rate is 6 MHz. + * WARNING! this must be an even number, or machinecycles_to_usecs + * below will break. + */ +#define MPUTICKS_PER_SEC (12000000/2) +#endif + +static int mputimer_started[3] = {0,0,0}; + +static inline void __noinstrument start_mputimer(int n, + unsigned long load_val) +{ + volatile mputimer_regs_t* timer = mputimer_base(n); + + mputimer_started[n] = 0; + timer->cntl = MPUTIM_CLOCK_ENABLE; + udelay(1); + + timer->load_tim = load_val; + udelay(1); + timer->cntl = (MPUTIM_CLOCK_ENABLE | MPUTIM_AR | MPUTIM_ST); + mputimer_started[n] = 1; +} + +static inline unsigned long __noinstrument +read_mputimer(int n) +{ + volatile mputimer_regs_t* timer = mputimer_base(n); + return (mputimer_started[n] ? timer->read_tim : 0); +} + +void __noinstrument start_mputimer1(unsigned long load_val) +{ + start_mputimer(0, load_val); +} +void __noinstrument start_mputimer2(unsigned long load_val) +{ + start_mputimer(1, load_val); +} +void __noinstrument start_mputimer3(unsigned long load_val) +{ + start_mputimer(2, load_val); +} + +unsigned long __noinstrument read_mputimer1(void) +{ + return read_mputimer(0); +} +unsigned long __noinstrument read_mputimer2(void) +{ + return read_mputimer(1); +} +unsigned long __noinstrument read_mputimer3(void) +{ + return read_mputimer(2); +} + +unsigned long __noinstrument do_getmachinecycles(void) +{ + return 0 - read_mputimer(0); +} + +unsigned long __noinstrument machinecycles_to_usecs(unsigned long mputicks) +{ + /* Round up to nearest usec */ + return ((mputicks * 1000) / (MPUTICKS_PER_SEC / 2 / 1000) + 1) >> 1; +} + +/* + * This marks the time of the last system timer interrupt + * that was *processed by the ISR* (timer 2). + */ +static unsigned long systimer_mark; + +static unsigned long omap_gettimeoffset(void) +{ + /* Return elapsed usecs since last system timer ISR */ + return machinecycles_to_usecs(do_getmachinecycles() - systimer_mark); +} + +static irqreturn_t +omap_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long now, ilatency; + + /* + * Mark the time at which the timer interrupt ocurred using + * timer1. We need to remove interrupt latency, which we can + * retrieve from the current system timer2 counter. Both the + * offset timer1 and the system timer2 are counting at 6MHz, + * so we're ok. + */ + now = 0 - read_mputimer1(); + ilatency = MPUTICKS_PER_SEC / 100 - read_mputimer2(); + systimer_mark = now - ilatency; + + do_leds(); + do_timer(regs); + do_profile(regs); + + return IRQ_HANDLED; +} + +static struct irqaction omap_timer_irq = { + .name = "OMAP Timer Tick", + .flags = SA_INTERRUPT, + .handler = omap_timer_interrupt +}; + +void __init omap_init_time(void) +{ + /* Since we don't call request_irq, we must init the structure */ + gettimeoffset = omap_gettimeoffset; + +#ifdef OMAP1510_USE_32KHZ_TIMER + timer32k_write(TIMER32k_CR, 0x0); + timer32k_write(TIMER32k_TVR,TIMER32k_PERIOD); + setup_irq(INT_OS_32kHz_TIMER, &omap_timer_irq); + start_timer32k(); +#else + setup_irq(INT_TIMER2, &omap_timer_irq); + start_mputimer2(MPUTICKS_PER_SEC / 100 - 1); +#endif +} + diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index cc33a476796b..23c51e388a91 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -3,7 +3,7 @@ # # Common support (must be linked before board specific support) -obj-y += generic.o irq.o dma.o +obj-y += generic.o irq.o dma.o time.o obj-$(CONFIG_PXA25x) += pxa25x.o obj-$(CONFIG_PXA27x) += pxa27x.o diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h index 6b33fb03ce42..0534d175617a 100644 --- a/arch/arm/mach-pxa/generic.h +++ b/arch/arm/mach-pxa/generic.h @@ -11,6 +11,7 @@ extern void __init pxa_map_io(void); extern void __init pxa_init_irq(void); +extern void __init pxa_init_time(void); #define SET_BANK(__nr,__start,__size) \ mi->bank[__nr].start = (__start), \ diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c index 706858ea2490..db53cd571cd0 100644 --- a/arch/arm/mach-pxa/idp.c +++ b/arch/arm/mach-pxa/idp.c @@ -118,5 +118,6 @@ MACHINE_START(PXA_IDP, "Accelent Xscale IDP") BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) MAPIO(idp_map_io) INITIRQ(idp_init_irq) + INITTIME(pxa_init_time) INIT_MACHINE(idp_init) MACHINE_END diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 023c5e9f316f..ce8666a7a79e 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -220,5 +220,6 @@ MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)") BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) MAPIO(lubbock_map_io) INITIRQ(lubbock_init_irq) + INITTIME(pxa_init_time) INIT_MACHINE(lubbock_init) MACHINE_END diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 663c1eef8a0a..ac998c44d577 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -137,5 +137,6 @@ MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)") BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) MAPIO(mainstone_map_io) INITIRQ(mainstone_init_irq) + INITTIME(pxa_init_time) INIT_MACHINE(mainstone_init) MACHINE_END diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c new file mode 100644 index 000000000000..432f65db19b7 --- /dev/null +++ b/arch/arm/mach-pxa/time.c @@ -0,0 +1,128 @@ +/* + * arch/arm/mach-pxa/time.c + * + * Author: Nicolas Pitre + * Created: Jun 15, 2001 + * Copyright: MontaVista Software Inc. + * + * This program 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +static inline unsigned long pxa_get_rtc_time(void) +{ + return RCNR; +} + +static int pxa_set_rtc(void) +{ + unsigned long current_time = xtime.tv_sec; + + if (RTSR & RTSR_ALE) { + /* make sure not to forward the clock over an alarm */ + unsigned long alarm = RTAR; + if (current_time >= alarm && alarm >= RCNR) + return -ERESTARTSYS; + } + RCNR = current_time; + return 0; +} + +/* IRQs are disabled before entering here from do_gettimeofday() */ +static unsigned long pxa_gettimeoffset (void) +{ + long ticks_to_match, elapsed, usec; + + /* Get ticks before next timer match */ + ticks_to_match = OSMR0 - OSCR; + + /* We need elapsed ticks since last match */ + elapsed = LATCH - ticks_to_match; + + /* don't get fooled by the workaround in pxa_timer_interrupt() */ + if (elapsed <= 0) + return 0; + + /* Now convert them to usec */ + usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH; + + return usec; +} + +static irqreturn_t +pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int next_match; + + do_profile(regs); + + /* Loop until we get ahead of the free running timer. + * This ensures an exact clock tick count and time accuracy. + * IRQs are disabled inside the loop to ensure coherence between + * lost_ticks (updated in do_timer()) and the match reg value, so we + * can use do_gettimeofday() from interrupt handlers. + * + * HACK ALERT: it seems that the PXA timer regs aren't updated right + * away in all cases when a write occurs. We therefore compare with + * 8 instead of 0 in the while() condition below to avoid missing a + * match if OSCR has already reached the next OSMR value. + * Experience has shown that up to 6 ticks are needed to work around + * this problem, but let's use 8 to be conservative. Note that this + * affect things only when the timer IRQ has been delayed by nearly + * exactly one tick period which should be a pretty rare event. + */ + do { + do_leds(); + do_set_rtc(); + do_timer(regs); + OSSR = OSSR_M0; /* Clear match on timer 0 */ + next_match = (OSMR0 += LATCH); + } while( (signed long)(next_match - OSCR) <= 8 ); + + return IRQ_HANDLED; +} + +static struct irqaction pxa_timer_irq = { + .name = "PXA Timer Tick", + .flags = SA_INTERRUPT, + .handler = pxa_timer_interrupt +}; + +void __init pxa_init_time(void) +{ + struct timespec tv; + + gettimeoffset = pxa_gettimeoffset; + set_rtc = pxa_set_rtc; + + tv.tv_nsec = 0; + tv.tv_sec = pxa_get_rtc_time(); + do_settimeofday(&tv); + + OSMR0 = 0; /* set initial match at 0 */ + OSSR = 0xf; /* clear status on all timers */ + setup_irq(IRQ_OST0, &pxa_timer_irq); + OIER |= OIER_E0; /* enable match on timer 0 to cause interrupts */ + OSCR = 0; /* initialize free-running timer, force first match */ +} + diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c index f45e28116609..7dae14b39103 100644 --- a/arch/arm/mach-rpc/riscpc.c +++ b/arch/arm/mach-rpc/riscpc.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include @@ -25,6 +27,7 @@ #include #include +#include extern void rpc_init_irq(void); @@ -82,6 +85,33 @@ void __init rpc_map_io(void) elf_hwcap &= ~HWCAP_HALF; } +static irqreturn_t +rpc_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + do_timer(regs); + do_set_rtc(); + do_profile(regs); + + return IRQ_HANDLED; +} + +static struct irqaction rpc_timer_irq = { + .name = "RiscPC Timer Tick", + .flags = SA_INTERRUPT, + .handler = rpc_timer_interrupt +}; + +/* + * Set up timer interrupt. + */ +void __init rpc_init_time(void) +{ + extern void ioctime_init(void); + ioctime_init(); + + setup_irq(IRQ_TIMER, &rpc_timer_irq); +} + MACHINE_START(RISCPC, "Acorn-RiscPC") MAINTAINER("Russell King") BOOT_MEM(0x10000000, 0x03000000, 0xe0000000) @@ -90,4 +120,5 @@ MACHINE_START(RISCPC, "Acorn-RiscPC") DISABLE_PARPORT(1) MAPIO(rpc_map_io) INITIRQ(rpc_init_irq) + INITTIME(rpc_init_time) MACHINE_END diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile index d36316999639..d183de782168 100644 --- a/arch/arm/mach-s3c2410/Makefile +++ b/arch/arm/mach-s3c2410/Makefile @@ -4,7 +4,7 @@ # Object file lists. -obj-y := s3c2410.o irq.o +obj-y := s3c2410.o irq.o time.o obj-m := obj-n := obj- := diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index c1f566f319f5..2268ab3c7c69 100644 --- a/arch/arm/mach-s3c2410/mach-bast.c +++ b/arch/arm/mach-s3c2410/mach-bast.c @@ -185,10 +185,16 @@ void __init bast_init_irq(void) } +void __init bast_init_time(void) +{ + s3c2410_init_time(); +} + MACHINE_START(BAST, "Simtec-BAST") MAINTAINER("Ben Dooks ") BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART) BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) MAPIO(bast_map_io) INITIRQ(bast_init_irq) + INITTIME(bast_init_time) MACHINE_END diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c index a66b451ec7d0..f3515bcec1b7 100644 --- a/arch/arm/mach-s3c2410/mach-h1940.c +++ b/arch/arm/mach-s3c2410/mach-h1940.c @@ -91,10 +91,16 @@ void __init ipaq_init_irq(void) } +void __init ipaq_init_time(void) +{ + s3c2410_init_time(); +} + MACHINE_START(H1940, "IPAQ-H1940") MAINTAINER("Ben Dooks ") BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART) BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) MAPIO(ipaq_map_io) INITIRQ(ipaq_init_irq) + INITTIME(ipaq_init_time) MACHINE_END diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c index 4e0282b12fbb..fb180732b860 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2410.c +++ b/arch/arm/mach-s3c2410/mach-smdk2410.c @@ -99,6 +99,11 @@ void __init smdk2410_init_irq(void) s3c2410_init_irq(); } +void __init smdk2410_init_time(void) +{ + s3c2401_init_time(); +} + MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch * to SMDK2410 */ MAINTAINER("Jonas Dietsche") @@ -106,4 +111,5 @@ MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switc BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) MAPIO(smdk2410_map_io) INITIRQ(smdk2410_init_irq) + INITTIME(smdk2410_init_time) MACHINE_END diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c index 1758422da7bf..856739ba1921 100644 --- a/arch/arm/mach-s3c2410/mach-vr1000.c +++ b/arch/arm/mach-s3c2410/mach-vr1000.c @@ -155,10 +155,16 @@ void __init vr1000_init_irq(void) } +void __init vr1000_init_time(void) +{ + s3c2401_init_time(); +} + MACHINE_START(VR1000, "Simtec-VR1000") MAINTAINER("Ben Dooks ") BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART) BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) MAPIO(vr1000_map_io) INITIRQ(vr1000_init_irq) + INITTIME(vr1000_init_time) MACHINE_END diff --git a/arch/arm/mach-s3c2410/s3c2410.h b/arch/arm/mach-s3c2410/s3c2410.h index 80c336caa86d..5ff132081a6f 100644 --- a/arch/arm/mach-s3c2410/s3c2410.h +++ b/arch/arm/mach-s3c2410/s3c2410.h @@ -4,3 +4,5 @@ extern void s3c2410_map_io(struct map_desc *, int count); extern void s3c2410_init_irq(void); +extern s3c2410_init_time(void); + diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/mach-s3c2410/time.c new file mode 100644 index 000000000000..e86250e69b65 --- /dev/null +++ b/arch/arm/mach-s3c2410/time.c @@ -0,0 +1,181 @@ +/* linux/include/asm-arm/arch-s3c2410/time.h + * + * Copyright (C) 2003 Simtec Electronics + * Ben Dooks, + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static unsigned long timer_startval; +static unsigned long timer_ticks_usec; + +#ifdef CONFIG_S3C2410_RTC +extern void s3c2410_rtc_check(); +#endif + +/* with an 12MHz clock, we get 12 ticks per-usec + */ + + +/*** + * Returns microsecond since last clock interrupt. Note that interrupts + * will have been disabled by do_gettimeoffset() + * IRQs are disabled before entering here from do_gettimeofday() + */ +static unsigned long s3c2410_gettimeoffset (void) +{ + unsigned long tdone; + unsigned long usec; + + /* work out how many ticks have gone since last timer interrupt */ + + tdone = timer_startval - __raw_readl(S3C2410_TCNTO(4)); + + /* currently, tcnt is in 12MHz units, but this may change + * for non-bast machines... + */ + + usec = tdone / timer_ticks_usec; + + return usec; +} + + +/* + * IRQ handler for the timer + */ +static irqreturn_t +s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + do_leds(); + do_timer(regs); + + do_set_rtc(); + //s3c2410_rtc_check(); + do_profile(regs); + + return IRQ_HANDLED; +} + +static struct irqaction s3c2410_timer_irq = { + .name = "S32410 Timer Tick", + .flags = SA_INTERRUPT, + .handler = s3c2410_timer_interrupt +}; + +/* + * Set up timer interrupt, and return the current time in seconds. + * + * Currently we only use timer4, as it is the only timer which has no + * other function that can be exploited externally + */ +void __init s3c2410_init_time (void) +{ + unsigned long tcon; + unsigned long tcnt; + unsigned long tcfg1; + unsigned long tcfg0; + + gettimeoffset = s3c2410_gettimeoffset; + + tcnt = 0xffff; /* default value for tcnt */ + + /* read the current timer configuration bits */ + + tcon = __raw_readl(S3C2410_TCON); + tcfg1 = __raw_readl(S3C2410_TCFG1); + tcfg0 = __raw_readl(S3C2410_TCFG0); + + /* configure the system for whichever machine is in use */ + + if (machine_is_bast() || machine_is_vr1000()) { + timer_ticks_usec = 12; /* timer is at 12MHz */ + tcnt = (timer_ticks_usec * (1000*1000)) / HZ; + } + + /* for the h1940, we use the pclk from the core to generate + * the timer values. since 67.5MHz is not a value we can directly + * generate the timer value from, we need to pre-scale and + * divied before using it. + * + * overall divsior to get 200Hz is 337500 + * we can fit tcnt if we pre-scale by 6, producing a tick rate + * of 11.25MHz, and a tcnt of 56250. + */ + + if (machine_is_h1940() || machine_is_smdk2410() ) { + timer_ticks_usec = s3c2410_pclk / (1000*1000); + timer_ticks_usec /= 6; + + tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; + tcfg1 |= S3C2410_TCFG1_MUX4_DIV2; + + tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK; + tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT; + + tcnt = (s3c2410_pclk / 6) / HZ; + } + + + printk("setup_timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx\n", + tcon, tcnt, tcfg0, tcfg1); + + /* check to see if timer is within 16bit range... */ + if (tcnt > 0xffff) { + panic("setup_timer: HZ is too small, cannot configure timer!"); + return; + } + + __raw_writel(tcfg1, S3C2410_TCFG1); + __raw_writel(tcfg0, S3C2410_TCFG0); + + timer_startval = tcnt; + __raw_writel(tcnt, S3C2410_TCNTB(4)); + + /* ensure timer is stopped... */ + + tcon &= ~(7<<20); + tcon |= S3C2410_TCON_T4RELOAD; + tcon |= S3C2410_TCON_T4MANUALUPD; + + __raw_writel(tcon, S3C2410_TCON); + __raw_writel(tcnt, S3C2410_TCNTB(4)); + __raw_writel(tcnt, S3C2410_TCMPB(4)); + + setup_irq(IRQ_TIMER4, &s3c2410_timer_irq); + + /* start the timer running */ + tcon |= S3C2410_TCON_T4START; + tcon &= ~S3C2410_TCON_T4MANUALUPD; + __raw_writel(tcon, S3C2410_TCON); +} + + + diff --git a/arch/arm/mach-sa1100/adsbitsy.c b/arch/arm/mach-sa1100/adsbitsy.c index d028a87ce2eb..53f990e7d615 100644 --- a/arch/arm/mach-sa1100/adsbitsy.c +++ b/arch/arm/mach-sa1100/adsbitsy.c @@ -147,4 +147,5 @@ MACHINE_START(ADSBITSY, "ADS Bitsy") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) MAPIO(adsbitsy_map_io) INITIRQ(adsbitsy_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index dcd32454e606..e5098cf9c2e9 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -324,5 +324,6 @@ MACHINE_START(ASSABET, "Intel-Assabet") FIXUP(fixup_assabet) MAPIO(assabet_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) INIT_MACHINE(assabet_init) MACHINE_END diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c index 71d9e165a3b6..cef71047ccb7 100644 --- a/arch/arm/mach-sa1100/badge4.c +++ b/arch/arm/mach-sa1100/badge4.c @@ -245,4 +245,5 @@ MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4") BOOT_PARAMS(0xc0000100) MAPIO(badge4_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/brutus.c b/arch/arm/mach-sa1100/brutus.c index fdfe024b10fa..925bf0e59fe8 100644 --- a/arch/arm/mach-sa1100/brutus.c +++ b/arch/arm/mach-sa1100/brutus.c @@ -37,4 +37,5 @@ MACHINE_START(BRUTUS, "Intel Brutus (SA1100 eval board)") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) MAPIO(brutus_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c index 00af122c4819..2c4c05013cc9 100644 --- a/arch/arm/mach-sa1100/cerf.c +++ b/arch/arm/mach-sa1100/cerf.c @@ -92,4 +92,5 @@ MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) MAPIO(cerf_map_io) INITIRQ(cerf_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/empeg.c b/arch/arm/mach-sa1100/empeg.c index b1faaa92f930..6ab57cdb0182 100644 --- a/arch/arm/mach-sa1100/empeg.c +++ b/arch/arm/mach-sa1100/empeg.c @@ -35,4 +35,5 @@ MACHINE_START(EMPEG, "empeg MP3 Car Audio Player") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) MAPIO(empeg_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/flexanet.c b/arch/arm/mach-sa1100/flexanet.c index 0a40c7831515..370df9f773cf 100644 --- a/arch/arm/mach-sa1100/flexanet.c +++ b/arch/arm/mach-sa1100/flexanet.c @@ -183,5 +183,6 @@ MACHINE_START(FLEXANET, "FlexaNet") BOOT_PARAMS(0xc0000100) MAPIO(flexanet_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/freebird.c b/arch/arm/mach-sa1100/freebird.c index 5363d02ee7e6..abd27aef72f9 100644 --- a/arch/arm/mach-sa1100/freebird.c +++ b/arch/arm/mach-sa1100/freebird.c @@ -77,4 +77,5 @@ MACHINE_START(FREEBIRD, "Freebird-HPC-1.1") #endif MAPIO(freebird_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h index 4649fc5c5c4e..04bcfeb3b8a1 100644 --- a/arch/arm/mach-sa1100/generic.h +++ b/arch/arm/mach-sa1100/generic.h @@ -6,6 +6,7 @@ extern void __init sa1100_map_io(void); extern void __init sa1100_init_irq(void); +extern void __init sa1100_init_time(void); #define SET_BANK(__nr,__start,__size) \ mi->bank[__nr].start = (__start), \ diff --git a/arch/arm/mach-sa1100/graphicsclient.c b/arch/arm/mach-sa1100/graphicsclient.c index eb420d53a93d..2f628adbda2c 100644 --- a/arch/arm/mach-sa1100/graphicsclient.c +++ b/arch/arm/mach-sa1100/graphicsclient.c @@ -198,4 +198,5 @@ MACHINE_START(GRAPHICSCLIENT, "ADS GraphicsClient") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) MAPIO(graphicsclient_map_io) INITIRQ(graphicsclient_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/graphicsmaster.c b/arch/arm/mach-sa1100/graphicsmaster.c index 77d84368d7ac..7f1cfd18eaca 100644 --- a/arch/arm/mach-sa1100/graphicsmaster.c +++ b/arch/arm/mach-sa1100/graphicsmaster.c @@ -287,4 +287,5 @@ MACHINE_START(GRAPHICSMASTER, "ADS GraphicsMaster") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) MAPIO(graphicsmaster_map_io) INITIRQ(graphicsmaster_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c index 9868d4129650..54ab44452401 100644 --- a/arch/arm/mach-sa1100/h3600.c +++ b/arch/arm/mach-sa1100/h3600.c @@ -286,6 +286,7 @@ MACHINE_START(H3100, "Compaq iPAQ H3100") BOOT_PARAMS(0xc0000100) MAPIO(h3100_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END #endif /* CONFIG_SA1100_H3100 */ @@ -400,6 +401,7 @@ MACHINE_START(H3600, "Compaq iPAQ H3600") BOOT_PARAMS(0xc0000100) MAPIO(h3600_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END #endif /* CONFIG_SA1100_H3600 */ @@ -783,6 +785,7 @@ MACHINE_START(H3800, "Compaq iPAQ H3800") BOOT_PARAMS(0xc0000100) MAPIO(h3800_map_io) INITIRQ(h3800_init_irq) + INITTIME(sa1100_init_time) MACHINE_END #endif /* CONFIG_SA1100_H3800 */ diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c index e79bb441c8fe..e24be9716ba4 100644 --- a/arch/arm/mach-sa1100/hackkit.c +++ b/arch/arm/mach-sa1100/hackkit.c @@ -174,4 +174,5 @@ MACHINE_START(HACKKIT, "HackKit Cpu Board") BOOT_PARAMS(0xc0000100) MAPIO(hackkit_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/huw_webpanel.c b/arch/arm/mach-sa1100/huw_webpanel.c index 1ed5f365c950..771b10620249 100644 --- a/arch/arm/mach-sa1100/huw_webpanel.c +++ b/arch/arm/mach-sa1100/huw_webpanel.c @@ -81,4 +81,5 @@ MACHINE_START(HUW_WEBPANEL, "HuW-Webpanel") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) MAPIO(huw_webpanel_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/itsy.c b/arch/arm/mach-sa1100/itsy.c index 2d23c99c6115..a4af8d58867d 100644 --- a/arch/arm/mach-sa1100/itsy.c +++ b/arch/arm/mach-sa1100/itsy.c @@ -37,4 +37,5 @@ MACHINE_START(ITSY, "Compaq Itsy") BOOT_PARAMS(0xc0000100) MAPIO(itsy_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c index c71e512830bd..8943e816a180 100644 --- a/arch/arm/mach-sa1100/jornada720.c +++ b/arch/arm/mach-sa1100/jornada720.c @@ -101,4 +101,5 @@ MACHINE_START(JORNADA720, "HP Jornada 720") BOOT_PARAMS(0xc0000100) MAPIO(jornada720_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c index 728612961bd5..34ab20118c70 100644 --- a/arch/arm/mach-sa1100/lart.c +++ b/arch/arm/mach-sa1100/lart.c @@ -43,4 +43,5 @@ MACHINE_START(LART, "LART") BOOT_PARAMS(0xc0000100) MAPIO(lart_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/nanoengine.c b/arch/arm/mach-sa1100/nanoengine.c index 20b6d9a43d1d..84c870c3de49 100644 --- a/arch/arm/mach-sa1100/nanoengine.c +++ b/arch/arm/mach-sa1100/nanoengine.c @@ -49,4 +49,5 @@ MACHINE_START(NANOENGINE, "BSE nanoEngine") FIXUP(fixup_nanoengine) MAPIO(nanoengine_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/omnimeter.c b/arch/arm/mach-sa1100/omnimeter.c index baa3a0313a57..1533fc0ff51c 100644 --- a/arch/arm/mach-sa1100/omnimeter.c +++ b/arch/arm/mach-sa1100/omnimeter.c @@ -59,4 +59,5 @@ MACHINE_START(OMNIMETER, "OmniMeter") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) MAPIO(omnimeter_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/pangolin.c b/arch/arm/mach-sa1100/pangolin.c index f7102f4388ed..29922dd70e41 100644 --- a/arch/arm/mach-sa1100/pangolin.c +++ b/arch/arm/mach-sa1100/pangolin.c @@ -40,4 +40,5 @@ MACHINE_START(PANGOLIN, "Dialogue-Pangolin") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) MAPIO(pangolin_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/pfs168.c b/arch/arm/mach-sa1100/pfs168.c index 43b89fcc8919..04088629f4c7 100644 --- a/arch/arm/mach-sa1100/pfs168.c +++ b/arch/arm/mach-sa1100/pfs168.c @@ -112,4 +112,5 @@ MACHINE_START(PFS168, "Tulsa") BOOT_PARAMS(0xc0000100) MAPIO(pfs168_map_io) INITIRQ(pfs168_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c index b0284ff1c74a..2cdfef622c25 100644 --- a/arch/arm/mach-sa1100/pleb.c +++ b/arch/arm/mach-sa1100/pleb.c @@ -31,4 +31,5 @@ MACHINE_START(PLEB, "PLEB") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) MAPIO(pleb_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c index 0dbe474c7611..8bec82676a3b 100644 --- a/arch/arm/mach-sa1100/shannon.c +++ b/arch/arm/mach-sa1100/shannon.c @@ -41,4 +41,5 @@ MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)") BOOT_PARAMS(0xc0000100) MAPIO(shannon_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/sherman.c b/arch/arm/mach-sa1100/sherman.c index c36f46017f53..2e66fbadf16f 100644 --- a/arch/arm/mach-sa1100/sherman.c +++ b/arch/arm/mach-sa1100/sherman.c @@ -27,4 +27,5 @@ MACHINE_START(SHERMAN, "Blazie Engineering Sherman") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) MAPIO(sherman_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c index 472174365903..b73ec2e18eb0 100644 --- a/arch/arm/mach-sa1100/simpad.c +++ b/arch/arm/mach-sa1100/simpad.c @@ -231,4 +231,5 @@ MACHINE_START(SIMPAD, "Simpad") BOOT_PARAMS(0xc0000100) MAPIO(simpad_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/stork.c b/arch/arm/mach-sa1100/stork.c index 5aeb087c45d0..f3b3a6eb8c09 100644 --- a/arch/arm/mach-sa1100/stork.c +++ b/arch/arm/mach-sa1100/stork.c @@ -331,6 +331,7 @@ MACHINE_START(STORK, "Stork Technologies prototype") BOOT_PARAMS(0xc0000100) MAPIO(stork_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/system3.c b/arch/arm/mach-sa1100/system3.c index 09f679e4e67b..76e7d36e71bc 100644 --- a/arch/arm/mach-sa1100/system3.c +++ b/arch/arm/mach-sa1100/system3.c @@ -470,4 +470,5 @@ MACHINE_START(PT_SYSTEM3, "PT System 3") BOOT_PARAMS(0xc0000100) MAPIO(system3_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c new file mode 100644 index 000000000000..caff78e1c61f --- /dev/null +++ b/arch/arm/mach-sa1100/time.c @@ -0,0 +1,116 @@ +/* + * linux/include/asm-arm/arch-sa1100/time.h + * + * Copyright (C) 1998 Deborah Wallach. + * Twiddles (C) 1999 Hugo Fiennes + * + * 2000/03/29 (C) Nicolas Pitre + * Rewritten: big cleanup, much simpler, better HZ accuracy. + * + */ + + +#define RTC_DEF_DIVIDER (32768 - 1) +#define RTC_DEF_TRIM 0 + +static unsigned long __init sa1100_get_rtc_time(void) +{ + /* + * According to the manual we should be able to let RTTR be zero + * and then a default diviser for a 32.768KHz clock is used. + * Apparently this doesn't work, at least for my SA1110 rev 5. + * If the clock divider is uninitialized then reset it to the + * default value to get the 1Hz clock. + */ + if (RTTR == 0) { + RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); + printk(KERN_WARNING "Warning: uninitialized Real Time Clock\n"); + /* The current RTC value probably doesn't make sense either */ + RCNR = 0; + return 0; + } + return RCNR; +} + +static int sa1100_set_rtc(void) +{ + unsigned long current_time = xtime.tv_sec; + + if (RTSR & RTSR_ALE) { + /* make sure not to forward the clock over an alarm */ + unsigned long alarm = RTAR; + if (current_time >= alarm && alarm >= RCNR) + return -ERESTARTSYS; + } + RCNR = current_time; + return 0; +} + +/* IRQs are disabled before entering here from do_gettimeofday() */ +static unsigned long sa1100_gettimeoffset (void) +{ + unsigned long ticks_to_match, elapsed, usec; + + /* Get ticks before next timer match */ + ticks_to_match = OSMR0 - OSCR; + + /* We need elapsed ticks since last match */ + elapsed = LATCH - ticks_to_match; + + /* Now convert them to usec */ + usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH; + + return usec; +} + +/* + * We will be entered with IRQs enabled. + * + * Loop until we get ahead of the free running timer. + * This ensures an exact clock tick count and time accuracy. + * IRQs are disabled inside the loop to ensure coherence between + * lost_ticks (updated in do_timer()) and the match reg value, so we + * can use do_gettimeofday() from interrupt handlers. + */ +static irqreturn_t +sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int next_match; + + do { + do_leds(); + do_timer(regs); + OSSR = OSSR_M0; /* Clear match on timer 0 */ + next_match = (OSMR0 += LATCH); + do_set_rtc(); + } while ((signed long)(next_match - OSCR) <= 0); + + do_profile(regs); + + return IRQ_HANDLED; +} + +static struct irqaction sa1100_timer_irq = { + .name = "SA11xx Timer Tick", + .flags = SA_INTERRUPT, + .handler = sa1100_timer_interrupt +}; + +void __init sa1100_init_time(void) +{ + struct timespec tv; + + gettimeoffset = sa1100_gettimeoffset; + set_rtc = sa1100_set_rtc; + + tv.tv_nsec = 0; + tv.tv_sec = sa1100_get_rtc_time(); + do_settimeofday(&tv); + + OSMR0 = 0; /* set initial match at 0 */ + OSSR = 0xf; /* clear status on all timers */ + setup_irq(IRQ_OST0, &sa1100_timer_irq); + OIER |= OIER_E0; /* enable match on timer 0 to cause interrupts */ + OSCR = 0; /* initialize free-running timer, force first match */ +} + diff --git a/arch/arm/mach-sa1100/trizeps.c b/arch/arm/mach-sa1100/trizeps.c index 199d9cfc5024..f3f1682ecd34 100644 --- a/arch/arm/mach-sa1100/trizeps.c +++ b/arch/arm/mach-sa1100/trizeps.c @@ -228,4 +228,5 @@ MACHINE_START(TRIZEPS, "TRIZEPS") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) MAPIO(trizeps_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/xp860.c b/arch/arm/mach-sa1100/xp860.c index 501b1bfe8b2b..ab2a523c3b14 100644 --- a/arch/arm/mach-sa1100/xp860.c +++ b/arch/arm/mach-sa1100/xp860.c @@ -89,4 +89,5 @@ MACHINE_START(XP860, "XP860") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) MAPIO(xp860_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-sa1100/yopy.c b/arch/arm/mach-sa1100/yopy.c index fd9df1bc9162..46e447fc87d9 100644 --- a/arch/arm/mach-sa1100/yopy.c +++ b/arch/arm/mach-sa1100/yopy.c @@ -91,4 +91,5 @@ MACHINE_START(YOPY, "Yopy") BOOT_PARAMS(0xc0000100) MAPIO(yopy_map_io) INITIRQ(sa1100_init_irq) + INITTIME(sa1100_init_time) MACHINE_END diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c index fed8a03ddcf9..28504c990829 100644 --- a/arch/arm/mach-shark/core.c +++ b/arch/arm/mach-shark/core.c @@ -5,13 +5,18 @@ */ #include #include +#include +#include #include #include #include +#include +#include #include #include +#include extern void shark_init_irq(void); @@ -24,10 +29,45 @@ static void __init shark_map_io(void) iotable_init(shark_io_desc, ARRAY_SIZE(shark_io_desc)); } +#define IRQ_TIMER 0 +#define HZ_TIME ((1193180 + HZ/2) / HZ) + +static irqreturn_t +shark_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + do_leds(); + do_timer(regs); + do_profile(regs); + + return IRQ_HANDLED; +} + +static struct irqaction shark_timer_irq = { + .name = "Shark Timer Tick", + .flags = SA_INTERRUPT, + .handler = shark_timer_interrupt +}; + +/* + * Set up timer interrupt, and return the current time in seconds. + */ +void __init shark_init_time(void) +{ + unsigned long flags; + + outb(0x34, 0x43); /* binary, mode 0, LSB/MSB, Ch 0 */ + outb(HZ_TIME & 0xff, 0x40); /* LSB of count */ + outb(HZ_TIME >> 8, 0x40); + + setup_irq(IRQ_TIMER, &shark_timer_irq); +} + + MACHINE_START(SHARK, "Shark") MAINTAINER("Alexander Schulz") BOOT_MEM(0x08000000, 0x40000000, 0xe0000000) BOOT_PARAMS(0x08003000) MAPIO(shark_map_io) INITIRQ(shark_init_irq) + INITTIME(shark_init_time) MACHINE_END diff --git a/arch/arm/mach-tbox/core.c b/arch/arm/mach-tbox/core.c index db9ac783cfce..09c8e026b7c4 100644 --- a/arch/arm/mach-tbox/core.c +++ b/arch/arm/mach-tbox/core.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include @@ -19,6 +21,7 @@ #include #include +#include extern unsigned long soft_irq_mask; @@ -64,10 +67,34 @@ static void __init tbox_map_io(void) iotable_init(tbox_io_desc, ARRAY_SIZE(tbox_io_desc)); } +static irqreturn_t +tbox_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) +{ + /* Clear irq */ + __raw_writel(1, FPGA1CONT + 0xc); + __raw_writel(0, FPGA1CONT + 0xc); + + do_timer(regs); + + return IRQ_HANDLED; +} + +static struct irqaction tbox_timer_irq = { + .name = "TBOX Timer Tick", + .flags = SA_INTERRUPT, + .handler = tbox_timer_interrupt +}; + +void __init tbox_init_time(void) +{ + setup_irq(IRQ_TIMER, &timer_irq); +} + MACHINE_START(TBOX, "unknown-TBOX") MAINTAINER("Philip Blundell") BOOT_MEM(0x80000000, 0x00400000, 0xe0000000) MAPIO(tbox_map_io) INITIRQ(tbox_init_irq) + INITIME(tbox_init_time) MACHINE_END diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 4c8646c62efa..27b4b95f2508 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -22,7 +22,9 @@ #include #include #include +#include +#include #include #include #include @@ -33,6 +35,7 @@ #include #include #include +#include #include #ifdef CONFIG_MMC #include @@ -511,11 +514,155 @@ static void __init versatile_init(void) leds_event = versatile_leds_event; } +/* + * Where is the timer (VA)? + */ +#define TIMER0_VA_BASE IO_ADDRESS(VERSATILE_TIMER0_1_BASE) +#define TIMER1_VA_BASE (IO_ADDRESS(VERSATILE_TIMER0_1_BASE) + 0x20) +#define TIMER2_VA_BASE IO_ADDRESS(VERSATILE_TIMER2_3_BASE) +#define TIMER3_VA_BASE (IO_ADDRESS(VERSATILE_TIMER2_3_BASE) + 0x20) +#define VA_IC_BASE IO_ADDRESS(VERSATILE_VIC_BASE) + +/* + * How long is the timer interval? + */ +#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) +#if TIMER_INTERVAL >= 0x100000 +#define TIMER_RELOAD (TIMER_INTERVAL >> 8) /* Divide by 256 */ +#define TIMER_CTRL 0x88 /* Enable, Clock / 256 */ +#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) +#elif TIMER_INTERVAL >= 0x10000 +#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */ +#define TIMER_CTRL 0x84 /* Enable, Clock / 16 */ +#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) +#else +#define TIMER_RELOAD (TIMER_INTERVAL) +#define TIMER_CTRL 0x80 /* Enable */ +#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) +#endif + +#define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable */ + +/* + * What does it look like? + */ +typedef struct TimerStruct { + unsigned long TimerLoad; + unsigned long TimerValue; + unsigned long TimerControl; + unsigned long TimerClear; +} TimerStruct_t; + +extern unsigned long (*gettimeoffset)(void); + +/* + * Returns number of ms since last clock interrupt. Note that interrupts + * will have been disabled by do_gettimeoffset() + */ +static unsigned long versatile_gettimeoffset(void) +{ + volatile TimerStruct_t *timer0 = (TimerStruct_t *)TIMER0_VA_BASE; + unsigned long ticks1, ticks2, status; + + /* + * Get the current number of ticks. Note that there is a race + * condition between us reading the timer and checking for + * an interrupt. We get around this by ensuring that the + * counter has not reloaded between our two reads. + */ + ticks2 = timer0->TimerValue & 0xffff; + do { + ticks1 = ticks2; + status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS); + ticks2 = timer0->TimerValue & 0xffff; + } while (ticks2 > ticks1); + + /* + * Number of ticks since last interrupt. + */ + ticks1 = TIMER_RELOAD - ticks2; + + /* + * Interrupt pending? If so, we've reloaded once already. + * + * FIXME: Need to check this is effectively timer 0 that expires + */ + if (status & IRQMASK_TIMERINT0_1) + ticks1 += TIMER_RELOAD; + + /* + * Convert the ticks to usecs + */ + return TICKS2USECS(ticks1); +} + +/* + * IRQ handler for the timer + */ +static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; + + // ...clear the interrupt + timer0->TimerClear = 1; + + do_leds(); + do_timer(regs); + do_profile(regs); + + return IRQ_HANDLED; +} + +static struct irqaction versatile_timer_irq = { + .name = "Versatile Timer Tick", + .flags = SA_INTERRUPT, + .handler = versatile_timer_interrupt +}; + +/* + * Set up timer interrupt, and return the current time in seconds. + */ +void __init versatile_init_time(void) +{ + volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; + volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE; + volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE; + volatile TimerStruct_t *timer3 = (volatile TimerStruct_t *)TIMER3_VA_BASE; + + /* + * set clock frequency: + * VERSATILE_REFCLK is 32KHz + * VERSATILE_TIMCLK is 1MHz + */ + *(volatile unsigned int *)IO_ADDRESS(VERSATILE_SCTL_BASE) |= + ((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | + (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel)); + + /* + * Initialise to a known state (all timers off) + */ + timer0->TimerControl = 0; + timer1->TimerControl = 0; + timer2->TimerControl = 0; + timer3->TimerControl = 0; + + timer0->TimerLoad = TIMER_RELOAD; + timer0->TimerValue = TIMER_RELOAD; + timer0->TimerControl = TIMER_CTRL | 0x40 | TIMER_CTRL_IE; /* periodic + IE */ + + /* + * Make irqs happen for the system timer + */ + setup_irq(IRQ_TIMERINT0_1, &versatile_timer_irq); + gettimeoffset = versatile_gettimeoffset; +} + MACHINE_START(VERSATILE_PB, "ARM-Versatile PB") MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd") BOOT_MEM(0x00000000, 0x101f1000, 0xf11f1000) BOOT_PARAMS(0x00000100) MAPIO(versatile_map_io) INITIRQ(versatile_init_irq) + INITTIME(versatile_init_time) INIT_MACHINE(versatile_init) MACHINE_END diff --git a/include/asm-arm/arch-adifcc/time.h b/include/asm-arm/arch-adifcc/time.h deleted file mode 100644 index 2237ef006e71..000000000000 --- a/include/asm-arm/arch-adifcc/time.h +++ /dev/null @@ -1,9 +0,0 @@ -/* - * linux/include/asm-arm/arch-adifcc/time.h - * - */ - -/* - * No on board timer, implementation @ arch/arm/kernel/xscale-time.c - */ - diff --git a/include/asm-arm/arch-cl7500/time.h b/include/asm-arm/arch-cl7500/time.h deleted file mode 100644 index e5e5be510265..000000000000 --- a/include/asm-arm/arch-cl7500/time.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * linux/include/asm-arm/arch-cl7500/time.h - * - * Copyright (c) 1996-2000 Russell King. - * - * Changelog: - * 24-Sep-1996 RMK Created - * 10-Oct-1996 RMK Brought up to date with arch-sa110eval - * 04-Dec-1997 RMK Updated for new arch/arm/time.c - */ - -extern void ioctime_init(void); - -static irqreturn_t -timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - do_timer(regs); - do_set_rtc(); - do_profile(regs); - - { - /* Twinkle the lights. */ - static int count, state = 0xff00; - if (count-- == 0) { - state ^= 0x100; - count = 25; - *((volatile unsigned int *)LED_ADDRESS) = state; - } - } - return IRQ_HANDLED; -} - -/* - * Set up timer interrupt. - */ -void __init time_init(void) -{ - ioctime_init(); - - timer_irq.handler = timer_interrupt; - - setup_irq(IRQ_TIMER, &timer_irq); -} diff --git a/include/asm-arm/arch-ebsa110/time.h b/include/asm-arm/arch-ebsa110/time.h deleted file mode 100644 index c482e372b012..000000000000 --- a/include/asm-arm/arch-ebsa110/time.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * linux/include/asm-arm/arch-ebsa110/time.h - * - * Copyright (C) 1996,1997,1998 Russell King. - * - * This program 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. - * - * No real time clock on the evalulation board! - * - * Changelog: - * 10-Oct-1996 RMK Created - * 04-Dec-1997 RMK Updated for new arch/arm/kernel/time.c - * 07-Aug-1998 RMK Updated for arch/arm/kernel/leds.c - * 28-Dec-1998 APH Made leds code optional - */ - -#include -#include - -extern unsigned long (*gettimeoffset)(void); - -#define PIT_CTRL (PIT_BASE + 0x0d) -#define PIT_T2 (PIT_BASE + 0x09) -#define PIT_T1 (PIT_BASE + 0x05) -#define PIT_T0 (PIT_BASE + 0x01) - -/* - * This is the rate at which your MCLK signal toggles (in Hz) - * This was measured on a 10 digit frequency counter sampling - * over 1 second. - */ -#define MCLK 47894000 - -/* - * This is the rate at which the PIT timers get clocked - */ -#define CLKBY7 (MCLK / 7) - -/* - * This is the counter value. We tick at 200Hz on this platform. - */ -#define COUNT ((CLKBY7 + (HZ / 2)) / HZ) - -/* - * Get the time offset from the system PIT. Note that if we have missed an - * interrupt, then the PIT counter will roll over (ie, be negative). - * This actually works out to be convenient. - */ -static unsigned long ebsa110_gettimeoffset(void) -{ - unsigned long offset, count; - - __raw_writeb(0x40, PIT_CTRL); - count = __raw_readb(PIT_T1); - count |= __raw_readb(PIT_T1) << 8; - - /* - * If count > COUNT, make the number negative. - */ - if (count > COUNT) - count |= 0xffff0000; - - offset = COUNT; - offset -= count; - - /* - * `offset' is in units of timer counts. Convert - * offset to units of microseconds. - */ - offset = offset * (1000000 / HZ) / COUNT; - - return offset; -} - -static irqreturn_t -timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - u32 count; - - /* latch and read timer 1 */ - __raw_writeb(0x40, PIT_CTRL); - count = __raw_readb(PIT_T1); - count |= __raw_readb(PIT_T1) << 8; - - count += COUNT; - - __raw_writeb(count & 0xff, PIT_T1); - __raw_writeb(count >> 8, PIT_T1); - - do_leds(); - do_timer(regs); - do_profile(regs); - - return IRQ_HANDLED; -} - -/* - * Set up timer interrupt. - */ -void __init time_init(void) -{ - /* - * Timer 1, mode 2, LSB/MSB - */ - __raw_writeb(0x70, PIT_CTRL); - __raw_writeb(COUNT & 0xff, PIT_T1); - __raw_writeb(COUNT >> 8, PIT_T1); - - gettimeoffset = ebsa110_gettimeoffset; - - timer_irq.handler = timer_interrupt; - - setup_irq(IRQ_EBSA110_TIMER0, &timer_irq); -} - - diff --git a/include/asm-arm/arch-ebsa285/time.h b/include/asm-arm/arch-ebsa285/time.h deleted file mode 100644 index f651eeb655be..000000000000 --- a/include/asm-arm/arch-ebsa285/time.h +++ /dev/null @@ -1,287 +0,0 @@ -/* - * linux/include/asm-arm/arch-ebsa285/time.h - * - * Copyright (C) 1998 Russell King. - * Copyright (C) 1998 Phil Blundell - * - * CATS has a real-time clock, though the evaluation board doesn't. - * - * Changelog: - * 21-Mar-1998 RMK Created - * 27-Aug-1998 PJB CATS support - * 28-Dec-1998 APH Made leds optional - * 20-Jan-1999 RMK Started merge of EBSA285, CATS and NetWinder - * 16-Mar-1999 RMK More support for EBSA285-like machines with RTCs in - */ - -#define RTC_PORT(x) (rtc_base+(x)) -#define RTC_ALWAYS_BCD 0 - -#include -#include - -#include -#include -#include - -static int rtc_base; - -#define mSEC_10_from_14 ((14318180 + 100) / 200) - -static unsigned long isa_gettimeoffset(void) -{ - int count; - - static int count_p = (mSEC_10_from_14/6); /* for the first call after boot */ - static unsigned long jiffies_p = 0; - - /* - * cache volatile jiffies temporarily; we have IRQs turned off. - */ - unsigned long jiffies_t; - - /* timer count may underflow right here */ - outb_p(0x00, 0x43); /* latch the count ASAP */ - - count = inb_p(0x40); /* read the latched count */ - - /* - * We do this guaranteed double memory access instead of a _p - * postfix in the previous port access. Wheee, hackady hack - */ - jiffies_t = jiffies; - - count |= inb_p(0x40) << 8; - - /* Detect timer underflows. If we haven't had a timer tick since - the last time we were called, and time is apparently going - backwards, the counter must have wrapped during this routine. */ - if ((jiffies_t == jiffies_p) && (count > count_p)) - count -= (mSEC_10_from_14/6); - else - jiffies_p = jiffies_t; - - count_p = count; - - count = (((mSEC_10_from_14/6)-1) - count) * (tick_nsec / 1000); - count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6); - - return count; -} - -static irqreturn_t -isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - if (machine_is_netwinder()) - do_leds(); - - do_timer(regs); - do_set_rtc(); - do_profile(regs); - - return IRQ_HANDLED; -} - -static unsigned long __init get_isa_cmos_time(void) -{ - unsigned int year, mon, day, hour, min, sec; - int i; - - // check to see if the RTC makes sense..... - if ((CMOS_READ(RTC_VALID) & RTC_VRT) == 0) - return mktime(1970, 1, 1, 0, 0, 0); - - /* The Linux interpretation of the CMOS clock register contents: - * When the Update-In-Progress (UIP) flag goes from 1 to 0, the - * RTC registers show the second which has precisely just started. - * Let's hope other operating systems interpret the RTC the same way. - */ - /* read RTC exactly on falling edge of update flag */ - for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ - if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) - break; - - for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ - if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) - break; - - do { /* Isn't this overkill ? UIP above should guarantee consistency */ - sec = CMOS_READ(RTC_SECONDS); - min = CMOS_READ(RTC_MINUTES); - hour = CMOS_READ(RTC_HOURS); - day = CMOS_READ(RTC_DAY_OF_MONTH); - mon = CMOS_READ(RTC_MONTH); - year = CMOS_READ(RTC_YEAR); - } while (sec != CMOS_READ(RTC_SECONDS)); - - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - } - if ((year += 1900) < 1970) - year += 100; - return mktime(year, mon, day, hour, min, sec); -} - -static int -set_isa_cmos_time(void) -{ - int retval = 0; - int real_seconds, real_minutes, cmos_minutes; - unsigned char save_control, save_freq_select; - unsigned long nowtime = xtime.tv_sec; - - save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - cmos_minutes = CMOS_READ(RTC_MINUTES); - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - BCD_TO_BIN(cmos_minutes); - - /* - * since we're only adjusting minutes and seconds, - * don't interfere with hour overflow. This avoids - * messing with unknown time zones but requires your - * RTC not to be off by more than 15 minutes - */ - real_seconds = nowtime % 60; - real_minutes = nowtime / 60; - if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) - real_minutes += 30; /* correct for half hour time zone */ - real_minutes %= 60; - - if (abs(real_minutes - cmos_minutes) < 30) { - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BIN_TO_BCD(real_seconds); - BIN_TO_BCD(real_minutes); - } - CMOS_WRITE(real_seconds,RTC_SECONDS); - CMOS_WRITE(real_minutes,RTC_MINUTES); - } else - retval = -1; - - /* The following flags have to be released exactly in this order, - * otherwise the DS12887 (popular MC146818A clone with integrated - * battery and quartz) will not reset the oscillator and will not - * update precisely 500 ms later. You won't find this mentioned in - * the Dallas Semiconductor data sheets, but who believes data - * sheets anyway ... -- Markus Kuhn - */ - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - - return retval; -} - - -static unsigned long timer1_latch; - -static unsigned long timer1_gettimeoffset (void) -{ - unsigned long value = timer1_latch - *CSR_TIMER1_VALUE; - - return ((tick_nsec / 1000) * value) / timer1_latch; -} - -static irqreturn_t -timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - *CSR_TIMER1_CLR = 0; - - /* Do the LEDs things */ - do_leds(); - do_timer(regs); - do_set_rtc(); - do_profile(regs); - - return IRQ_HANDLED; -} - -/* - * Set up timer interrupt. - */ -void __init time_init(void) -{ - int irq; - - if (machine_is_co285() || - machine_is_personal_server()) - /* - * Add-in 21285s shouldn't access the RTC - */ - rtc_base = 0; - else - rtc_base = 0x70; - - if (rtc_base) { - int reg_d, reg_b; - - /* - * Probe for the RTC. - */ - reg_d = CMOS_READ(RTC_REG_D); - - /* - * make sure the divider is set - */ - CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_REG_A); - - /* - * Set control reg B - * (24 hour mode, update enabled) - */ - reg_b = CMOS_READ(RTC_REG_B) & 0x7f; - reg_b |= 2; - CMOS_WRITE(reg_b, RTC_REG_B); - - if ((CMOS_READ(RTC_REG_A) & 0x7f) == RTC_REF_CLCK_32KHZ && - CMOS_READ(RTC_REG_B) == reg_b) { - struct timespec tv; - - /* - * We have a RTC. Check the battery - */ - if ((reg_d & 0x80) == 0) - printk(KERN_WARNING "RTC: *** warning: CMOS battery bad\n"); - - tv.tv_nsec = 0; - tv.tv_sec = get_isa_cmos_time(); - do_settimeofday(&tv); - set_rtc = set_isa_cmos_time; - } else - rtc_base = 0; - } - - if (machine_is_ebsa285() || - machine_is_co285() || - machine_is_personal_server()) { - gettimeoffset = timer1_gettimeoffset; - - timer1_latch = (mem_fclk_21285 + 8 * HZ) / (16 * HZ); - - *CSR_TIMER1_CLR = 0; - *CSR_TIMER1_LOAD = timer1_latch; - *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16; - - timer_irq.handler = timer1_interrupt; - irq = IRQ_TIMER1; - } else { - /* enable PIT timer */ - /* set for periodic (4) and LSB/MSB write (0x30) */ - outb(0x34, 0x43); - outb((mSEC_10_from_14/6) & 0xFF, 0x40); - outb((mSEC_10_from_14/6) >> 8, 0x40); - - gettimeoffset = isa_gettimeoffset; - timer_irq.handler = isa_timer_interrupt; - irq = IRQ_ISA_TIMER; - } - setup_irq(irq, &timer_irq); -} diff --git a/include/asm-arm/arch-epxa10db/time.h b/include/asm-arm/arch-epxa10db/time.h deleted file mode 100644 index 749770b83e9a..000000000000 --- a/include/asm-arm/arch-epxa10db/time.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * linux/include/asm-arm/arch-epxa10db/time.h - * - * Copyright (C) 2001 Altera Corporation - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#define TIMER00_TYPE (volatile unsigned int*) -#include - - -/* - * IRQ handler for the timer - */ -static irqreturn_t -excalibur_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - - // ...clear the interrupt - *TIMER0_CR(IO_ADDRESS(EXC_TIMER00_BASE))|=TIMER0_CR_CI_MSK; - - do_leds(); - do_timer(regs); - do_profile(regs); - - return IRQ_HANDLED; -} - -/* - * Set up timer interrupt, and return the current time in seconds. - */ -void __init time_init(void) -{ - timer_irq.handler = excalibur_timer_interrupt; - - /* - * Make irqs happen for the system timer - */ - setup_irq(IRQ_TIMER0, &timer_irq); - - /* Start the timer */ - *TIMER0_LIMIT(IO_ADDRESS(EXC_TIMER00_BASE))=(unsigned int)(EXC_AHB2_CLK_FREQUENCY/200); - *TIMER0_PRESCALE(IO_ADDRESS(EXC_TIMER00_BASE))=1; - *TIMER0_CR(IO_ADDRESS(EXC_TIMER00_BASE))=TIMER0_CR_IE_MSK | TIMER0_CR_S_MSK; -} diff --git a/include/asm-arm/arch-integrator/platform.h b/include/asm-arm/arch-integrator/platform.h index 6b67e41669f4..09ec7902f4bf 100644 --- a/include/asm-arm/arch-integrator/platform.h +++ b/include/asm-arm/arch-integrator/platform.h @@ -457,6 +457,10 @@ #define mSEC_25 (mSEC_1 * 25) #define SEC_1 (mSEC_1 * 1000) +#ifndef __ASSEMBLY__ +extern void integrator_time_init(unsigned long, unsigned int); +#endif + #define INTEGRATOR_CSR_BASE 0x10000000 #define INTEGRATOR_CSR_SIZE 0x10000000 diff --git a/include/asm-arm/arch-ixp4xx/platform.h b/include/asm-arm/arch-ixp4xx/platform.h index 52c1c445c536..b8ea57968d4a 100644 --- a/include/asm-arm/arch-ixp4xx/platform.h +++ b/include/asm-arm/arch-ixp4xx/platform.h @@ -58,6 +58,7 @@ struct ixp4xx_i2c_pins { */ extern void ixp4xx_map_io(void); extern void ixp4xx_init_irq(void); +extern void ixp4xx_init_time(void); extern void ixp4xx_pci_preinit(void); struct pci_sys_data; extern int ixp4xx_setup(int nr, struct pci_sys_data *sys); diff --git a/include/asm-arm/arch-lh7a40x/time.h b/include/asm-arm/arch-lh7a40x/time.h deleted file mode 100644 index 5f1cf4f9b2c7..000000000000 --- a/include/asm-arm/arch-lh7a40x/time.h +++ /dev/null @@ -1,53 +0,0 @@ -/* include/asm-arm/arch-lh7a40x/time.h - * - * Copyright (C) 2004 Logic Product Development - * - * This program 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. - * - */ - -#if HZ < 100 -# define TIMER_CONTROL TIMER_CONTROL1 -# define TIMER_LOAD TIMER_LOAD1 -# define TIMER_CONSTANT (508469/HZ) -# define TIMER_MODE (TIMER_C_ENABLE | TIMER_C_PERIODIC | TIMER_C_508KHZ) -# define TIMER_EOI TIMER_EOI1 -# define TIMER_IRQ IRQ_T1UI -#else -# define TIMER_CONTROL TIMER_CONTROL3 -# define TIMER_LOAD TIMER_LOAD3 -# define TIMER_CONSTANT (3686400/HZ) -# define TIMER_MODE (TIMER_C_ENABLE | TIMER_C_PERIODIC) -# define TIMER_EOI TIMER_EOI3 -# define TIMER_IRQ IRQ_T3UI -#endif - -static irqreturn_t -lh7a40x_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - TIMER_EOI = 0; - do_profile (regs); - do_leds(); - do_set_rtc(); - do_timer (regs); - - return IRQ_HANDLED; -} - -void __init time_init(void) -{ - /* Stop/disable all timers */ - TIMER_CONTROL1 = 0; - TIMER_CONTROL2 = 0; - TIMER_CONTROL3 = 0; - - timer_irq.handler = lh7a40x_timer_interrupt; - timer_irq.flags |= SA_INTERRUPT; - setup_irq (TIMER_IRQ, &timer_irq); - - TIMER_LOAD = TIMER_CONSTANT; - TIMER_CONTROL = TIMER_MODE; -} - diff --git a/include/asm-arm/arch-omap/time.h b/include/asm-arm/arch-omap/time.h deleted file mode 100644 index 9e3cc951ebb4..000000000000 --- a/include/asm-arm/arch-omap/time.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * linux/include/asm-arm/arch-omap/time.h - * - * 32kHz timer definition - * - * Copyright (C) 2000 RidgeRun, Inc. - * Author: Greg Lonnon - * - * 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; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#if !defined(__ASM_ARCH_OMAP_TIME_H) -#define __ASM_ARCH_OMAP_TIME_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef __instrument -#define __instrument -#define __noinstrument __attribute__ ((no_instrument_function)) -#endif - -typedef struct { - u32 cntl; /* CNTL_TIMER, R/W */ - u32 load_tim; /* LOAD_TIM, W */ - u32 read_tim; /* READ_TIM, R */ -} mputimer_regs_t; - -#define mputimer_base(n) \ - ((volatile mputimer_regs_t*)IO_ADDRESS(OMAP_MPUTIMER_BASE + \ - (n)*OMAP_MPUTIMER_OFF)) - -static inline unsigned long timer32k_read(int reg) { - unsigned long val; - val = omap_readw(reg + OMAP_32kHz_TIMER_BASE); - return val; -} -static inline void timer32k_write(int reg,int val) { - omap_writew(val, reg + OMAP_32kHz_TIMER_BASE); -} - -/* - * How long is the timer interval? 100 HZ, right... - * IRQ rate = (TVR + 1) / 32768 seconds - * TVR = 32768 * IRQ_RATE -1 - * IRQ_RATE = 1/100 - * TVR = 326 - */ -#define TIMER32k_PERIOD 326 -//#define TIMER32k_PERIOD 0x7ff - -static inline void start_timer32k(void) { - timer32k_write(TIMER32k_CR, - TIMER32k_TSS | TIMER32k_TRB | - TIMER32k_INT | TIMER32k_ARL); -} - -#ifdef CONFIG_MACH_OMAP_PERSEUS2 -/* - * After programming PTV with 0 and setting the MPUTIM_CLOCK_ENABLE - * (external clock enable) bit, the timer count rate is 6.5 MHz (13 - * MHZ input/2). !! The divider by 2 is undocumented !! - */ -#define MPUTICKS_PER_SEC (13000000/2) -#else -/* - * After programming PTV with 0, the timer count rate is 6 MHz. - * WARNING! this must be an even number, or machinecycles_to_usecs - * below will break. - */ -#define MPUTICKS_PER_SEC (12000000/2) -#endif - -static int mputimer_started[3] = {0,0,0}; - -static inline void __noinstrument start_mputimer(int n, - unsigned long load_val) -{ - volatile mputimer_regs_t* timer = mputimer_base(n); - - mputimer_started[n] = 0; - timer->cntl = MPUTIM_CLOCK_ENABLE; - udelay(1); - - timer->load_tim = load_val; - udelay(1); - timer->cntl = (MPUTIM_CLOCK_ENABLE | MPUTIM_AR | MPUTIM_ST); - mputimer_started[n] = 1; -} - -static inline unsigned long __noinstrument -read_mputimer(int n) -{ - volatile mputimer_regs_t* timer = mputimer_base(n); - return (mputimer_started[n] ? timer->read_tim : 0); -} - -void __noinstrument start_mputimer1(unsigned long load_val) -{ - start_mputimer(0, load_val); -} -void __noinstrument start_mputimer2(unsigned long load_val) -{ - start_mputimer(1, load_val); -} -void __noinstrument start_mputimer3(unsigned long load_val) -{ - start_mputimer(2, load_val); -} - -unsigned long __noinstrument read_mputimer1(void) -{ - return read_mputimer(0); -} -unsigned long __noinstrument read_mputimer2(void) -{ - return read_mputimer(1); -} -unsigned long __noinstrument read_mputimer3(void) -{ - return read_mputimer(2); -} - -unsigned long __noinstrument do_getmachinecycles(void) -{ - return 0 - read_mputimer(0); -} - -unsigned long __noinstrument machinecycles_to_usecs(unsigned long mputicks) -{ - /* Round up to nearest usec */ - return ((mputicks * 1000) / (MPUTICKS_PER_SEC / 2 / 1000) + 1) >> 1; -} - -/* - * This marks the time of the last system timer interrupt - * that was *processed by the ISR* (timer 2). - */ -static unsigned long systimer_mark; - -static unsigned long omap1510_gettimeoffset(void) -{ - /* Return elapsed usecs since last system timer ISR */ - return machinecycles_to_usecs(do_getmachinecycles() - systimer_mark); -} - -static irqreturn_t -omap1510_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned long now, ilatency; - - /* - * Mark the time at which the timer interrupt ocurred using - * timer1. We need to remove interrupt latency, which we can - * retrieve from the current system timer2 counter. Both the - * offset timer1 and the system timer2 are counting at 6MHz, - * so we're ok. - */ - now = 0 - read_mputimer1(); - ilatency = MPUTICKS_PER_SEC / 100 - read_mputimer2(); - systimer_mark = now - ilatency; - - do_leds(); - do_timer(regs); - do_profile(regs); - - return IRQ_HANDLED; -} - -void __init time_init(void) -{ - /* Since we don't call request_irq, we must init the structure */ - gettimeoffset = omap1510_gettimeoffset; - - timer_irq.handler = omap1510_timer_interrupt; - timer_irq.flags = SA_INTERRUPT; -#ifdef OMAP1510_USE_32KHZ_TIMER - timer32k_write(TIMER32k_CR, 0x0); - timer32k_write(TIMER32k_TVR,TIMER32k_PERIOD); - setup_irq(INT_OS_32kHz_TIMER, &timer_irq); - start_timer32k(); -#else - setup_irq(INT_TIMER2, &timer_irq); - start_mputimer2(MPUTICKS_PER_SEC / 100 - 1); -#endif -} - -#endif diff --git a/include/asm-arm/arch-pxa/time.h b/include/asm-arm/arch-pxa/time.h deleted file mode 100644 index bc9437a8c38d..000000000000 --- a/include/asm-arm/arch-pxa/time.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * linux/include/asm-arm/arch-pxa/time.h - * - * Author: Nicolas Pitre - * Created: Jun 15, 2001 - * Copyright: MontaVista Software Inc. - * - * This program 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. - */ - - -static inline unsigned long pxa_get_rtc_time(void) -{ - return RCNR; -} - -static int pxa_set_rtc(void) -{ - unsigned long current_time = xtime.tv_sec; - - if (RTSR & RTSR_ALE) { - /* make sure not to forward the clock over an alarm */ - unsigned long alarm = RTAR; - if (current_time >= alarm && alarm >= RCNR) - return -ERESTARTSYS; - } - RCNR = current_time; - return 0; -} - -/* IRQs are disabled before entering here from do_gettimeofday() */ -static unsigned long pxa_gettimeoffset (void) -{ - long ticks_to_match, elapsed, usec; - - /* Get ticks before next timer match */ - ticks_to_match = OSMR0 - OSCR; - - /* We need elapsed ticks since last match */ - elapsed = LATCH - ticks_to_match; - - /* don't get fooled by the workaround in pxa_timer_interrupt() */ - if (elapsed <= 0) - return 0; - - /* Now convert them to usec */ - usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH; - - return usec; -} - -static irqreturn_t -pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - int next_match; - - do_profile(regs); - - /* Loop until we get ahead of the free running timer. - * This ensures an exact clock tick count and time accuracy. - * IRQs are disabled inside the loop to ensure coherence between - * lost_ticks (updated in do_timer()) and the match reg value, so we - * can use do_gettimeofday() from interrupt handlers. - * - * HACK ALERT: it seems that the PXA timer regs aren't updated right - * away in all cases when a write occurs. We therefore compare with - * 8 instead of 0 in the while() condition below to avoid missing a - * match if OSCR has already reached the next OSMR value. - * Experience has shown that up to 6 ticks are needed to work around - * this problem, but let's use 8 to be conservative. Note that this - * affect things only when the timer IRQ has been delayed by nearly - * exactly one tick period which should be a pretty rare event. - */ - do { - do_leds(); - do_set_rtc(); - do_timer(regs); - OSSR = OSSR_M0; /* Clear match on timer 0 */ - next_match = (OSMR0 += LATCH); - } while( (signed long)(next_match - OSCR) <= 8 ); - - return IRQ_HANDLED; -} - -void __init time_init(void) -{ - struct timespec tv; - - gettimeoffset = pxa_gettimeoffset; - set_rtc = pxa_set_rtc; - - tv.tv_nsec = 0; - tv.tv_sec = pxa_get_rtc_time(); - do_settimeofday(&tv); - - timer_irq.handler = pxa_timer_interrupt; - OSMR0 = 0; /* set initial match at 0 */ - OSSR = 0xf; /* clear status on all timers */ - setup_irq(IRQ_OST0, &timer_irq); - OIER |= OIER_E0; /* enable match on timer 0 to cause interrupts */ - OSCR = 0; /* initialize free-running timer, force first match */ -} - diff --git a/include/asm-arm/arch-rpc/time.h b/include/asm-arm/arch-rpc/time.h deleted file mode 100644 index 1df6a12cd0e3..000000000000 --- a/include/asm-arm/arch-rpc/time.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * linux/include/asm-arm/arch-rpc/time.h - * - * Copyright (C) 1996-2000 Russell King. - * - * This program 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. - * - * Changelog: - * 24-Sep-1996 RMK Created - * 10-Oct-1996 RMK Brought up to date with arch-sa110eval - * 04-Dec-1997 RMK Updated for new arch/arm/time.c - */ -extern void ioctime_init(void); - -static irqreturn_t -timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - do_timer(regs); - do_set_rtc(); - do_profile(regs); - - return IRQ_HANDLED; -} - -/* - * Set up timer interrupt. - */ -void __init time_init(void) -{ - ioctime_init(); - - timer_irq.handler = timer_interrupt; - - setup_irq(IRQ_TIMER, &timer_irq); -} diff --git a/include/asm-arm/arch-s3c2410/time.h b/include/asm-arm/arch-s3c2410/time.h deleted file mode 100644 index 8aab3438a992..000000000000 --- a/include/asm-arm/arch-s3c2410/time.h +++ /dev/null @@ -1,173 +0,0 @@ -/* linux/include/asm-arm/arch-s3c2410/time.h - * - * Copyright (C) 2003 Simtec Electronics - * Ben Dooks, - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include - -#include -#include -#include - -extern unsigned long (*gettimeoffset)(void); - -static unsigned long timer_startval; -static unsigned long timer_ticks_usec; - -#ifdef CONFIG_S3C2410_RTC -extern void s3c2410_rtc_check(); -#endif - -/* with an 12MHz clock, we get 12 ticks per-usec - */ - - -/*** - * Returns microsecond since last clock interrupt. Note that interrupts - * will have been disabled by do_gettimeoffset() - * IRQs are disabled before entering here from do_gettimeofday() - */ -static unsigned long s3c2410_gettimeoffset (void) -{ - unsigned long tdone; - unsigned long usec; - - /* work out how many ticks have gone since last timer interrupt */ - - tdone = timer_startval - __raw_readl(S3C2410_TCNTO(4)); - - /* currently, tcnt is in 12MHz units, but this may change - * for non-bast machines... - */ - - usec = tdone / timer_ticks_usec; - - return usec; -} - - -/* - * IRQ handler for the timer - */ -static irqreturn_t -s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - do_leds(); - do_timer(regs); - - do_set_rtc(); - //s3c2410_rtc_check(); - do_profile(regs); - - return IRQ_HANDLED; -} - -/* - * Set up timer interrupt, and return the current time in seconds. - */ - -/* currently we only use timer4, as it is the only timer which has no - * other function that can be exploited externally -*/ - -void __init time_init (void) -{ - unsigned long tcon; - unsigned long tcnt; - unsigned long tcfg1; - unsigned long tcfg0; - - gettimeoffset = s3c2410_gettimeoffset; - timer_irq.handler = s3c2410_timer_interrupt; - - tcnt = 0xffff; /* default value for tcnt */ - - /* read the current timer configuration bits */ - - tcon = __raw_readl(S3C2410_TCON); - tcfg1 = __raw_readl(S3C2410_TCFG1); - tcfg0 = __raw_readl(S3C2410_TCFG0); - - /* configure the system for whichever machine is in use */ - - if (machine_is_bast() || machine_is_vr1000()) { - timer_ticks_usec = 12; /* timer is at 12MHz */ - tcnt = (timer_ticks_usec * (1000*1000)) / HZ; - } - - /* for the h1940, we use the pclk from the core to generate - * the timer values. since 67.5MHz is not a value we can directly - * generate the timer value from, we need to pre-scale and - * divied before using it. - * - * overall divsior to get 200Hz is 337500 - * we can fit tcnt if we pre-scale by 6, producing a tick rate - * of 11.25MHz, and a tcnt of 56250. - */ - - if (machine_is_h1940() || machine_is_smdk2410() ) { - timer_ticks_usec = s3c2410_pclk / (1000*1000); - timer_ticks_usec /= 6; - - tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; - tcfg1 |= S3C2410_TCFG1_MUX4_DIV2; - - tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK; - tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT; - - tcnt = (s3c2410_pclk / 6) / HZ; - } - - - printk("setup_timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx\n", - tcon, tcnt, tcfg0, tcfg1); - - /* check to see if timer is within 16bit range... */ - if (tcnt > 0xffff) { - panic("setup_timer: HZ is too small, cannot configure timer!"); - return; - } - - __raw_writel(tcfg1, S3C2410_TCFG1); - __raw_writel(tcfg0, S3C2410_TCFG0); - - timer_startval = tcnt; - __raw_writel(tcnt, S3C2410_TCNTB(4)); - - /* ensure timer is stopped... */ - - tcon &= ~(7<<20); - tcon |= S3C2410_TCON_T4RELOAD; - tcon |= S3C2410_TCON_T4MANUALUPD; - - __raw_writel(tcon, S3C2410_TCON); - __raw_writel(tcnt, S3C2410_TCNTB(4)); - __raw_writel(tcnt, S3C2410_TCMPB(4)); - - setup_irq(IRQ_TIMER4, &timer_irq); - - /* start the timer running */ - tcon |= S3C2410_TCON_T4START; - tcon &= ~S3C2410_TCON_T4MANUALUPD; - __raw_writel(tcon, S3C2410_TCON); -} - - - diff --git a/include/asm-arm/arch-sa1100/time.h b/include/asm-arm/arch-sa1100/time.h deleted file mode 100644 index d962626154dd..000000000000 --- a/include/asm-arm/arch-sa1100/time.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * linux/include/asm-arm/arch-sa1100/time.h - * - * Copyright (C) 1998 Deborah Wallach. - * Twiddles (C) 1999 Hugo Fiennes - * - * 2000/03/29 (C) Nicolas Pitre - * Rewritten: big cleanup, much simpler, better HZ accuracy. - * - */ - - -#define RTC_DEF_DIVIDER (32768 - 1) -#define RTC_DEF_TRIM 0 - -static unsigned long __init sa1100_get_rtc_time(void) -{ - /* - * According to the manual we should be able to let RTTR be zero - * and then a default diviser for a 32.768KHz clock is used. - * Apparently this doesn't work, at least for my SA1110 rev 5. - * If the clock divider is uninitialized then reset it to the - * default value to get the 1Hz clock. - */ - if (RTTR == 0) { - RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); - printk(KERN_WARNING "Warning: uninitialized Real Time Clock\n"); - /* The current RTC value probably doesn't make sense either */ - RCNR = 0; - return 0; - } - return RCNR; -} - -static int sa1100_set_rtc(void) -{ - unsigned long current_time = xtime.tv_sec; - - if (RTSR & RTSR_ALE) { - /* make sure not to forward the clock over an alarm */ - unsigned long alarm = RTAR; - if (current_time >= alarm && alarm >= RCNR) - return -ERESTARTSYS; - } - RCNR = current_time; - return 0; -} - -/* IRQs are disabled before entering here from do_gettimeofday() */ -static unsigned long sa1100_gettimeoffset (void) -{ - unsigned long ticks_to_match, elapsed, usec; - - /* Get ticks before next timer match */ - ticks_to_match = OSMR0 - OSCR; - - /* We need elapsed ticks since last match */ - elapsed = LATCH - ticks_to_match; - - /* Now convert them to usec */ - usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH; - - return usec; -} - -/* - * We will be entered with IRQs enabled. - * - * Loop until we get ahead of the free running timer. - * This ensures an exact clock tick count and time accuracy. - * IRQs are disabled inside the loop to ensure coherence between - * lost_ticks (updated in do_timer()) and the match reg value, so we - * can use do_gettimeofday() from interrupt handlers. - */ -static irqreturn_t -sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned int next_match; - - do { - do_leds(); - do_timer(regs); - OSSR = OSSR_M0; /* Clear match on timer 0 */ - next_match = (OSMR0 += LATCH); - do_set_rtc(); - } while ((signed long)(next_match - OSCR) <= 0); - - do_profile(regs); - - return IRQ_HANDLED; -} - -void __init time_init(void) -{ - struct timespec tv; - - gettimeoffset = sa1100_gettimeoffset; - set_rtc = sa1100_set_rtc; - - tv.tv_nsec = 0; - tv.tv_sec = sa1100_get_rtc_time(); - do_settimeofday(&tv); - - timer_irq.handler = sa1100_timer_interrupt; - OSMR0 = 0; /* set initial match at 0 */ - OSSR = 0xf; /* clear status on all timers */ - setup_irq(IRQ_OST0, &timer_irq); - OIER |= OIER_E0; /* enable match on timer 0 to cause interrupts */ - OSCR = 0; /* initialize free-running timer, force first match */ -} - diff --git a/include/asm-arm/arch-shark/time.h b/include/asm-arm/arch-shark/time.h deleted file mode 100644 index 66e45254a628..000000000000 --- a/include/asm-arm/arch-shark/time.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * linux/include/asm-arm/arch-shark/time.h - * - * by Alexander Schulz - * - * derived from include/asm-arm/arch-ebsa110/time.h - * Copyright (c) 1996,1997,1998 Russell King. - */ - -#include -#include - -#define IRQ_TIMER 0 -#define HZ_TIME ((1193180 + HZ/2) / HZ) - -static irqreturn_t -timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - do_leds(); - do_timer(regs); - do_profile(regs); - - return IRQ_HANDLED; -} - -/* - * Set up timer interrupt, and return the current time in seconds. - */ -void __init time_init(void) -{ - unsigned long flags; - - outb(0x34, 0x43); /* binary, mode 0, LSB/MSB, Ch 0 */ - outb(HZ_TIME & 0xff, 0x40); /* LSB of count */ - outb(HZ_TIME >> 8, 0x40); - - timer_irq.handler = timer_interrupt; - setup_irq(IRQ_TIMER, &timer_irq); -} diff --git a/include/asm-arm/arch-tbox/time.h b/include/asm-arm/arch-tbox/time.h deleted file mode 100644 index 461787189e1e..000000000000 --- a/include/asm-arm/arch-tbox/time.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * linux/include/asm-arm/arch-tbox/time.h - * - * Copyright (c) 1997, 1999 Phil Blundell. - * Copyright (c) 2000 FutureTV Labs Ltd - * - * Tbox has no real-time clock -- we get millisecond ticks to update - * our soft copy. - */ - -/* - * 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; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include - -#define update_rtc() - -static irqreturn_t -timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) -{ - /* Clear irq */ - __raw_writel(1, FPGA1CONT + 0xc); - __raw_writel(0, FPGA1CONT + 0xc); - - do_timer(regs); - - return IRQ_HANDLED; -} - -void __init time_init(void) -{ - timer_irq.handler = timer_interrupt; - setup_irq(IRQ_TIMER, &timer_irq); -} diff --git a/include/asm-arm/mach/arch.h b/include/asm-arm/mach/arch.h index d751faf725de..7841941c0e25 100644 --- a/include/asm-arm/mach/arch.h +++ b/include/asm-arm/mach/arch.h @@ -45,6 +45,8 @@ struct machine_desc { struct meminfo *); void (*map_io)(void);/* IO mapping function */ void (*init_irq)(void); + void (*init_time)(void); + void (*gettimeoffset)(void); void (*init_machine)(void); }; @@ -87,6 +89,9 @@ const struct machine_desc __mach_desc_##_type \ #define INITIRQ(_func) \ .init_irq = _func, +#define INITTIME(_func) \ + .init_time = _func, + #define INIT_MACHINE(_func) \ .init_machine = _func, -- cgit v1.2.3 From 04b928363634a28ff931f064488351da038f2493 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Tue, 15 Jun 2004 04:16:01 -0700 Subject: [ARM] Remove bogus gettimeoffset ptr from machine_desc struct. This was accidently added during the timer code cleanup. Signed-off-by: Deepak Saxena --- include/asm-arm/mach/arch.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/asm-arm/mach/arch.h b/include/asm-arm/mach/arch.h index 7841941c0e25..37ae74796331 100644 --- a/include/asm-arm/mach/arch.h +++ b/include/asm-arm/mach/arch.h @@ -46,7 +46,6 @@ struct machine_desc { void (*map_io)(void);/* IO mapping function */ void (*init_irq)(void); void (*init_time)(void); - void (*gettimeoffset)(void); void (*init_machine)(void); }; -- cgit v1.2.3 From 65f8e7460d289df22f91f8b15801d5681d6dbbc7 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Tue, 15 Jun 2004 04:38:14 -0700 Subject: [ARM] Delete include/asm-arm/arch-nexuspci/time.h Signed-off-by: Deepak Saxena --- include/asm-arm/arch-nexuspci/time.h | 62 ------------------------------------ 1 file changed, 62 deletions(-) delete mode 100644 include/asm-arm/arch-nexuspci/time.h diff --git a/include/asm-arm/arch-nexuspci/time.h b/include/asm-arm/arch-nexuspci/time.h deleted file mode 100644 index c0fd0cdc9cb0..000000000000 --- a/include/asm-arm/arch-nexuspci/time.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * linux/include/asm-arm/arch-nexuspci/time.h - * - * Copyright (c) 1997, 1998, 1999, 2000 FutureTV Labs Ltd. - * - * The FTV PCI card has no real-time clock. We get timer ticks from the - * SCC chip. - */ - -/* - * 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; either version - * 2 of the License, or (at your option) any later version. - */ - -static irqreturn_t -timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - static int count = 25; - unsigned char stat = __raw_readb(DUART_BASE + 0x14); - if (!(stat & 0x10)) - return; /* Not for us */ - - /* Reset counter */ - __raw_writeb(0x90, DUART_BASE + 8); - - if (--count == 0) { - static int state = 1; - state ^= 1; - __raw_writeb(0x1a + state, INTCONT_BASE); - __raw_writeb(0x18 + state, INTCONT_BASE); - count = 50; - } - - /* Wait for slow rise time */ - __raw_readb(DUART_BASE + 0x14); - __raw_readb(DUART_BASE + 0x14); - __raw_readb(DUART_BASE + 0x14); - __raw_readb(DUART_BASE + 0x14); - __raw_readb(DUART_BASE + 0x14); - __raw_readb(DUART_BASE + 0x14); - - do_timer(regs); - - return IRQ_HANDLED; -} - -void __init time_init(void) -{ - int tick = 3686400 / 16 / 2 / 100; - - __raw_writeb(tick & 0xff, DUART_BASE + 0x1c); - __raw_writeb(tick >> 8, DUART_BASE + 0x18); - __raw_writeb(0x80, DUART_BASE + 8); - __raw_writeb(0x10, DUART_BASE + 0x14); - - timer_irq.handler = timer_interrupt; - timer_irq.flags = SA_SHIRQ; - - setup_irq(IRQ_TIMER, &timer_irq); -} -- cgit v1.2.3 From d1e1909659c468219aee7547f58ebc631bbd4423 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Tue, 15 Jun 2004 04:42:18 -0700 Subject: [ARM] Delete include/asm-arm/arch-iop3xx/time.h Signed-off-by: Deepak Saxena --- include/asm-arm/arch-iop3xx/time.h | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 include/asm-arm/arch-iop3xx/time.h diff --git a/include/asm-arm/arch-iop3xx/time.h b/include/asm-arm/arch-iop3xx/time.h deleted file mode 100644 index b58ac84f954e..000000000000 --- a/include/asm-arm/arch-iop3xx/time.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * linux/include/asm-arm/arch-iop80310/time.h - * - * Author: Nicolas Pitre - * Copyright: (C) 2001 MontaVista Software Inc. - * - * This program 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. - * - */ - -- cgit v1.2.3 From f20ebfbaf07c164e83c6000ead7169839fde6085 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Tue, 15 Jun 2004 04:45:01 -0700 Subject: [ARM] Delete include/asm-arm/arch-ixp4xx/time.h Signed-off-by: Deepak Saxena --- include/asm-arm/arch-ixp4xx/time.h | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 include/asm-arm/arch-ixp4xx/time.h diff --git a/include/asm-arm/arch-ixp4xx/time.h b/include/asm-arm/arch-ixp4xx/time.h deleted file mode 100644 index e79f4acbe7b3..000000000000 --- a/include/asm-arm/arch-ixp4xx/time.h +++ /dev/null @@ -1,7 +0,0 @@ -/* - * linux/include/asm-arm/arch-ixp4xx/time.h - * - * We implement timer code in arch/arm/mach-ixp4xx/time.c - * - */ - -- cgit v1.2.3 From 237b1524ef4a23008076a36258bdb06f5bd7453f Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Tue, 15 Jun 2004 05:00:23 -0700 Subject: [ARM] Delete include/asm-arm/arch-versatile/time.h Signed-off-by: Deepak Saxena --- include/asm-arm/arch-versatile/time.h | 158 ---------------------------------- 1 file changed, 158 deletions(-) delete mode 100644 include/asm-arm/arch-versatile/time.h diff --git a/include/asm-arm/arch-versatile/time.h b/include/asm-arm/arch-versatile/time.h deleted file mode 100644 index 7d97d9565a4b..000000000000 --- a/include/asm-arm/arch-versatile/time.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * linux/include/asm-arm/arch-versatile/time.h - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include - -/* - * Where is the timer (VA)? - */ -#define TIMER0_VA_BASE IO_ADDRESS(VERSATILE_TIMER0_1_BASE) -#define TIMER1_VA_BASE (IO_ADDRESS(VERSATILE_TIMER0_1_BASE) + 0x20) -#define TIMER2_VA_BASE IO_ADDRESS(VERSATILE_TIMER2_3_BASE) -#define TIMER3_VA_BASE (IO_ADDRESS(VERSATILE_TIMER2_3_BASE) + 0x20) -#define VA_IC_BASE IO_ADDRESS(VERSATILE_VIC_BASE) - -/* - * How long is the timer interval? - */ -#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) -#if TIMER_INTERVAL >= 0x100000 -#define TIMER_RELOAD (TIMER_INTERVAL >> 8) /* Divide by 256 */ -#define TIMER_CTRL 0x88 /* Enable, Clock / 256 */ -#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) -#elif TIMER_INTERVAL >= 0x10000 -#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */ -#define TIMER_CTRL 0x84 /* Enable, Clock / 16 */ -#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) -#else -#define TIMER_RELOAD (TIMER_INTERVAL) -#define TIMER_CTRL 0x80 /* Enable */ -#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) -#endif - -#define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable */ - -/* - * What does it look like? - */ -typedef struct TimerStruct { - unsigned long TimerLoad; - unsigned long TimerValue; - unsigned long TimerControl; - unsigned long TimerClear; -} TimerStruct_t; - -extern unsigned long (*gettimeoffset)(void); - -/* - * Returns number of ms since last clock interrupt. Note that interrupts - * will have been disabled by do_gettimeoffset() - */ -static unsigned long versatile_gettimeoffset(void) -{ - volatile TimerStruct_t *timer0 = (TimerStruct_t *)TIMER0_VA_BASE; - unsigned long ticks1, ticks2, status; - - /* - * Get the current number of ticks. Note that there is a race - * condition between us reading the timer and checking for - * an interrupt. We get around this by ensuring that the - * counter has not reloaded between our two reads. - */ - ticks2 = timer0->TimerValue & 0xffff; - do { - ticks1 = ticks2; - status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS); - ticks2 = timer0->TimerValue & 0xffff; - } while (ticks2 > ticks1); - - /* - * Number of ticks since last interrupt. - */ - ticks1 = TIMER_RELOAD - ticks2; - - /* - * Interrupt pending? If so, we've reloaded once already. - * - * FIXME: Need to check this is effectively timer 0 that expires - */ - if (status & IRQMASK_TIMERINT0_1) - ticks1 += TIMER_RELOAD; - - /* - * Convert the ticks to usecs - */ - return TICKS2USECS(ticks1); -} - -/* - * IRQ handler for the timer - */ -static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; - - // ...clear the interrupt - timer0->TimerClear = 1; - - do_leds(); - do_timer(regs); - do_profile(regs); - - return IRQ_HANDLED; -} - -/* - * Set up timer interrupt, and return the current time in seconds. - */ -void __init time_init(void) -{ - volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; - volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE; - volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE; - volatile TimerStruct_t *timer3 = (volatile TimerStruct_t *)TIMER3_VA_BASE; - - /* - * set clock frequency: - * VERSATILE_REFCLK is 32KHz - * VERSATILE_TIMCLK is 1MHz - */ - *(volatile unsigned int *)IO_ADDRESS(VERSATILE_SCTL_BASE) |= - ((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | - (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel)); - - timer_irq.handler = versatile_timer_interrupt; - - /* - * Initialise to a known state (all timers off) - */ - timer0->TimerControl = 0; - timer1->TimerControl = 0; - timer2->TimerControl = 0; - timer3->TimerControl = 0; - - timer0->TimerLoad = TIMER_RELOAD; - timer0->TimerValue = TIMER_RELOAD; - timer0->TimerControl = TIMER_CTRL | 0x40 | TIMER_CTRL_IE; /* periodic + IE */ - - /* - * Make irqs happen for the system timer - */ - setup_irq(IRQ_TIMERINT0_1, &timer_irq); - gettimeoffset = versatile_gettimeoffset; -} -- cgit v1.2.3 From 9ab6f3220efd4b4d11ba7d9fafdc6ce7b0707981 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Tue, 15 Jun 2004 05:32:48 -0700 Subject: [ARM] Add include/asm-arm/mach/time.h for shared timer definitions Signed-off-by: Deepak Saxena --- include/asm-arm/mach/time.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 include/asm-arm/mach/time.h diff --git a/include/asm-arm/mach/time.h b/include/asm-arm/mach/time.h new file mode 100644 index 000000000000..a473e6dfc878 --- /dev/null +++ b/include/asm-arm/mach/time.h @@ -0,0 +1,24 @@ +/* + * linux/include/asm-arm/mach/time.h + * + * Copyright (C) 2004 MontaVista Software, Inc. + * + * This program 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. + */ +#ifndef __ASM_ARM_MACH_TIME_H +#define __ASM_ARM_MACH_TIME_H + +extern void (*init_arch_time)(void); + +void do_set_rtc(void); + +void do_profile(struct pt_regs *); + +void do_leds(void); + +extern int (*set_rtc)(void); +extern unsigned long(*gettimeoffset)(void); + +#endif -- cgit v1.2.3 From 4e54c4816bfe51c145382d272b19c2ae41e9e36f Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Tue, 15 Jun 2004 06:37:41 -0700 Subject: [NET]: Add tc extensions infrastructure. Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 + include/linux/pkt_cls.h | 171 +++++++- include/linux/pkt_sched.h | 1 + include/linux/rtnetlink.h | 17 + include/linux/skbuff.h | 10 +- include/net/pkt_act.h | 286 ++++++++++++++ include/net/pkt_cls.h | 32 +- include/net/pkt_sched.h | 80 +++- net/core/dev.c | 81 ++++ net/core/rtnetlink.c | 6 +- net/core/skbuff.c | 23 ++ net/ethernet/eth.c | 3 + net/sched/Kconfig | 35 +- net/sched/Makefile | 4 +- net/sched/act_api.c | 978 ++++++++++++++++++++++++++++++++++++++++++++++ net/sched/cls_api.c | 23 +- net/sched/cls_fw.c | 177 ++++++++- net/sched/cls_route.c | 6 +- net/sched/cls_rsvp.h | 6 +- net/sched/cls_tcindex.c | 4 +- net/sched/cls_u32.c | 187 ++++++++- net/sched/police.c | 330 +++++++++++++++- net/sched/sch_ingress.c | 72 +++- net/sched/sch_prio.c | 72 +++- 24 files changed, 2539 insertions(+), 67 deletions(-) create mode 100644 include/net/pkt_act.h create mode 100644 net/sched/act_api.c diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a55f97a34035..6402659e2e6a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -366,6 +366,8 @@ struct net_device struct Qdisc *qdisc_ingress; unsigned long tx_queue_len; /* Max frames per queue allowed */ + /* ingress path synchronizer */ + spinlock_t ingress_lock; /* hard_start_xmit synchronizer */ spinlock_t xmit_lock; /* cpu id of processor entered to hard_start_xmit or -1, diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index f54111f9d14c..74daa67e81c9 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -1,14 +1,130 @@ #ifndef __LINUX_PKT_CLS_H #define __LINUX_PKT_CLS_H +/* I think i could have done better macros ; for now this is stolen from + * some arch/mips code - jhs +*/ +#define _TC_MAKE32(x) ((x)) + +#define _TC_MAKEMASK1(n) (_TC_MAKE32(1) << _TC_MAKE32(n)) +#define _TC_MAKEMASK(v,n) (_TC_MAKE32((_TC_MAKE32(1)<<(v))-1) << _TC_MAKE32(n)) +#define _TC_MAKEVALUE(v,n) (_TC_MAKE32(v) << _TC_MAKE32(n)) +#define _TC_GETVALUE(v,n,m) ((_TC_MAKE32(v) & _TC_MAKE32(m)) >> _TC_MAKE32(n)) + +/* verdict bit breakdown + * +bit 0: when set -> this packet has been munged already + +bit 1: when set -> It is ok to munge this packet + +bit 2,3,4,5: Reclassify counter - sort of reverse TTL - if exceeded +assume loop + +bit 6,7: Where this packet was last seen +0: Above the transmit example at the socket level +1: on the Ingress +2: on the Egress + +bit 8: when set --> Request not to classify on ingress. + +bits 9,10,11: redirect counter - redirect TTL. Loop avoidance + + * + * */ + +#define TC_MUNGED _TC_MAKEMASK1(0) +#define SET_TC_MUNGED(v) ( TC_MUNGED | (v & ~TC_MUNGED)) +#define CLR_TC_MUNGED(v) ( v & ~TC_MUNGED) + +#define TC_OK2MUNGE _TC_MAKEMASK1(1) +#define SET_TC_OK2MUNGE(v) ( TC_OK2MUNGE | (v & ~TC_OK2MUNGE)) +#define CLR_TC_OK2MUNGE(v) ( v & ~TC_OK2MUNGE) + +#define S_TC_VERD _TC_MAKE32(2) +#define M_TC_VERD _TC_MAKEMASK(4,S_TC_VERD) +#define G_TC_VERD(x) _TC_GETVALUE(x,S_TC_VERD,M_TC_VERD) +#define V_TC_VERD(x) _TC_MAKEVALUE(x,S_TC_VERD) +#define SET_TC_VERD(v,n) ((V_TC_VERD(n)) | (v & ~M_TC_VERD)) + +#define S_TC_FROM _TC_MAKE32(6) +#define M_TC_FROM _TC_MAKEMASK(2,S_TC_FROM) +#define G_TC_FROM(x) _TC_GETVALUE(x,S_TC_FROM,M_TC_FROM) +#define V_TC_FROM(x) _TC_MAKEVALUE(x,S_TC_FROM) +#define SET_TC_FROM(v,n) ((V_TC_FROM(n)) | (v & ~M_TC_FROM)) +#define AT_STACK 0x0 +#define AT_INGRESS 0x1 +#define AT_EGRESS 0x2 + +#define TC_NCLS _TC_MAKEMASK1(8) +#define SET_TC_NCLS(v) ( TC_NCLS | (v & ~TC_NCLS)) +#define CLR_TC_NCLS(v) ( v & ~TC_NCLS) + +#define S_TC_RTTL _TC_MAKE32(9) +#define M_TC_RTTL _TC_MAKEMASK(3,S_TC_RTTL) +#define G_TC_RTTL(x) _TC_GETVALUE(x,S_TC_RTTL,M_TC_RTTL) +#define V_TC_RTTL(x) _TC_MAKEVALUE(x,S_TC_RTTL) +#define SET_TC_RTTL(v,n) ((V_TC_RTTL(n)) | (v & ~M_TC_RTTL)) + +#define S_TC_AT _TC_MAKE32(12) +#define M_TC_AT _TC_MAKEMASK(2,S_TC_AT) +#define G_TC_AT(x) _TC_GETVALUE(x,S_TC_AT,M_TC_AT) +#define V_TC_AT(x) _TC_MAKEVALUE(x,S_TC_AT) +#define SET_TC_AT(v,n) ((V_TC_AT(n)) | (v & ~M_TC_AT)) + +/* Action types */ +enum +{ + TCA_ACT_UNSPEC=0, + TCA_ACT_KIND=1, + TCA_ACT_OPTIONS=2, + TCA_ACT_INDEX=3, + TCA_ACT_POLICE=4, + /* other actions go here */ + __TCA_ACT_MAX=255 +}; + +#define TCA_ACT_MAX __TCA_ACT_MAX +#define TCA_OLD_COMPAT (TCA_ACT_MAX+1) +#define TCA_ACT_MAX_PRIO 32 +#define TCA_ACT_BIND 1 +#define TCA_ACT_NOBIND 0 +#define TCA_ACT_UNBIND 1 +#define TCA_ACT_NOUNBIND 0 +#define TCA_ACT_REPLACE 1 +#define TCA_ACT_NOREPLACE 0 +#define MAX_REC_LOOP 4 +#define MAX_RED_LOOP 4 + +#define TC_ACT_UNSPEC (-1) +#define TC_ACT_OK 0 +#define TC_ACT_RECLASSIFY 1 +#define TC_ACT_SHOT 2 +#define TC_ACT_PIPE 3 +#define TC_ACT_STOLEN 4 +#define TC_ACT_QUEUED 5 +#define TC_ACT_REPEAT 6 +#define TC_ACT_JUMP 0x10000000 + struct tc_police { __u32 index; +#ifdef CONFIG_NET_CLS_ACT + int refcnt; + int bindcnt; +#endif +/* Turned off because it requires new tc + * to work (for now maintain ABI) + * +#ifdef CONFIG_NET_CLS_ACT + __u32 capab; +#endif +*/ int action; -#define TC_POLICE_UNSPEC (-1) -#define TC_POLICE_OK 0 -#define TC_POLICE_RECLASSIFY 1 -#define TC_POLICE_SHOT 2 +#define TC_POLICE_UNSPEC TC_ACT_UNSPEC +#define TC_POLICE_OK TC_ACT_OK +#define TC_POLICE_RECLASSIFY TC_ACT_RECLASSIFY +#define TC_POLICE_SHOT TC_ACT_SHOT +#define TC_POLICE_PIPE TC_ACT_PIPE __u32 limit; __u32 burst; @@ -17,6 +133,26 @@ struct tc_police struct tc_ratespec peakrate; }; +struct tcf_t +{ + __u32 install; + __u32 lastuse; + __u32 expires; +}; + +struct tc_cnt +{ + int refcnt; + int bindcnt; +}; + +#define tc_gen \ + __u32 index; \ + __u32 capab; \ + int action; \ + int refcnt; \ + int bindcnt + enum { TCA_POLICE_UNSPEC, @@ -25,8 +161,8 @@ enum TCA_POLICE_PEAKRATE, TCA_POLICE_AVRATE, TCA_POLICE_RESULT, -#define TCA_POLICE_RESULT TCA_POLICE_RESULT __TCA_POLICE_MAX +#define TCA_POLICE_RESULT TCA_POLICE_RESULT }; #define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1) @@ -50,6 +186,12 @@ enum TCA_U32_DIVISOR, TCA_U32_SEL, TCA_U32_POLICE, +#ifdef CONFIG_NET_CLS_ACT + TCA_U32_ACT, +#endif +#ifdef CONFIG_NET_CLS_IND + TCA_U32_INDEV, +#endif __TCA_U32_MAX }; @@ -61,6 +203,9 @@ struct tc_u32_key __u32 val; int off; int offmask; +#ifdef CONFIG_CLS_U32_PERF + unsigned long kcnt; +#endif }; struct tc_u32_sel @@ -68,6 +213,7 @@ struct tc_u32_sel unsigned char flags; unsigned char offshift; unsigned char nkeys; + unsigned char fshift; /* fold shift */ __u16 offmask; __u16 off; @@ -75,7 +221,10 @@ struct tc_u32_sel short hoff; __u32 hmask; - +#ifdef CONFIG_CLS_U32_PERF + unsigned long rcnt; + unsigned long rhit; +#endif struct tc_u32_key keys[0]; }; @@ -102,7 +251,7 @@ enum __TCA_RSVP_MAX }; -#define TCA_RSVP_MAX (__TCA_RSVP_MAX - 1) +#define TCA_RSVP_MAX (__TCA_RSVP_MAX - 1 ) struct tc_rsvp_gpi { @@ -143,6 +292,12 @@ enum TCA_FW_UNSPEC, TCA_FW_CLASSID, TCA_FW_POLICE, +#ifdef CONFIG_NET_CLS_IND + TCA_FW_INDEV, +#endif +#ifdef CONFIG_NET_CLS_ACT + TCA_FW_ACT, +#endif __TCA_FW_MAX }; @@ -162,6 +317,6 @@ enum __TCA_TCINDEX_MAX }; -#define TCA_TCINDEX_MAX (__TCA_TCINDEX_MAX - 1) +#define TCA_TCINDEX_MAX (__TCA_TCINDEX_MAX - 1) #endif diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index a3d6b59af515..437cf3206e0e 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -37,6 +37,7 @@ struct tc_stats __u32 bps; /* Current flow byte rate */ __u32 pps; /* Current flow packet rate */ __u32 qlen; + __u32 reqs; /* number of requeues happened */ __u32 backlog; #ifdef __KERNEL__ spinlock_t *lock; diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 4b3a0b5d44b6..366eae3b4fc3 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -44,6 +44,10 @@ #define RTM_DELTFILTER (RTM_BASE+29) #define RTM_GETTFILTER (RTM_BASE+30) +#define RTM_NEWACTION (RTM_BASE+32) +#define RTM_DELACTION (RTM_BASE+33) +#define RTM_GETACTION (RTM_BASE+34) + #define RTM_NEWPREFIX (RTM_BASE+36) #define RTM_GETPREFIX (RTM_BASE+38) @@ -639,6 +643,7 @@ enum TCA_STATS, TCA_XSTATS, TCA_RATE, + TCA_FCNT, __TCA_MAX }; @@ -673,6 +678,18 @@ enum #define RTMGRP_IPV6_PREFIX 0x20000 +/* TC action piece */ +struct tcamsg +{ + unsigned char tca_family; + unsigned char tca__pad1; + unsigned short tca__pad2; +}; +#define TA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcamsg)))) +#define TA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcamsg)) +#define TCA_ACT_TAB 1 /* attr type must be >=1 */ +#define TCAA_MAX 1 + /* End of information exported to user level */ #ifdef __KERNEL__ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 7bf6501a9024..dcadb7781b9d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -155,6 +155,7 @@ struct skb_shared_info { * @sk: Socket we are owned by * @stamp: Time we arrived * @dev: Device we arrived on/are leaving by + * @input_dev: Device we arrived on * @real_dev: The real device we are using * @h: Transport layer header * @nh: Network layer header @@ -197,6 +198,7 @@ struct sk_buff { struct sock *sk; struct timeval stamp; struct net_device *dev; + struct net_device *input_dev; struct net_device *real_dev; union { @@ -262,9 +264,15 @@ struct sk_buff { } private; #endif #ifdef CONFIG_NET_SCHED - __u32 tc_index; /* traffic control index */ + __u32 tc_index; /* traffic control index */ +#ifdef CONFIG_NET_CLS_ACT + __u32 tc_verd; /* traffic control verdict */ + __u32 tc_classid; /* traffic control classid */ + #endif + #endif + /* These elements must be at the end, see alloc_skb() for details. */ unsigned int truesize; atomic_t users; diff --git a/include/net/pkt_act.h b/include/net/pkt_act.h new file mode 100644 index 000000000000..390b82aea577 --- /dev/null +++ b/include/net/pkt_act.h @@ -0,0 +1,286 @@ +#ifndef __NET_PKT_ACT_H +#define __NET_PKT_ACT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define tca_st(val) (struct tcf_##val *) +#define PRIV(a,name) ( tca_st(name) (a)->priv) + +#if 0 /* control */ +#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format,args...) +#endif + +#if 0 /* data */ +#define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define D2PRINTK(format,args...) +#endif + +static __inline__ unsigned +tcf_hash(u32 index) +{ + return index & MY_TAB_MASK; +} + +/* probably move this from being inline + * and put into act_generic +*/ +static inline void +tcf_hash_destroy(struct tcf_st *p) +{ + unsigned h = tcf_hash(p->index); + struct tcf_st **p1p; + + for (p1p = &tcf_ht[h]; *p1p; p1p = &(*p1p)->next) { + if (*p1p == p) { + write_lock_bh(&tcf_t_lock); + *p1p = p->next; + write_unlock_bh(&tcf_t_lock); +#ifdef CONFIG_NET_ESTIMATOR + qdisc_kill_estimator(&p->stats); +#endif + kfree(p); + return; + } + } + BUG_TRAP(0); +} + +static inline void +tcf_hash_release(struct tcf_st *p, int bind ) +{ + if (p) { + if (bind) { + p->bindcnt--; + } + p->refcnt--; + if (p->refcnt > 0) + MOD_DEC_USE_COUNT; + if(p->bindcnt <=0 && p->refcnt <= 0) { + tcf_hash_destroy(p); + } + } +} + +static __inline__ int +tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb, + struct tc_action *a) +{ + struct tcf_st *p; + int err =0, index = -1,i= 0, s_i = 0, n_i = 0; + struct rtattr *r ; + + read_lock(&tcf_t_lock); + + s_i = cb->args[0]; + + for (i = 0; i < MY_TAB_SIZE; i++) { + p = tcf_ht[tcf_hash(i)]; + + for (; p; p = p->next) { + index++; + if (index < s_i) + continue; + a->priv = p; + a->order = n_i; + r = (struct rtattr*) skb->tail; + RTA_PUT(skb, a->order, 0, NULL); + err = tcf_action_dump_1(skb, a, 0, 0); + if (0 > err) { + index--; + skb_trim(skb, (u8*)r - skb->data); + goto done; + } + r->rta_len = skb->tail - (u8*)r; + n_i++; + if (n_i >= TCA_ACT_MAX_PRIO) { + printk("Jamal Dump Exceeded batch limit\n"); + goto done; + } + } + } +done: + read_unlock(&tcf_t_lock); + if (n_i) + cb->args[0] += n_i; + return n_i; + +rtattr_failure: + skb_trim(skb, (u8*)r - skb->data); + goto done; +} + +static __inline__ int +tcf_del_walker(struct sk_buff *skb, struct tc_action *a) +{ + struct tcf_st *p, *s_p; + struct rtattr *r ; + int i= 0, n_i = 0; + + r = (struct rtattr*) skb->tail; + RTA_PUT(skb, a->order, 0, NULL); + RTA_PUT(skb, TCA_KIND, IFNAMSIZ, a->ops->kind); + for (i = 0; i < MY_TAB_SIZE; i++) { + p = tcf_ht[tcf_hash(i)]; + + while (p != NULL) { + s_p = p->next; + printk("tcf_del_walker deleting ..\n"); + tcf_hash_release(p, 0); + n_i++; + p = s_p; + } + } + RTA_PUT(skb, TCA_FCNT, 4, &n_i); + r->rta_len = skb->tail - (u8*)r; + + return n_i; +rtattr_failure: + skb_trim(skb, (u8*)r - skb->data); + return -EINVAL; +} + +static __inline__ int +tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb, int type, + struct tc_action *a) +{ + if (type == RTM_DELACTION) { + return tcf_del_walker(skb,a); + } else if (type == RTM_GETACTION) { + return tcf_dump_walker(skb,cb,a); + } else { + printk("tcf_generic_walker: unknown action %d\n",type); + return -EINVAL; + } +} + +static __inline__ struct tcf_st * +tcf_hash_lookup(u32 index) +{ + struct tcf_st *p; + + read_lock(&tcf_t_lock); + for (p = tcf_ht[tcf_hash(index)]; p; p = p->next) { + if (p->index == index) + break; + } + read_unlock(&tcf_t_lock); + return p; +} + +static __inline__ u32 +tcf_hash_new_index(void) +{ + do { + if (++idx_gen == 0) + idx_gen = 1; + } while (tcf_hash_lookup(idx_gen)); + + return idx_gen; +} + + +static inline int +tcf_hash_search(struct tc_action *a, u32 index) +{ + struct tcf_st *p = tcf_hash_lookup(index); + + if (p != NULL) { + a->priv = p; + return 1; + } else { + return 0; + } +} + +#ifdef CONFIG_NET_ACT_INIT +static inline struct tcf_st * +tcf_hash_check(struct tc_st *parm, struct tc_action *a, int ovr, int bind) +{ + struct tcf_st *p = NULL; + if (parm->index && (p = tcf_hash_lookup(parm->index)) != NULL) { + spin_lock(&p->lock); + if (bind) { + p->bindcnt++; + p->refcnt++; + } + spin_unlock(&p->lock); + a->priv = (void *) p; + } + return p; +} + +static inline struct tcf_st * +tcf_hash_create(struct tc_st *parm, struct rtattr *est, struct tc_action *a, int size, int ovr, int bind) +{ + unsigned h; + struct tcf_st *p = NULL; + + p = kmalloc(size, GFP_KERNEL); + if (p == NULL) + return p; + + memset(p, 0, size); + p->refcnt = 1; + + if (bind) { + p->bindcnt = 1; + } + + MOD_INC_USE_COUNT; + spin_lock_init(&p->lock); + p->stats.lock = &p->lock; + p->index = parm->index ? : tcf_hash_new_index(); + p->tm.install = jiffies; + p->tm.lastuse = jiffies; +#ifdef CONFIG_NET_ESTIMATOR + if (est) { + qdisc_new_estimator(&p->stats, est); + } +#endif + h = tcf_hash(p->index); + write_lock_bh(&tcf_t_lock); + p->next = tcf_ht[h]; + tcf_ht[h] = p; + write_unlock_bh(&tcf_t_lock); + + a->priv = (void *) p; + return p; +} + +static inline struct tcf_st * +tcf_hash_init(struct tc_st *parm, struct rtattr *est, struct tc_action *a, int size, int ovr, int bind) +{ + struct tcf_st *p; + p = tcf_hash_check (parm,a,ovr,bind); + if (NULL == p) { + return tcf_hash_create(parm, est, a, size, ovr, bind); + } +} + +#endif + +#endif diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index ca07367721df..4de3ea73ca5d 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -71,12 +71,38 @@ static inline int tc_classify(struct sk_buff *skb, struct tcf_proto *tp, struct { int err = 0; u32 protocol = skb->protocol; +#ifdef CONFIG_NET_CLS_ACT + struct tcf_proto *otp = tp; +reclassify: +#endif + protocol = skb->protocol; for ( ; tp; tp = tp->next) { if ((tp->protocol == protocol || - tp->protocol == __constant_htons(ETH_P_ALL)) && - (err = tp->classify(skb, tp, res)) >= 0) + tp->protocol == __constant_htons(ETH_P_ALL)) && + (err = tp->classify(skb, tp, res)) >= 0) { +#ifdef CONFIG_NET_CLS_ACT + if ( TC_ACT_RECLASSIFY == err) { + __u32 verd = (__u32) G_TC_VERD(skb->tc_verd); + tp = otp; + + if (MAX_REC_LOOP < verd++) { + printk("rule prio %d protocol %02x reclassify is buggy packet dropped\n",tp->prio&0xffff, ntohs(tp->protocol)); + return TC_ACT_SHOT; + } + skb->tc_verd = SET_TC_VERD(skb->tc_verd,verd); + goto reclassify; + } else { + if (skb->tc_verd) + skb->tc_verd = SET_TC_VERD(skb->tc_verd,0); + return err; + } +#else + return err; +#endif + } + } return -1; } @@ -90,6 +116,8 @@ static inline void tcf_destroy(struct tcf_proto *tp) extern int register_tcf_proto_ops(struct tcf_proto_ops *ops); extern int unregister_tcf_proto_ops(struct tcf_proto_ops *ops); +extern int ing_filter(struct sk_buff *skb); + diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 80661d855fd8..eb6c344ddd95 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -12,11 +12,14 @@ #include #include #include +#include +#include #ifdef CONFIG_X86_TSC #include #endif + struct rtattr; struct Qdisc; @@ -390,14 +393,15 @@ struct tcf_police { struct tcf_police *next; int refcnt; +#ifdef CONFIG_NET_CLS_ACT + int bindcnt; +#endif u32 index; - int action; int result; u32 ewma_rate; u32 burst; u32 mtu; - u32 toks; u32 ptoks; psched_time_t t_c; @@ -408,16 +412,84 @@ struct tcf_police struct tc_stats stats; }; +#ifdef CONFIG_NET_CLS_ACT + +#define tca_gen(name) \ +struct tcf_##name *next; \ + u32 index; \ + int refcnt; \ + int bindcnt; \ + u32 capab; \ + int action; \ + struct tcf_t tm; \ + struct tc_stats stats; \ + spinlock_t lock + + +struct tc_action +{ + void *priv; + struct tc_action_ops *ops; + __u32 type; /* for backward compat(TCA_OLD_COMPAT) */ + __u32 order; + struct tc_action *next; +}; + +#define TCA_CAP_NONE 0 +struct tc_action_ops +{ + struct tc_action_ops *next; + char kind[IFNAMSIZ]; + __u32 type; /* TBD to match kind */ + __u32 capab; /* capabilities includes 4 bit version */ + int (*act)(struct sk_buff **, struct tc_action *); + int (*get_stats)(struct sk_buff *, struct tc_action *); + int (*dump)(struct sk_buff *, struct tc_action *,int , int); + void (*cleanup)(struct tc_action *, int bind); + int (*lookup)(struct tc_action *, u32 ); + int (*init)(struct rtattr *,struct rtattr *,struct tc_action *, int , int ); + int (*walk)(struct sk_buff *, struct netlink_callback *, int , struct tc_action *); +}; + +extern int tcf_register_action(struct tc_action_ops *a); +extern int tcf_unregister_action(struct tc_action_ops *a); +extern void tcf_action_destroy(struct tc_action *a, int bind); +extern int tcf_action_exec(struct sk_buff *skb, struct tc_action *a); +extern int tcf_action_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a,char *n, int ovr, int bind); +extern int tcf_action_init_1(struct rtattr *rta, struct rtattr *est, struct tc_action *a,char *n, int ovr, int bind); +extern int tcf_action_dump(struct sk_buff *skb, struct tc_action *a, int, int); +extern int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, int); +extern int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int); +extern int tcf_action_copy_stats (struct sk_buff *,struct tc_action *); +extern int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_action *,int , int ); +extern int tcf_act_police_dump(struct sk_buff *, struct tc_action *, int, int); +extern int tcf_act_police(struct sk_buff **skb, struct tc_action *a); +#endif + +extern int tcf_police(struct sk_buff *skb, struct tcf_police *p); extern int qdisc_copy_stats(struct sk_buff *skb, struct tc_stats *st); extern void tcf_police_destroy(struct tcf_police *p); extern struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est); extern int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p); -extern int tcf_police(struct sk_buff *skb, struct tcf_police *p); -static inline void tcf_police_release(struct tcf_police *p) +static inline void tcf_police_release(struct tcf_police *p, int bind) { +#ifdef CONFIG_NET_CLS_ACT + if (p) { + if (bind) { + p->bindcnt--; + } + p->refcnt--; + if (p->refcnt > 0) + MOD_DEC_USE_COUNT; + if (p->refcnt <= 0 && !p->bindcnt) + tcf_police_destroy(p); + } +#else if (p && --p->refcnt == 0) tcf_police_destroy(p); + +#endif } extern struct Qdisc noop_qdisc; diff --git a/net/core/dev.c b/net/core/dev.c index fb20e1047f27..e3ef7d5884ff 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1351,6 +1351,9 @@ int dev_queue_xmit(struct sk_buff *skb) /* Grab device queue */ spin_lock_bh(&dev->queue_lock); q = dev->qdisc; +#ifdef CONFIG_NET_CLS_ACT + skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_EGRESS); +#endif if (q->enqueue) { rc = q->enqueue(skb, q); @@ -1731,6 +1734,48 @@ static inline int __handle_bridge(struct sk_buff *skb, return 0; } + +#ifdef CONFIG_NET_CLS_ACT +/* TODO: Maybe we should just force sch_ingress to be compiled in + * when CONFIG_NET_CLS_ACT is? otherwise some useless instructions + * a compare and 2 stores extra right now if we dont have it on + * but have CONFIG_NET_CLS_ACT + * NOTE: This doesnt stop any functionality; if you dont have + * the ingress scheduler, you just cant add policies on ingress. + * + */ +int ing_filter(struct sk_buff *skb) +{ + struct Qdisc *q; + struct net_device *dev = skb->dev; + int result = TC_ACT_OK; + + if (dev->qdisc_ingress) { + __u32 ttl = (__u32) G_TC_RTTL(skb->tc_verd); + if (MAX_RED_LOOP < ttl++) { + printk("Redir loop detected Dropping packet (%s->%s)\n", + skb->input_dev?skb->input_dev->name:"??",skb->dev->name); + return TC_ACT_SHOT; + } + + skb->tc_verd = SET_TC_RTTL(skb->tc_verd,ttl); + + skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_INGRESS); + if (NULL == skb->input_dev) { + skb->input_dev = skb->dev; + printk("ing_filter: fixed %s out %s\n",skb->input_dev->name,skb->dev->name); + } + spin_lock(&dev->ingress_lock); + if ((q = dev->qdisc_ingress) != NULL) + result = q->enqueue(skb, q); + spin_unlock(&dev->ingress_lock); + + } + + return result; +} +#endif + int netif_receive_skb(struct sk_buff *skb) { struct packet_type *ptype, *pt_prev; @@ -1762,6 +1807,13 @@ int netif_receive_skb(struct sk_buff *skb) skb->mac_len = skb->nh.raw - skb->mac.raw; pt_prev = NULL; +#ifdef CONFIG_NET_CLS_ACT + if (skb->tc_verd & TC_NCLS) { + skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); + goto ncls; + } + #endif + rcu_read_lock(); list_for_each_entry_rcu(ptype, &ptype_all, list) { if (!ptype->dev || ptype->dev == skb->dev) { @@ -1771,6 +1823,26 @@ int netif_receive_skb(struct sk_buff *skb) } } +#ifdef CONFIG_NET_CLS_ACT + if (pt_prev) { + atomic_inc(&skb->users); + ret = pt_prev->func(skb, skb->dev, pt_prev); + pt_prev = NULL; /* noone else should process this after*/ + } else { + skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd); + } + + ret = ing_filter(skb); + + if (ret == TC_ACT_SHOT || (ret == TC_ACT_STOLEN)) { + kfree_skb(skb); + goto out; + } + + skb->tc_verd = 0; +ncls: +#endif + handle_diverter(skb); if (__handle_bridge(skb, &pt_prev, &ret)) @@ -2824,6 +2896,10 @@ int register_netdevice(struct net_device *dev) spin_lock_init(&dev->queue_lock); spin_lock_init(&dev->xmit_lock); dev->xmit_lock_owner = -1; +#ifdef CONFIG_NET_CLS_ACT + spin_lock_init(&dev->ingress_lock); +#endif + #ifdef CONFIG_NET_FASTROUTE dev->fastpath_lock = RW_LOCK_UNLOCKED; #endif @@ -3358,4 +3434,9 @@ EXPORT_SYMBOL(netdev_fastroute); EXPORT_SYMBOL(netdev_fastroute_obstacles); #endif +#ifdef CONFIG_NET_CLS_ACT +EXPORT_SYMBOL(ing_filter); +#endif + + EXPORT_PER_CPU_SYMBOL(softnet_data); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 26e3577c0ec3..e652d8fbaa60 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -93,7 +93,8 @@ static const int rtm_min[(RTM_MAX+1-RTM_BASE)/4] = NLMSG_LENGTH(sizeof(struct rtmsg)), NLMSG_LENGTH(sizeof(struct tcmsg)), NLMSG_LENGTH(sizeof(struct tcmsg)), - NLMSG_LENGTH(sizeof(struct tcmsg)) + NLMSG_LENGTH(sizeof(struct tcmsg)), + NLMSG_LENGTH(sizeof(struct tcamsg)) }; static const int rta_max[(RTM_MAX+1-RTM_BASE)/4] = @@ -105,7 +106,8 @@ static const int rta_max[(RTM_MAX+1-RTM_BASE)/4] = RTA_MAX, TCA_MAX, TCA_MAX, - TCA_MAX + TCA_MAX, + TCAA_MAX }; void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 7d72cdb49a57..03a64d3ae6c2 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -49,6 +49,9 @@ #include #include #include +#ifdef CONFIG_NET_CLS_ACT +#include +#endif #include #include #include @@ -241,6 +244,15 @@ void __kfree_skb(struct sk_buff *skb) nf_bridge_put(skb->nf_bridge); #endif #endif +/* XXX: IS this still necessary? - JHS */ +#ifdef CONFIG_NET_SCHED + skb->tc_index = 0; +#ifdef CONFIG_NET_CLS_ACT + skb->tc_verd = 0; + skb->tc_classid = 0; +#endif +#endif + kfree_skbmem(skb); } @@ -312,6 +324,14 @@ struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask) #endif #ifdef CONFIG_NET_SCHED C(tc_index); +#ifdef CONFIG_NET_CLS_ACT + n->tc_verd = SET_TC_VERD(skb->tc_verd,0); + n->tc_verd = CLR_TC_OK2MUNGE(skb->tc_verd); + n->tc_verd = CLR_TC_MUNGED(skb->tc_verd); + C(input_dev); + C(tc_classid); +#endif + #endif C(truesize); atomic_set(&n->users, 1); @@ -366,6 +386,9 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) #endif #endif #ifdef CONFIG_NET_SCHED +#ifdef CONFIG_NET_CLS_ACT + new->tc_verd = old->tc_verd; +#endif new->tc_index = old->tc_index; #endif atomic_set(&new->users, 1); diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 4b3fa0084cd5..9569f3a80f86 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -164,6 +164,9 @@ unsigned short eth_type_trans(struct sk_buff *skb, struct net_device *dev) skb->mac.raw=skb->data; skb_pull(skb,ETH_HLEN); eth= skb->mac.ethernet; +#ifdef CONFIG_NET_CLS_ACT + skb->input_dev = dev; +#endif if(*eth->h_dest&1) { diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 8931426e0243..481b8ad2b84c 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -177,7 +177,7 @@ config NET_SCH_DELAY config NET_SCH_INGRESS tristate "Ingress Qdisc" - depends on NET_SCHED && NETFILTER + depends on NET_SCHED help If you say Y here, you will be able to police incoming bandwidth and drop packets when this bandwidth exceeds your desired rate. @@ -274,6 +274,22 @@ config NET_CLS_U32 To compile this code as a module, choose M here: the module will be called cls_u32. +config CLS_U32_PERF + bool " U32 classifier perfomance counters" + depends on NET_CLS_U32 + help + gathers stats that could be used to tune u32 classifier perfomance. + Requires a new iproute2 + +config NET_CLS_IND + bool "classify input device (slows things u32/fw) " + depends on NET_CLS_U32 || NET_CLS_FW + help + This option will be killed eventually when a + metadata action appears because it slows things a little + Available only for u32 and fw classifiers. + Requires a new iproute2 + config NET_CLS_RSVP tristate "Special RSVP classifier" depends on NET_CLS && NET_QOS @@ -303,9 +319,24 @@ config NET_CLS_RSVP6 To compile this code as a module, choose M here: the module will be called cls_rsvp6. +config NET_CLS_ACT + bool ' Packet ACTION ' + depends on NET_CLS && NET_QOS + ---help--- + This option requires you have a new iproute2. It enables + tc extensions which can be used with tc classifiers. + Only the u32 and fw classifiers are supported at the moment. + +config NET_ACT_POLICE + tristate ' Policing Actions' + depends on NET_CLS_ACT + ---help--- + If you are using a newer iproute2 select this one, otherwise use one + NET_CLS_POLICE below + config NET_CLS_POLICE bool "Traffic policing (needed for in/egress)" - depends on NET_CLS && NET_QOS + depends on NET_CLS && NET_QOS && !NET_ACT_POLICE help Say Y to support traffic policing (bandwidth limits). Needed for ingress and egress rate limiting. diff --git a/net/sched/Makefile b/net/sched/Makefile index af4a4f284d3a..89d838fc7e77 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile @@ -7,7 +7,9 @@ obj-y := sch_generic.o obj-$(CONFIG_NET_SCHED) += sch_api.o sch_fifo.o obj-$(CONFIG_NET_ESTIMATOR) += estimator.o obj-$(CONFIG_NET_CLS) += cls_api.o -obj-$(CONFIG_NET_CLS_POLICE) += police.o +obj-$(CONFIG_NET_CLS_ACT) += act_api.o +obj-$(CONFIG_NET_ACT_POLICE) += police.o +obj-$(CONFIG_NET_CLS_POLICE) += police.o obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o obj-$(CONFIG_NET_SCH_CSZ) += sch_csz.o diff --git a/net/sched/act_api.c b/net/sched/act_api.c new file mode 100644 index 000000000000..a0ba2f6363e9 --- /dev/null +++ b/net/sched/act_api.c @@ -0,0 +1,978 @@ +/* + * net/sched/act_api.c Packet action API. + * + * 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; either version + * 2 of the License, or (at your option) any later version. + * + * Author: Jamal Hadi Salim + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 1 /* control */ +#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format,args...) +#endif + +static struct tc_action_ops *act_base = NULL; +static rwlock_t act_mod_lock = RW_LOCK_UNLOCKED; + +int tcf_register_action(struct tc_action_ops *act) +{ + struct tc_action_ops *a, **ap; + + write_lock(&act_mod_lock); + for (ap = &act_base; (a=*ap)!=NULL; ap = &a->next) { + if (strcmp(act->kind, a->kind) == 0) { + write_unlock(&act_mod_lock); + return -EEXIST; + } + } + act->next = NULL; + *ap = act; + + write_unlock(&act_mod_lock); + + return 0; +} + +int tcf_unregister_action(struct tc_action_ops *act) +{ + struct tc_action_ops *a, **ap; + int err = -ENOENT; + + write_lock(&act_mod_lock); + for (ap = &act_base; (a=*ap)!=NULL; ap = &a->next) + if(a == act) + break; + + if (a) { + *ap = a->next; + a->next = NULL; + err = 0; + } + write_unlock(&act_mod_lock); + return err; +} + +/* lookup by name */ +struct tc_action_ops *tc_lookup_action_n(char *kind) +{ + + struct tc_action_ops *a = NULL; + + if (kind) { + read_lock(&act_mod_lock); + for (a = act_base; a; a = a->next) { + if (strcmp(kind,a->kind) == 0) + break; + } + read_unlock(&act_mod_lock); + } + + return a; +} + +/* lookup by rtattr */ +struct tc_action_ops *tc_lookup_action(struct rtattr *kind) +{ + + struct tc_action_ops *a = NULL; + + if (kind) { + read_lock(&act_mod_lock); + for (a = act_base; a; a = a->next) { + + if (strcmp((char*)RTA_DATA(kind),a->kind) == 0) + break; + } + read_unlock(&act_mod_lock); + } + + return a; +} + +/* lookup by id */ +struct tc_action_ops *tc_lookup_action_id(u32 type) +{ + struct tc_action_ops *a = NULL; + + if (type) { + read_lock(&act_mod_lock); + for (a = act_base; a; a = a->next) { + if (a->type == type) + break; + } + read_unlock(&act_mod_lock); + } + + return a; +} + +int tcf_action_exec(struct sk_buff *skb,struct tc_action *act) +{ + + struct tc_action *a; + int ret = -1; + + if (skb->tc_verd & TC_NCLS) { + skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); + DPRINTK("(%p)tcf_action_exec: cleared TC_NCLS in %s out %s\n",skb,skb->input_dev?skb->input_dev->name:"xxx",skb->dev->name); + return TC_ACT_OK; + } + while ((a = act) != NULL) { +repeat: + if (a->ops && a->ops->act) { + ret = a->ops->act(&skb,a); + if (TC_MUNGED & skb->tc_verd) { + /* copied already, allow trampling */ + skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd); + skb->tc_verd = CLR_TC_MUNGED(skb->tc_verd); + } + + if (ret != TC_ACT_PIPE) + goto exec_done; + if (ret == TC_ACT_REPEAT) + goto repeat; /* we need a ttl - JHS */ + + } + act = a->next; + } + +exec_done: + + return ret; +} + +void tcf_action_destroy(struct tc_action *act, int bind) +{ + struct tc_action *a; + + for (a = act; act; a = act) { + if (a && a->ops && a->ops->cleanup) { + DPRINTK("tcf_action_destroy destroying %p next %p\n", a,a->next?a->next:NULL); + act = act->next; + a->ops->cleanup(a, bind); + a->ops = NULL; + kfree(a); + } else { /*FIXME: Remove later - catch insertion bugs*/ + printk("tcf_action_destroy: BUG? destroying NULL ops \n"); + if (a) { + act = act->next; + kfree(a); + } else { + printk("tcf_action_destroy: BUG? destroying NULL action! \n"); + break; + } + } + } +} + +int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int bind, int ref) +{ + int err = -EINVAL; + + + if ( (NULL == a) || (NULL == a->ops) + || (NULL == a->ops->dump) ) + return err; + return a->ops->dump(skb, a, bind, ref); + +} + + +int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref) +{ + int err = -EINVAL; + unsigned char *b = skb->tail; + struct rtattr *r; + + + if ( (NULL == a) || (NULL == a->ops) + || (NULL == a->ops->dump) || (NULL == a->ops->kind)) + return err; + + + RTA_PUT(skb, TCA_KIND, IFNAMSIZ, a->ops->kind); + if (tcf_action_copy_stats(skb,a)) + goto rtattr_failure; + r = (struct rtattr*) skb->tail; + RTA_PUT(skb, TCA_OPTIONS, 0, NULL); + if ((err = tcf_action_dump_old(skb, a, bind, ref)) > 0) { + r->rta_len = skb->tail - (u8*)r; + return err; + } + + +rtattr_failure: + skb_trim(skb, b - skb->data); + return -1; + +} + +int tcf_action_dump(struct sk_buff *skb, struct tc_action *act, int bind, int ref) +{ + struct tc_action *a; + int err = -EINVAL; + unsigned char *b = skb->tail; + struct rtattr *r ; + + while ((a = act) != NULL) { + r = (struct rtattr*) skb->tail; + act = a->next; + RTA_PUT(skb, a->order, 0, NULL); + err = tcf_action_dump_1(skb, a, bind, ref); + if (0 > err) + goto rtattr_failure; + + r->rta_len = skb->tail - (u8*)r; + } + + return 0; + +rtattr_failure: + skb_trim(skb, b - skb->data); + return -err; + +} + +int tcf_action_init_1(struct rtattr *rta, struct rtattr *est, struct tc_action *a, char *name, int ovr, int bind ) +{ + struct tc_action_ops *a_o; + char act_name[4 + IFNAMSIZ + 1]; + struct rtattr *tb[TCA_ACT_MAX+1]; + struct rtattr *kind = NULL; + + int err = -EINVAL; + + + if (NULL == name) { + if (rtattr_parse(tb, TCA_ACT_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta))<0) + goto err_out; + kind = tb[TCA_ACT_KIND-1]; + if (NULL != kind) { + sprintf(act_name, "%s", (char*)RTA_DATA(kind)); + if (RTA_PAYLOAD(kind) >= IFNAMSIZ) { + printk(" Action %s bad\n", (char*)RTA_DATA(kind)); + goto err_out; + } + + } else { + printk("Action bad kind\n"); + goto err_out; + } + a_o = tc_lookup_action(kind); + } else { + sprintf(act_name, "%s", name); + DPRINTK("tcf_action_init_1: finding %s\n",act_name); + a_o = tc_lookup_action_n(name); + } +#ifdef CONFIG_KMOD + if (NULL == a_o) { + DPRINTK("tcf_action_init_1: trying to load module %s\n",act_name); + request_module (act_name); + a_o = tc_lookup_action_n(act_name); + } + +#endif + if (NULL == a_o) { + printk("failed to find %s\n",act_name); + goto err_out; + } + + if (NULL == a) { + goto err_out; + } + + /* backward compatibility for policer */ + if (NULL == name) { + err = a_o->init(tb[TCA_ACT_OPTIONS-1], est, a, ovr, bind); + if (0 > err ) { + return -EINVAL; + } + } else { + err = a_o->init(rta, est, a, ovr, bind); + if (0 > err ) { + return -EINVAL; + } + } + + DPRINTK("tcf_action_init_1: sucess %s\n",act_name); + + a->ops = a_o; + + return 0; +err_out: + return err; +} + +int tcf_action_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, char *name, int ovr , int bind) +{ + struct rtattr *tb[TCA_ACT_MAX_PRIO+1]; + int i; + struct tc_action *act = a, *a_s = a; + + int err = -EINVAL; + + if (rtattr_parse(tb, TCA_ACT_MAX_PRIO, RTA_DATA(rta), RTA_PAYLOAD(rta))<0) + return err; + + for (i=0; i < TCA_ACT_MAX_PRIO ; i++) { + if (tb[i]) { + if (NULL == act) { + act = kmalloc(sizeof(*act),GFP_KERNEL); + if (NULL == act) { + err = -ENOMEM; + goto bad_ret; + } + memset(act, 0,sizeof(*act)); + } + act->next = NULL; + if (0 > tcf_action_init_1(tb[i],est,act,name,ovr,bind)) { + printk("Error processing action order %d\n",i); + return err; + } + + act->order = i+1; + if (a_s != act) { + a_s->next = act; + a_s = act; + } + act = NULL; + } + + } + + return 0; +bad_ret: + tcf_action_destroy(a, bind); + return err; +} + +int tcf_action_copy_stats (struct sk_buff *skb,struct tc_action *a) +{ +#ifdef CONFIG_KMOD + /* place holder */ +#endif + + if (NULL == a->ops || NULL == a->ops->get_stats) + return 1; + + return a->ops->get_stats(skb,a); +} + + +static int +tca_get_fill(struct sk_buff *skb, struct tc_action *a, + u32 pid, u32 seq, unsigned flags, int event, int bind, int ref) +{ + struct tcamsg *t; + struct nlmsghdr *nlh; + unsigned char *b = skb->tail; + struct rtattr *x; + + nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*t)); + nlh->nlmsg_flags = flags; + t = NLMSG_DATA(nlh); + t->tca_family = AF_UNSPEC; + + x = (struct rtattr*) skb->tail; + RTA_PUT(skb, TCA_ACT_TAB, 0, NULL); + + if (0 > tcf_action_dump(skb, a, bind, ref)) { + goto rtattr_failure; + } + + x->rta_len = skb->tail - (u8*)x; + + nlh->nlmsg_len = skb->tail - b; + return skb->len; + +rtattr_failure: +nlmsg_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +static int act_get_notify(u32 pid, struct nlmsghdr *n, + struct tc_action *a, int event) +{ + struct sk_buff *skb; + + int err = 0; + + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); + if (!skb) + return -ENOBUFS; + + if (tca_get_fill(skb, a, pid, n->nlmsg_seq, 0, event, 0, 0) <= 0) { + kfree_skb(skb); + return -EINVAL; + } + + err = netlink_unicast(rtnl,skb, pid, MSG_DONTWAIT); + if (err > 0) + err = 0; + return err; +} + +int tcf_action_get_1(struct rtattr *rta, struct tc_action *a, struct nlmsghdr *n, u32 pid) +{ + struct tc_action_ops *a_o; + char act_name[4 + IFNAMSIZ + 1]; + struct rtattr *tb[TCA_ACT_MAX+1]; + struct rtattr *kind = NULL; + int index; + + int err = -EINVAL; + + if (rtattr_parse(tb, TCA_ACT_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta))<0) + goto err_out; + + + kind = tb[TCA_ACT_KIND-1]; + if (NULL != kind) { + sprintf(act_name, "%s", (char*)RTA_DATA(kind)); + if (RTA_PAYLOAD(kind) >= IFNAMSIZ) { + printk("tcf_action_get_1: action %s bad\n", (char*)RTA_DATA(kind)); + goto err_out; + } + + } else { + printk("tcf_action_get_1: action bad kind\n"); + goto err_out; + } + + if (tb[TCA_ACT_INDEX - 1]) { + index = *(int *)RTA_DATA(tb[TCA_ACT_INDEX - 1]); + } else { + printk("tcf_action_get_1: index not received\n"); + goto err_out; + } + + a_o = tc_lookup_action(kind); +#ifdef CONFIG_KMOD + if (NULL == a_o) { + request_module (act_name); + a_o = tc_lookup_action_n(act_name); + } + +#endif + if (NULL == a_o) { + printk("failed to find %s\n",act_name); + goto err_out; + } + + if (NULL == a) { + goto err_out; + } + + a->ops = a_o; + + if (NULL == a_o->lookup || 0 == a_o->lookup(a, index)) + return -EINVAL; + + return 0; +err_out: + return err; +} + +void cleanup_a (struct tc_action *act) +{ + struct tc_action *a; + + for (a = act; act; a = act) { + if (a) { + act = act->next; + a->ops = NULL; + a->priv = NULL; + kfree(a); + } else { + printk("cleanup_a: BUG? empty action\n"); + } + } +} + +struct tc_action_ops *get_ao(struct rtattr *kind, struct tc_action *a) +{ + char act_name[4 + IFNAMSIZ + 1]; + struct tc_action_ops *a_o = NULL; + + if (NULL != kind) { + sprintf(act_name, "%s", (char*)RTA_DATA(kind)); + if (RTA_PAYLOAD(kind) >= IFNAMSIZ) { + printk("get_ao: action %s bad\n", (char*)RTA_DATA(kind)); + return NULL; + } + + } else { + printk("get_ao: action bad kind\n"); + return NULL; + } + + a_o = tc_lookup_action(kind); +#ifdef CONFIG_KMOD + if (NULL == a_o) { + DPRINTK("get_ao: trying to load module %s\n",act_name); + request_module (act_name); + a_o = tc_lookup_action_n(act_name); + } +#endif + + if (NULL == a_o) { + printk("get_ao: failed to find %s\n",act_name); + return NULL; + } + + a->ops = a_o; + return a_o; +} + +struct tc_action *create_a(int i) +{ + struct tc_action *act = NULL; + + act = kmalloc(sizeof(*act),GFP_KERNEL); + if (NULL == act) { /* grrr .. */ + printk("create_a: failed to alloc! \n"); + return NULL; + } + + memset(act, 0,sizeof(*act)); + + act->order = i; + + return act; +} + +int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid) +{ + struct sk_buff *skb; + unsigned char *b; + struct nlmsghdr *nlh; + struct tcamsg *t; + struct rtattr *x; + struct rtattr *tb[TCA_ACT_MAX+1]; + struct rtattr *kind = NULL; + struct tc_action *a = create_a(0); + int err = -EINVAL; + + if (NULL == a) { + printk("tca_action_flush: couldnt create tc_action\n"); + return err; + } + + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); + if (!skb) { + printk("tca_action_flush: failed skb alloc\n"); + kfree(a); + return -ENOBUFS; + } + + b = (unsigned char *)skb->tail; + + if (rtattr_parse(tb, TCA_ACT_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta))<0) { + goto err_out; + } + + kind = tb[TCA_ACT_KIND-1]; + if (NULL == get_ao(kind, a)) { + goto err_out; + } + + nlh = NLMSG_PUT(skb, pid, n->nlmsg_seq, RTM_DELACTION, sizeof (*t)); + t = NLMSG_DATA(nlh); + t->tca_family = AF_UNSPEC; + + x = (struct rtattr *) skb->tail; + RTA_PUT(skb, TCA_ACT_TAB, 0, NULL); + + err = a->ops->walk(skb, NULL, RTM_DELACTION, a); + if (0 > err ) { + goto rtattr_failure; + } + + x->rta_len = skb->tail - (u8 *) x; + + nlh->nlmsg_len = skb->tail - b; + nlh->nlmsg_flags |= NLM_F_ROOT; + kfree(a); + err = rtnetlink_send(skb, pid, RTMGRP_TC, n->nlmsg_flags&NLM_F_ECHO); + if (err > 0) + return 0; + + return err; + + +rtattr_failure: +nlmsg_failure: +err_out: + kfree_skb(skb); + kfree(a); + return err; +} + +int tca_action_gd(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int event ) +{ + + int s = 0; + int i, ret = 0; + struct tc_action *act = NULL; + struct rtattr *tb[TCA_ACT_MAX_PRIO+1]; + struct tc_action *a = NULL, *a_s = NULL; + + if (event != RTM_GETACTION && event != RTM_DELACTION) + ret = -EINVAL; + + if (rtattr_parse(tb, TCA_ACT_MAX_PRIO, RTA_DATA(rta), RTA_PAYLOAD(rta))<0) { + ret = -EINVAL; + goto nlmsg_failure; + } + + if (event == RTM_DELACTION && n->nlmsg_flags&NLM_F_ROOT) { + if (NULL != tb[0] && NULL == tb[1]) { + return tca_action_flush(tb[0],n,pid); + } + } + + for (i=0; i < TCA_ACT_MAX_PRIO ; i++) { + + if (NULL == tb[i]) + break; + + act = create_a(i+1); + if (NULL != a && a != act) { + a->next = act; + a = act; + } else { + a = act; + } + + if (!s) { + s = 1; + a_s = a; + } + + ret = tcf_action_get_1(tb[i],act,n,pid); + if (ret < 0) { + printk("tcf_action_get: failed to get! \n"); + ret = -EINVAL; + goto rtattr_failure; + } + + } + + + if (RTM_GETACTION == event) { + ret = act_get_notify(pid, n, a_s, event); + } else { /* delete */ + + struct sk_buff *skb; + + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); + if (!skb) { + ret = -ENOBUFS; + goto nlmsg_failure; + } + + if (tca_get_fill(skb, a_s, pid, n->nlmsg_seq, 0, event, 0 , 1) <= 0) { + kfree_skb(skb); + ret = -EINVAL; + goto nlmsg_failure; + } + + /* now do the delete */ + tcf_action_destroy(a_s, 0); + + ret = rtnetlink_send(skb, pid, RTMGRP_TC, n->nlmsg_flags&NLM_F_ECHO); + if (ret > 0) + return 0; + return ret; + } +rtattr_failure: +nlmsg_failure: + cleanup_a(a_s); + return ret; +} + + +int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event, unsigned flags) +{ + struct tcamsg *t; + struct nlmsghdr *nlh; + struct sk_buff *skb; + struct rtattr *x; + unsigned char *b; + + + int err = 0; + + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); + if (!skb) + return -ENOBUFS; + + b = (unsigned char *)skb->tail; + + nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*t)); + nlh->nlmsg_flags = flags; + t = NLMSG_DATA(nlh); + t->tca_family = AF_UNSPEC; + + x = (struct rtattr*) skb->tail; + RTA_PUT(skb, TCA_ACT_TAB, 0, NULL); + + if (0 > tcf_action_dump(skb, a, 0, 0)) { + goto rtattr_failure; + } + + x->rta_len = skb->tail - (u8*)x; + + nlh->nlmsg_len = skb->tail - b; + NETLINK_CB(skb).dst_groups = RTMGRP_TC; + + err = rtnetlink_send(skb, pid, RTMGRP_TC, flags&NLM_F_ECHO); + if (err > 0) + err = 0; + + return err; + +rtattr_failure: +nlmsg_failure: + skb_trim(skb, b - skb->data); + return -1; +} + + +int tcf_action_add(struct rtattr *rta, struct nlmsghdr *n, u32 pid, int ovr ) +{ + int ret = 0; + struct tc_action *act = NULL; + struct tc_action *a = NULL; + u32 seq = n->nlmsg_seq; + + act = kmalloc(sizeof(*act),GFP_KERNEL); + if (NULL == act) + return -ENOMEM; + + ret = tcf_action_init(rta, NULL,act,NULL,ovr,0); + /* NOTE: We have an all-or-none model + * This means that of any of the actions fail + * to update then all are undone. + * */ + if (0 > ret) { + tcf_action_destroy(act, 0); + goto done; + } + + /* dump then free all the actions after update; inserted policy + * stays intact + * */ + ret = tcf_add_notify(act, pid, seq, RTM_NEWACTION, n->nlmsg_flags); + for (a = act; act; a = act) { + if (a) { + act = act->next; + a->ops = NULL; + a->priv = NULL; + kfree(a); + } else { + printk("tcf_action_add: BUG? empty action\n"); + } + } +done: + + return ret; +} + +static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg) +{ + struct rtattr **tca = arg; + u32 pid = skb ? NETLINK_CB(skb).pid : 0; + + int ret = 0, ovr = 0; + + if (NULL == tca[TCA_ACT_TAB-1]) { + printk("tc_ctl_action: received NO action attribs\n"); + return -EINVAL; + } + + /* n->nlmsg_flags&NLM_F_CREATE + * */ + switch (n->nlmsg_type) { + case RTM_NEWACTION: + /* we are going to assume all other flags + * imply create only if it doesnt exist + * Note that CREATE | EXCL implies that + * but since we want avoid ambiguity (eg when flags + * is zero) then just set this + */ + if (n->nlmsg_flags&NLM_F_REPLACE) { + ovr = 1; + } + ret = tcf_action_add(tca[TCA_ACT_TAB-1], n, pid, ovr); + break; + case RTM_DELACTION: + ret = tca_action_gd(tca[TCA_ACT_TAB-1], n, pid,RTM_DELACTION); + break; + case RTM_GETACTION: + ret = tca_action_gd(tca[TCA_ACT_TAB-1], n, pid,RTM_GETACTION); + break; + default: + printk(" Unknown cmd was detected\n"); + break; + } + + return ret; +} + +char * +find_dump_kind(struct nlmsghdr *n) +{ + struct rtattr *tb1, *tb2[TCA_ACT_MAX_PRIO+1]; + struct rtattr *tb[TCA_ACT_MAX_PRIO + 1]; + struct rtattr *rta[TCAA_MAX + 1]; + struct rtattr *kind = NULL; + int min_len = NLMSG_LENGTH(sizeof (struct tcamsg)); + + int attrlen = n->nlmsg_len - NLMSG_ALIGN(min_len); + struct rtattr *attr = (void *) n + NLMSG_ALIGN(min_len); + + if (rtattr_parse(rta, TCAA_MAX, attr, attrlen) < 0) + return NULL; + tb1 = rta[TCA_ACT_TAB - 1]; + if (NULL == tb1) { + return NULL; + } + + if (rtattr_parse(tb, TCA_ACT_MAX_PRIO, RTA_DATA(tb1), NLMSG_ALIGN(RTA_PAYLOAD(tb1))) < 0) + return NULL; + if (NULL == tb[0]) + return NULL; + + if (rtattr_parse(tb2, TCA_ACT_MAX, RTA_DATA(tb[0]), RTA_PAYLOAD(tb[0]))<0) + return NULL; + kind = tb2[TCA_ACT_KIND-1]; + + return (char *) RTA_DATA(kind); +} + +static int +tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct nlmsghdr *nlh; + unsigned char *b = skb->tail; + struct rtattr *x; + struct tc_action_ops *a_o; + struct tc_action a; + int ret = 0; + + struct tcamsg *t = (struct tcamsg *) NLMSG_DATA(cb->nlh); + char *kind = find_dump_kind(cb->nlh); + if (NULL == kind) { + printk("tc_dump_action: action bad kind\n"); + return 0; + } + + a_o = tc_lookup_action_n(kind); + +#ifdef CONFIG_KMOD + if (NULL == a_o) { + DPRINTK("tc_dump_action: trying to load module %s\n", kind); + request_module(kind); + a_o = tc_lookup_action_n(kind); + } +#endif + if (NULL == a_o) { + printk("failed to find %s\n", kind); + return 0; + } + + memset(&a,0,sizeof(struct tc_action)); + a.ops = a_o; + + if (NULL == a_o->walk) { + printk("tc_dump_action: %s !capable of dumping table\n",kind); + goto rtattr_failure; + } + + nlh = NLMSG_PUT(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, cb->nlh->nlmsg_type, sizeof (*t)); + t = NLMSG_DATA(nlh); + t->tca_family = AF_UNSPEC; + + x = (struct rtattr *) skb->tail; + RTA_PUT(skb, TCA_ACT_TAB, 0, NULL); + + ret = a_o->walk(skb, cb, RTM_GETACTION, &a); + if (0 > ret ) { + goto rtattr_failure; + } + + if (ret > 0) { + x->rta_len = skb->tail - (u8 *) x; + ret = skb->len; + } else { + skb_trim(skb, (u8*)x - skb->data); + } + + nlh->nlmsg_len = skb->tail - b; + if (NETLINK_CB(cb->skb).pid && ret) + nlh->nlmsg_flags |= NLM_F_MULTI; + return skb->len; + +rtattr_failure: +nlmsg_failure: + skb_trim(skb, b - skb->data); + return skb->len; +} + +static int __init tc_action_init(void) +{ + struct rtnetlink_link *link_p = rtnetlink_links[PF_UNSPEC]; + + if (link_p) { + link_p[RTM_NEWACTION-RTM_BASE].doit = tc_ctl_action; + link_p[RTM_DELACTION-RTM_BASE].doit = tc_ctl_action; + link_p[RTM_GETACTION-RTM_BASE].doit = tc_ctl_action; + link_p[RTM_GETACTION-RTM_BASE].dumpit = tc_dump_action; + } + + printk("TC classifier action (bugs to netdev@oss.sgi.com cc hadi@cyberus.ca)\n"); + return 0; +} + +subsys_initcall(tc_action_init); + +EXPORT_SYMBOL(tcf_register_action); +EXPORT_SYMBOL(tcf_unregister_action); +EXPORT_SYMBOL(tcf_action_init_1); +EXPORT_SYMBOL(tcf_action_init); +EXPORT_SYMBOL(tcf_action_destroy); +EXPORT_SYMBOL(tcf_action_exec); +EXPORT_SYMBOL(tcf_action_copy_stats); +EXPORT_SYMBOL(tcf_action_dump); +EXPORT_SYMBOL(tcf_action_dump_1); +EXPORT_SYMBOL(tcf_action_dump_old); diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index a48b75d54fb9..5d034cc0d874 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -11,6 +11,7 @@ * Changes: * * Eduardo J. Blanco :990222: kmod support + * */ #include @@ -36,6 +37,12 @@ #include #include +#if 0 /* control */ +#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format,args...) +#endif + /* The list of all installed classifier types */ static struct tcf_proto_ops *tcf_proto_base; @@ -132,7 +139,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg) struct tcf_proto_ops *tp_ops; struct Qdisc_class_ops *cops; unsigned long cl = 0; - unsigned long fh; + unsigned long fh, fh_s; int err; if (prio == 0) { @@ -238,7 +245,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg) } else if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], tp->ops->kind)) goto errout; - fh = tp->ops->get(tp, t->tcm_handle); + fh_s = fh = tp->ops->get(tp, t->tcm_handle); if (fh == 0) { if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) { @@ -247,6 +254,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg) *back = tp->next; spin_unlock_bh(&dev->queue_lock); write_unlock(&qdisc_tree_lock); + tfilter_notify(skb, n, tp, fh_s, RTM_DELTFILTER); tcf_destroy(tp); err = 0; goto errout; @@ -264,6 +272,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg) break; case RTM_DELTFILTER: err = tp->ops->delete(tp, fh); + if (err == 0) + tfilter_notify(skb, n, tp, fh_s, RTM_DELTFILTER); goto errout; case RTM_GETTFILTER: err = tfilter_notify(skb, n, tp, fh, RTM_NEWTFILTER); @@ -298,11 +308,14 @@ tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp, unsigned long fh, tcm->tcm_family = AF_UNSPEC; tcm->tcm_ifindex = tp->q->dev->ifindex; tcm->tcm_parent = tp->classid; - tcm->tcm_handle = 0; tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol); RTA_PUT(skb, TCA_KIND, IFNAMSIZ, tp->ops->kind); - if (tp->ops->dump && tp->ops->dump(tp, fh, skb, tcm) < 0) - goto rtattr_failure; + tcm->tcm_handle = fh; + if (RTM_DELTFILTER != event) { + tcm->tcm_handle = 0; + if (tp->ops->dump && tp->ops->dump(tp, fh, skb, tcm) < 0) + goto rtattr_failure; + } nlh->nlmsg_len = skb->tail - b; return skb->len; diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index 5b614b63aa66..6e0baf28e5ab 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c @@ -11,6 +11,11 @@ * Changes: * Karlis Peisenieks : 990415 : fw_walk off by one * Karlis Peisenieks : 990415 : fw_delete killed all the filter (and kernel). + * Alex : 2004xxyy: Added Action extension + * + * JHS: We should remove the CONFIG_NET_CLS_IND from here + * eventually when the meta match extension is made available + * */ #include @@ -50,9 +55,16 @@ struct fw_filter struct fw_filter *next; u32 id; struct tcf_result res; +#ifdef CONFIG_NET_CLS_ACT + struct tc_action *action; +#ifdef CONFIG_NET_CLS_IND + char indev[IFNAMSIZ]; +#endif +#else #ifdef CONFIG_NET_CLS_POLICE struct tcf_police *police; #endif +#endif }; static __inline__ int fw_hash(u32 handle) @@ -77,9 +89,28 @@ static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp, for (f=head->ht[fw_hash(id)]; f; f=f->next) { if (f->id == id) { *res = f->res; +#ifdef CONFIG_NET_CLS_ACT +#ifdef CONFIG_NET_CLS_IND + if (0 != f->indev[0]) { + if (NULL == skb->input_dev) { + continue; + } else { + if (0 != strcmp(f->indev, skb->input_dev->name)) { + continue; + } + } + } +#endif + if (f->action) { + int pol_res = tcf_action_exec(skb, f->action); + if (pol_res >= 0) + return pol_res; + } else +#else #ifdef CONFIG_NET_CLS_POLICE if (f->police) return tcf_police(skb, f->police); +#endif #endif return 0; } @@ -136,9 +167,16 @@ static void fw_destroy(struct tcf_proto *tp) if ((cl = __cls_set_class(&f->res.class, 0)) != 0) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); +#ifdef CONFIG_NET_CLS_ACT + if (f->action) { + tcf_action_destroy(f->action,TCA_ACT_UNBIND); + } +#else #ifdef CONFIG_NET_CLS_POLICE - tcf_police_release(f->police); + tcf_police_release(f->police,TCA_ACT_UNBIND); +#endif #endif + kfree(f); } } @@ -164,8 +202,14 @@ static int fw_delete(struct tcf_proto *tp, unsigned long arg) if ((cl = cls_set_class(tp, &f->res.class, 0)) != 0) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); +#ifdef CONFIG_NET_CLS_ACT + if (f->action) { + tcf_action_destroy(f->action,TCA_ACT_UNBIND); + } +#else #ifdef CONFIG_NET_CLS_POLICE - tcf_police_release(f->police); + tcf_police_release(f->police,TCA_ACT_UNBIND); +#endif #endif kfree(f); return 0; @@ -185,6 +229,11 @@ static int fw_change(struct tcf_proto *tp, unsigned long base, struct rtattr *opt = tca[TCA_OPTIONS-1]; struct rtattr *tb[TCA_FW_MAX]; int err; +#ifdef CONFIG_NET_CLS_ACT + struct tc_action *act = NULL; + int ret; +#endif + if (!opt) return handle ? -EINVAL : 0; @@ -206,6 +255,58 @@ static int fw_change(struct tcf_proto *tp, unsigned long base, if (cl) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); } +#ifdef CONFIG_NET_CLS_ACT + if (tb[TCA_FW_POLICE-1]) { + act = kmalloc(sizeof(*act),GFP_KERNEL); + if (NULL == act) + return -ENOMEM; + + memset(act,0,sizeof(*act)); + ret = tcf_action_init_1(tb[TCA_FW_POLICE-1], tca[TCA_RATE-1] ,act,"police",TCA_ACT_NOREPLACE,TCA_ACT_BIND); + if (0 > ret){ + tcf_action_destroy(act,TCA_ACT_UNBIND); + return ret; + } + act->type = TCA_OLD_COMPAT; + + sch_tree_lock(tp->q); + act = xchg(&f->action, act); + sch_tree_unlock(tp->q); + + tcf_action_destroy(act,TCA_ACT_UNBIND); + + } + + if(tb[TCA_FW_ACT-1]) { + act = kmalloc(sizeof(*act),GFP_KERNEL); + if (NULL == act) + return -ENOMEM; + memset(act,0,sizeof(*act)); + ret = tcf_action_init(tb[TCA_FW_ACT-1], tca[TCA_RATE-1],act,NULL, TCA_ACT_NOREPLACE,TCA_ACT_BIND); + if (0 > ret) { + tcf_action_destroy(act,TCA_ACT_UNBIND); + return ret; + } + + sch_tree_lock(tp->q); + act = xchg(&f->action, act); + sch_tree_unlock(tp->q); + + tcf_action_destroy(act,TCA_ACT_UNBIND); + } +#ifdef CONFIG_NET_CLS_IND + if(tb[TCA_FW_INDEV-1]) { + struct rtattr *idev = tb[TCA_FW_INDEV-1]; + if (RTA_PAYLOAD(idev) >= IFNAMSIZ) { + printk("cls_fw: bad indev name %s\n",(char*)RTA_DATA(idev)); + err = -EINVAL; + goto errout; + } + memset(f->indev,0,IFNAMSIZ); + sprintf(f->indev, "%s", (char*)RTA_DATA(idev)); + } +#endif +#else /* only POLICE defined */ #ifdef CONFIG_NET_CLS_POLICE if (tb[TCA_FW_POLICE-1]) { struct tcf_police *police = tcf_police_locate(tb[TCA_FW_POLICE-1], tca[TCA_RATE-1]); @@ -214,8 +315,9 @@ static int fw_change(struct tcf_proto *tp, unsigned long base, police = xchg(&f->police, police); tcf_tree_unlock(tp); - tcf_police_release(police); + tcf_police_release(police,TCA_ACT_UNBIND); } +#endif #endif return 0; } @@ -249,9 +351,36 @@ static int fw_change(struct tcf_proto *tp, unsigned long base, cls_set_class(tp, &f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid)); } +#ifdef CONFIG_NET_CLS_ACT + if(tb[TCA_FW_ACT-1]) { + act = kmalloc(sizeof(*act),GFP_KERNEL); + if (NULL == act) + return -ENOMEM; + memset(act,0,sizeof(*act)); + ret = tcf_action_init(tb[TCA_FW_ACT-1], tca[TCA_RATE-1],act,NULL,TCA_ACT_NOREPLACE,TCA_ACT_BIND); + if (0 > ret) { + tcf_action_destroy(act,TCA_ACT_UNBIND); + return ret; + } + f->action= act; + } +#ifdef CONFIG_NET_CLS_IND + if(tb[TCA_FW_INDEV-1]) { + struct rtattr *idev = tb[TCA_FW_INDEV-1]; + if (RTA_PAYLOAD(idev) >= IFNAMSIZ) { + printk("cls_fw: bad indev name %s\n",(char*)RTA_DATA(idev)); + err = -EINVAL; + goto errout; + } + memset(f->indev,0,IFNAMSIZ); + sprintf(f->indev, "%s", (char*)RTA_DATA(idev)); + } +#endif +#else #ifdef CONFIG_NET_CLS_POLICE if (tb[TCA_FW_POLICE-1]) f->police = tcf_police_locate(tb[TCA_FW_POLICE-1], tca[TCA_RATE-1]); +#endif #endif f->next = head->ht[fw_hash(handle)]; @@ -309,8 +438,12 @@ static int fw_dump(struct tcf_proto *tp, unsigned long fh, t->tcm_handle = f->id; if (!f->res.classid +#ifdef CONFIG_NET_CLS_ACT + && !f->action +#else #ifdef CONFIG_NET_CLS_POLICE && !f->police +#endif #endif ) return skb->len; @@ -320,6 +453,36 @@ static int fw_dump(struct tcf_proto *tp, unsigned long fh, if (f->res.classid) RTA_PUT(skb, TCA_FW_CLASSID, 4, &f->res.classid); +#ifdef CONFIG_NET_CLS_ACT + /* again for backward compatible mode - we want + * to work with both old and new modes of entering + * tc data even if iproute2 was newer - jhs + */ + if (f->action) { + struct rtattr * p_rta = (struct rtattr*)skb->tail; + + if (f->action->type != TCA_OLD_COMPAT) { + RTA_PUT(skb, TCA_FW_ACT, 0, NULL); + if (tcf_action_dump(skb,f->action,0,0) < 0) { + goto rtattr_failure; + } + } else { + RTA_PUT(skb, TCA_FW_POLICE, 0, NULL); + if (tcf_action_dump_old(skb,f->action,0,0) < 0) { + goto rtattr_failure; + } + } + + p_rta->rta_len = skb->tail - (u8*)p_rta; + } +#ifdef CONFIG_NET_CLS_IND + if(strlen(f->indev)) { + struct rtattr * p_rta = (struct rtattr*)skb->tail; + RTA_PUT(skb, TCA_FW_INDEV, IFNAMSIZ, f->indev); + p_rta->rta_len = skb->tail - (u8*)p_rta; + } +#endif +#else #ifdef CONFIG_NET_CLS_POLICE if (f->police) { struct rtattr * p_rta = (struct rtattr*)skb->tail; @@ -331,14 +494,22 @@ static int fw_dump(struct tcf_proto *tp, unsigned long fh, p_rta->rta_len = skb->tail - (u8*)p_rta; } +#endif #endif rta->rta_len = skb->tail - b; +#ifdef CONFIG_NET_CLS_ACT + if (f->action && f->action->type == TCA_OLD_COMPAT) { + if (tcf_action_copy_stats(skb,f->action)) + goto rtattr_failure; + } +#else #ifdef CONFIG_NET_CLS_POLICE if (f->police) { if (qdisc_copy_stats(skb, &f->police->stats)) goto rtattr_failure; } +#endif #endif return skb->len; diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index 4c09012edbce..d4dada10e6ef 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c @@ -297,7 +297,7 @@ static void route4_destroy(struct tcf_proto *tp) if ((cl = __cls_set_class(&f->res.class, 0)) != 0) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); #ifdef CONFIG_NET_CLS_POLICE - tcf_police_release(f->police); + tcf_police_release(f->police,TCA_ACT_UNBIND); #endif kfree(f); } @@ -336,7 +336,7 @@ static int route4_delete(struct tcf_proto *tp, unsigned long arg) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); #ifdef CONFIG_NET_CLS_POLICE - tcf_police_release(f->police); + tcf_police_release(f->police,TCA_ACT_UNBIND); #endif kfree(f); @@ -398,7 +398,7 @@ static int route4_change(struct tcf_proto *tp, unsigned long base, police = xchg(&f->police, police); tcf_tree_unlock(tp); - tcf_police_release(police); + tcf_police_release(police,TCA_ACT_UNBIND); } #endif return 0; diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h index 85e028d84757..8ebaa2787d9a 100644 --- a/net/sched/cls_rsvp.h +++ b/net/sched/cls_rsvp.h @@ -278,7 +278,7 @@ static void rsvp_destroy(struct tcf_proto *tp) if ((cl = __cls_set_class(&f->res.class, 0)) != 0) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); #ifdef CONFIG_NET_CLS_POLICE - tcf_police_release(f->police); + tcf_police_release(f->police,TCA_ACT_UNBIND); #endif kfree(f); } @@ -310,7 +310,7 @@ static int rsvp_delete(struct tcf_proto *tp, unsigned long arg) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); #ifdef CONFIG_NET_CLS_POLICE - tcf_police_release(f->police); + tcf_police_release(f->police,TCA_ACT_UNBIND); #endif kfree(f); @@ -452,7 +452,7 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base, police = xchg(&f->police, police); tcf_tree_unlock(tp); - tcf_police_release(police); + tcf_police_release(police,TCA_ACT_UNBIND); } #endif return 0; diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index adbc77dd2318..c696fcf8f166 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@ -190,7 +190,7 @@ found: if (cl) tp->q->ops->cl_ops->unbind_tcf(tp->q,cl); #ifdef CONFIG_NET_CLS_POLICE - tcf_police_release(r->police); + tcf_police_release(r->police, TCA_ACT_UNBIND); #endif if (f) kfree(f); @@ -333,7 +333,7 @@ static int tcindex_change(struct tcf_proto *tp,unsigned long base,u32 handle, tcf_tree_lock(tp); police = xchg(&r->police,police); tcf_tree_unlock(tp); - tcf_police_release(police); + tcf_police_release(police,TCA_ACT_UNBIND); } #endif if (r != &new_filter_result) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 938d88744b63..7ea20b622fc8 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -23,6 +23,10 @@ * It is especially useful for link sharing combined with QoS; * pure RSVP doesn't need such a general approach and can use * much simpler (and faster) schemes, sort of cls_rsvp.c. + * + * JHS: We should remove the CONFIG_NET_CLS_IND from here + * eventually when the meta match extension is made available + * */ #include @@ -58,8 +62,15 @@ struct tc_u_knode struct tc_u_knode *next; u32 handle; struct tc_u_hnode *ht_up; +#ifdef CONFIG_NET_CLS_ACT + struct tc_action *action; +#ifdef CONFIG_NET_CLS_IND + char indev[IFNAMSIZ]; +#endif +#else #ifdef CONFIG_NET_CLS_POLICE struct tcf_police *police; +#endif #endif struct tcf_result res; struct tc_u_hnode *ht_down; @@ -90,10 +101,12 @@ static struct tc_u_common *u32_list; static __inline__ unsigned u32_hash_fold(u32 key, struct tc_u32_sel *sel) { - unsigned h = key & sel->hmask; + unsigned h = (key & sel->hmask)>>sel->fshift; + /* h ^= h>>16; h ^= h>>8; + */ return h; } @@ -119,22 +132,61 @@ next_knode: if (n) { struct tc_u32_key *key = n->sel.keys; +#ifdef CONFIG_CLS_U32_PERF + n->sel.rcnt +=1; +#endif for (i = n->sel.nkeys; i>0; i--, key++) { + if ((*(u32*)(ptr+key->off+(off2&key->offmask))^key->val)&key->mask) { n = n->next; goto next_knode; } +#ifdef CONFIG_CLS_U32_PERF + key->kcnt +=1; +#endif } if (n->ht_down == NULL) { check_terminal: if (n->sel.flags&TC_U32_TERMINAL) { + *res = n->res; +#ifdef CONFIG_NET_CLS_ACT +#ifdef CONFIG_NET_CLS_IND + /* yes, i know it sucks but the feature is + ** optional dammit! - JHS */ + if (0 != n->indev[0]) { + if (NULL == skb->input_dev) { + n = n->next; + goto next_knode; + } else { + if (0 != strcmp(n->indev, skb->input_dev->name)) { + n = n->next; + goto next_knode; + } + } + } +#endif +#ifdef CONFIG_CLS_U32_PERF + n->sel.rhit +=1; +#endif + if (n->action) { + int pol_res = tcf_action_exec(skb, n->action); + if (skb->tc_classid > 0) { + res->classid = skb->tc_classid; + skb->tc_classid = 0; + } + + if (pol_res >= 0) + return pol_res; + } else +#else #ifdef CONFIG_NET_CLS_POLICE if (n->police) { int pol_res = tcf_police(skb, n->police); if (pol_res >= 0) return pol_res; } else +#endif #endif return 0; } @@ -298,8 +350,14 @@ static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n) if ((cl = __cls_set_class(&n->res.class, 0)) != 0) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); +#ifdef CONFIG_NET_CLS_ACT + if (n->action) { + tcf_action_destroy(n->action, TCA_ACT_UNBIND); + } +#else #ifdef CONFIG_NET_CLS_POLICE - tcf_police_release(n->police); + tcf_police_release(n->police, TCA_ACT_UNBIND); +#endif #endif if (n->ht_down) n->ht_down->refcnt--; @@ -438,6 +496,10 @@ static int u32_set_parms(struct Qdisc *q, unsigned long base, struct tc_u_knode *n, struct rtattr **tb, struct rtattr *est) { +#ifdef CONFIG_NET_CLS_ACT + struct tc_action *act = NULL; + int ret; +#endif if (tb[TCA_U32_LINK-1]) { u32 handle = *(u32*)RTA_DATA(tb[TCA_U32_LINK-1]); struct tc_u_hnode *ht_down = NULL; @@ -470,17 +532,73 @@ static int u32_set_parms(struct Qdisc *q, unsigned long base, if (cl) q->ops->cl_ops->unbind_tcf(q, cl); } +#ifdef CONFIG_NET_CLS_ACT + /*backward compatibility */ + if (tb[TCA_U32_POLICE-1]) + { + act = kmalloc(sizeof(*act),GFP_KERNEL); + if (NULL == act) + return -ENOMEM; + + memset(act,0,sizeof(*act)); + ret = tcf_action_init_1(tb[TCA_U32_POLICE-1], est,act,"police", TCA_ACT_NOREPLACE, TCA_ACT_BIND); + if (0 > ret){ + tcf_action_destroy(act, TCA_ACT_UNBIND); + return ret; + } + act->type = TCA_OLD_COMPAT; + + sch_tree_lock(q); + act = xchg(&n->action, act); + sch_tree_unlock(q); + + tcf_action_destroy(act, TCA_ACT_UNBIND); + + } + + if(tb[TCA_U32_ACT-1]) { + act = kmalloc(sizeof(*act),GFP_KERNEL); + if (NULL == act) + return -ENOMEM; + memset(act,0,sizeof(*act)); + ret = tcf_action_init(tb[TCA_U32_ACT-1], est,act,NULL,TCA_ACT_NOREPLACE, TCA_ACT_BIND); + if (0 > ret) { + tcf_action_destroy(act, TCA_ACT_UNBIND); + return ret; + } + + sch_tree_lock(q); + act = xchg(&n->action, act); + sch_tree_unlock(q); + + tcf_action_destroy(act, TCA_ACT_UNBIND); + } + +#ifdef CONFIG_NET_CLS_IND + n->indev[0] = 0; + if(tb[TCA_U32_INDEV-1]) { + struct rtattr *input_dev = tb[TCA_U32_INDEV-1]; + if (RTA_PAYLOAD(input_dev) >= IFNAMSIZ) { + printk("cls_u32: bad indev name %s\n",(char*)RTA_DATA(input_dev)); + /* should we clear state first? */ + return -EINVAL; + } + sprintf(n->indev, "%s", (char*)RTA_DATA(input_dev)); + } +#endif + +#else #ifdef CONFIG_NET_CLS_POLICE if (tb[TCA_U32_POLICE-1]) { struct tcf_police *police = tcf_police_locate(tb[TCA_U32_POLICE-1], est); - sch_tree_lock(q); police = xchg(&n->police, police); sch_tree_unlock(q); - - tcf_police_release(police); + tcf_police_release(police, TCA_ACT_UNBIND); } #endif +#endif + return 0; } @@ -656,26 +774,79 @@ static int u32_dump(struct tcf_proto *tp, unsigned long fh, RTA_PUT(skb, TCA_U32_CLASSID, 4, &n->res.classid); if (n->ht_down) RTA_PUT(skb, TCA_U32_LINK, 4, &n->ht_down->handle); +#ifdef CONFIG_CLS_U32_PERF2 + printk("fh %x cnt %lu hit %lu\n",n->handle,n->sel.rcnt,n->sel.rhit); + n->sel.rcnt = n->sel.rhit = 0; + /* dump key cnt */ + { + int i = 0; + struct tc_u32_key *key = n->sel.keys; + for (i = n->sel.nkeys; i>0; i--, key++) { + printk("\t key%d success %lu\n",i,key->kcnt); + key->cnt = 0; + } + } + +#endif +#ifdef CONFIG_NET_CLS_ACT + /* again for backward compatible mode - we want + * to work with both old and new modes of entering + * tc data even if iproute2 was newer - jhs + */ + if (n->action) { + struct rtattr * p_rta = (struct rtattr*)skb->tail; + + if (n->action->type != TCA_OLD_COMPAT) { + RTA_PUT(skb, TCA_U32_ACT, 0, NULL); + if (tcf_action_dump(skb,n->action, 0, 0) < 0) { + goto rtattr_failure; + } + } else { + RTA_PUT(skb, TCA_U32_POLICE, 0, NULL); + if (tcf_action_dump_old(skb,n->action,0,0) < 0) { + goto rtattr_failure; + } + } + + p_rta->rta_len = skb->tail - (u8*)p_rta; + } +#ifdef CONFIG_NET_CLS_IND + if(strlen(n->indev)) { + struct rtattr * p_rta = (struct rtattr*)skb->tail; + RTA_PUT(skb, TCA_U32_INDEV, IFNAMSIZ, n->indev); + p_rta->rta_len = skb->tail - (u8*)p_rta; + } +#endif + +#else #ifdef CONFIG_NET_CLS_POLICE if (n->police) { struct rtattr * p_rta = (struct rtattr*)skb->tail; - RTA_PUT(skb, TCA_U32_POLICE, 0, NULL); - + if (tcf_police_dump(skb, n->police) < 0) goto rtattr_failure; p_rta->rta_len = skb->tail - (u8*)p_rta; + } +#endif #endif } rta->rta_len = skb->tail - b; +#ifdef CONFIG_NET_CLS_ACT + if (TC_U32_KEY(n->handle) && n->action && n->action->type == TCA_OLD_COMPAT) { + if (tcf_action_copy_stats(skb,n->action)) + goto rtattr_failure; + } +#else #ifdef CONFIG_NET_CLS_POLICE if (TC_U32_KEY(n->handle) && n->police) { - if (qdisc_copy_stats(skb, &n->police->stats)) + if (qdisc_copy_stats(skb,&n->police->stats)) goto rtattr_failure; } +#endif #endif return skb->len; diff --git a/net/sched/police.c b/net/sched/police.c index e92a07620ffd..14ccbae43858 100644 --- a/net/sched/police.c +++ b/net/sched/police.c @@ -7,6 +7,7 @@ * 2 of the License, or (at your option) any later version. * * Authors: Alexey Kuznetsov, + * J Hadi Salim (action changes) */ #include @@ -26,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -33,9 +35,13 @@ #define L2T(p,L) ((p)->R_tab->data[(L)>>(p)->R_tab->rate.cell_log]) #define L2T_P(p,L) ((p)->P_tab->data[(L)>>(p)->P_tab->rate.cell_log]) +#define PRIV(a) ((struct tcf_police *) (a)->priv) +/* use generic hash table */ +#define MY_TAB_SIZE 16 +#define MY_TAB_MASK 15 static u32 idx_gen; -static struct tcf_police *tcf_police_ht[16]; +static struct tcf_police *tcf_police_ht[MY_TAB_SIZE]; /* Policer hash table lock */ static rwlock_t police_lock = RW_LOCK_UNLOCKED; @@ -59,6 +65,68 @@ static __inline__ struct tcf_police * tcf_police_lookup(u32 index) return p; } +#ifdef CONFIG_NET_CLS_ACT +static __inline__ int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb, int type, struct tc_action *a) +{ + struct tcf_police *p; + int err =0, index = -1,i= 0, s_i = 0, n_i = 0; + struct rtattr *r ; + + read_lock(&police_lock); + + s_i = cb->args[0]; + + for (i = 0; i < MY_TAB_SIZE; i++) { + p = tcf_police_ht[tcf_police_hash(i)]; + + for (; p; p = p->next) { + index++; + if (index < s_i) + continue; + a->priv = p; + a->order = index; + r = (struct rtattr*) skb->tail; + RTA_PUT(skb, a->order, 0, NULL); + if (type == RTM_DELACTION) + err = tcf_action_dump_1(skb, a, 0, 1); + else + err = tcf_action_dump_1(skb, a, 0, 0); + if (0 > err) { + index--; + skb_trim(skb, (u8*)r - skb->data); + goto done; + } + r->rta_len = skb->tail - (u8*)r; + n_i++; + } + } +done: + read_unlock(&police_lock); + if (n_i) + cb->args[0] += n_i; + return n_i; + +rtattr_failure: + skb_trim(skb, (u8*)r - skb->data); + goto done; +} + +static inline int +tcf_hash_search(struct tc_action *a, u32 index) +{ + struct tcf_police *p = tcf_police_lookup(index); + + if (p != NULL) { + a->priv = p; + return 1; + } else { + return 0; + } +} + + +#endif + static __inline__ u32 tcf_police_new_index(void) { do { @@ -94,6 +162,264 @@ void tcf_police_destroy(struct tcf_police *p) BUG_TRAP(0); } +#ifdef CONFIG_NET_CLS_ACT +int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_action *a, int ovr, int bind) +{ + unsigned h; + struct rtattr *tb[TCA_POLICE_MAX]; + struct tc_police *parm; + struct tcf_police *p; + + if (NULL == a) { + if (net_ratelimit()) + printk("BUG: tcf_police_locate called with NULL params\n"); + return -1; + } + + if (rtattr_parse(tb, TCA_POLICE_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) < 0) + return -1; + + if (tb[TCA_POLICE_TBF-1] == NULL) + return -1; + + parm = RTA_DATA(tb[TCA_POLICE_TBF-1]); + + if (parm->index && (p = tcf_police_lookup(parm->index)) != NULL) { + a->priv = (void *)p; + spin_lock(&p->lock); + if (bind) { + p->bindcnt += 1; + p->refcnt += 1; + } + if (ovr) { + goto override; + } + spin_unlock(&p->lock); + return 1; + } + + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (p == NULL) + return -1; + + memset(p, 0, sizeof(*p)); + MOD_INC_USE_COUNT; + p->refcnt = 1; + spin_lock_init(&p->lock); + p->stats.lock = &p->lock; + if (bind) + p->bindcnt = 1; +override: + if (parm->rate.rate) { + if ((p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1])) == NULL) + goto failure; + if (parm->peakrate.rate && + (p->P_tab = qdisc_get_rtab(&parm->peakrate, tb[TCA_POLICE_PEAKRATE-1])) == NULL) + goto failure; + } + if (tb[TCA_POLICE_RESULT-1]) + p->result = *(int*)RTA_DATA(tb[TCA_POLICE_RESULT-1]); +#ifdef CONFIG_NET_ESTIMATOR + if (tb[TCA_POLICE_AVRATE-1]) + p->ewma_rate = *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]); +#endif + p->toks = p->burst = parm->burst; + p->mtu = parm->mtu; + if (p->mtu == 0) { + p->mtu = ~0; + if (p->R_tab) + p->mtu = 255<R_tab->rate.cell_log; + } + if (p->P_tab) + p->ptoks = L2T_P(p, p->mtu); + p->action = parm->action; + + if (ovr) { + spin_unlock(&p->lock); + return 1; + } + PSCHED_GET_TIME(p->t_c); + p->index = parm->index ? : tcf_police_new_index(); +#ifdef CONFIG_NET_ESTIMATOR + if (est) + qdisc_new_estimator(&p->stats, est); +#endif + h = tcf_police_hash(p->index); + write_lock_bh(&police_lock); + p->next = tcf_police_ht[h]; + tcf_police_ht[h] = p; + write_unlock_bh(&police_lock); + + MOD_INC_USE_COUNT; + a->priv = (void *)p; + return 1; + +failure: + if (p->R_tab) + qdisc_put_rtab(p->R_tab); + if (ovr) + spin_unlock(&p->lock); + kfree(p); + return -1; +} + +void tcf_act_police_cleanup(struct tc_action *a, int bind) +{ + struct tcf_police *p; + p = PRIV(a); + if (NULL != p) + tcf_police_release(p, bind); +} + +int tcf_act_police_stats(struct sk_buff *skb, struct tc_action *a) +{ + struct tcf_police *p; + p = PRIV(a); + if (NULL != p) + return qdisc_copy_stats(skb, &p->stats); + + return 1; +} + +int tcf_act_police(struct sk_buff **pskb, struct tc_action *a) +{ + psched_time_t now; + struct sk_buff *skb = *pskb; + struct tcf_police *p; + long toks; + long ptoks = 0; + + p = PRIV(a); + + if (NULL == p) { + printk("BUG: tcf_police called with NULL params\n"); + return -1; + } + + spin_lock(&p->lock); + + p->stats.bytes += skb->len; + p->stats.packets++; + +#ifdef CONFIG_NET_ESTIMATOR + if (p->ewma_rate && p->stats.bps >= p->ewma_rate) { + p->stats.overlimits++; + spin_unlock(&p->lock); + return p->action; + } +#endif + + if (skb->len <= p->mtu) { + if (p->R_tab == NULL) { + spin_unlock(&p->lock); + return p->result; + } + + PSCHED_GET_TIME(now); + + toks = PSCHED_TDIFF_SAFE(now, p->t_c, p->burst, 0); + + if (p->P_tab) { + ptoks = toks + p->ptoks; + if (ptoks > (long)L2T_P(p, p->mtu)) + ptoks = (long)L2T_P(p, p->mtu); + ptoks -= L2T_P(p, skb->len); + } + toks += p->toks; + if (toks > (long)p->burst) + toks = p->burst; + toks -= L2T(p, skb->len); + + if ((toks|ptoks) >= 0) { + p->t_c = now; + p->toks = toks; + p->ptoks = ptoks; + spin_unlock(&p->lock); + return p->result; + } + } + + p->stats.overlimits++; + spin_unlock(&p->lock); + return p->action; +} + +int tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) +{ + unsigned char *b = skb->tail; + struct tc_police opt; + struct tcf_police *p; + + p = PRIV(a); + if (NULL == p) { + printk("BUG: tcf_police_dump called with NULL params\n"); + goto rtattr_failure; + } + + opt.index = p->index; + opt.action = p->action; + opt.mtu = p->mtu; + opt.burst = p->burst; + opt.refcnt = p->refcnt - ref; + opt.bindcnt = p->bindcnt - bind; + if (p->R_tab) + opt.rate = p->R_tab->rate; + else + memset(&opt.rate, 0, sizeof(opt.rate)); + if (p->P_tab) + opt.peakrate = p->P_tab->rate; + else + memset(&opt.peakrate, 0, sizeof(opt.peakrate)); + RTA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt); + if (p->result) + RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int), &p->result); +#ifdef CONFIG_NET_ESTIMATOR + if (p->ewma_rate) + RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &p->ewma_rate); +#endif + return skb->len; + +rtattr_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +MODULE_AUTHOR("Alexey Kuznetsov"); +MODULE_DESCRIPTION("Policing actions"); +MODULE_LICENSE("GPL"); + + +struct tc_action_ops act_police_ops = { + NULL, + "police", + TCA_ACT_POLICE, + TCA_CAP_NONE, + tcf_act_police, + tcf_act_police_stats, + tcf_act_police_dump, + tcf_act_police_cleanup, + tcf_hash_search, + tcf_act_police_locate, + tcf_generic_walker +}; + +static int __init +police_init_module(void) +{ + return tcf_register_action(&act_police_ops); +} + +static void __exit +police_cleanup_module(void) +{ + tcf_unregister_action(&act_police_ops); +} + +module_init(police_init_module); +module_exit(police_cleanup_module); + +#endif + struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) { unsigned h; @@ -111,6 +437,7 @@ struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) if (parm->index && (p = tcf_police_lookup(parm->index)) != NULL) { p->refcnt++; + MOD_INC_USE_COUNT; return p; } @@ -156,6 +483,7 @@ struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) p->next = tcf_police_ht[h]; tcf_police_ht[h] = p; write_unlock_bh(&police_lock); + MOD_INC_USE_COUNT; return p; failure: diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index 37eb5df8f304..3ec741a3b44a 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c @@ -45,7 +45,11 @@ /* Thanks to Doron Oz for this hack */ +#ifndef CONFIG_NET_CLS_ACT +#ifdef CONFIG_NETFILTER static int nf_registered; +#endif +#endif struct ingress_qdisc_data { struct Qdisc *q; @@ -146,27 +150,52 @@ static int ingress_enqueue(struct sk_buff *skb,struct Qdisc *sch) * Unlike normal "enqueue" functions, ingress_enqueue returns a * firewall FW_* code. */ -#ifdef CONFIG_NET_CLS_POLICE +#ifdef CONFIG_NET_CLS_ACT + sch->stats.packets++; + sch->stats.bytes += skb->len; switch (result) { - case TC_POLICE_SHOT: - result = NF_DROP; + case TC_ACT_SHOT: + result = TC_ACT_SHOT; sch->stats.drops++; break; + case TC_ACT_STOLEN: + case TC_ACT_QUEUED: + result = TC_ACT_STOLEN; + break; + case TC_ACT_RECLASSIFY: + case TC_ACT_OK: + case TC_ACT_UNSPEC: + default: + skb->tc_index = TC_H_MIN(res.classid); + result = TC_ACT_OK; + break; + }; +/* backward compat */ +#else +#ifdef CONFIG_NET_CLS_POLICE + switch (result) { + case TC_POLICE_SHOT: + result = NF_DROP; + sch->stats.drops++; + break; case TC_POLICE_RECLASSIFY: /* DSCP remarking here ? */ case TC_POLICE_OK: case TC_POLICE_UNSPEC: default: - sch->stats.packets++; - sch->stats.bytes += skb->len; - result = NF_ACCEPT; - break; + sch->stats.packets++; + sch->stats.bytes += skb->len; + result = NF_ACCEPT; + break; }; + #else + D2PRINTK("Overriding result to ACCEPT\n"); + result = NF_ACCEPT; sch->stats.packets++; sch->stats.bytes += skb->len; +#endif #endif - skb->tc_index = TC_H_MIN(res.classid); return result; } @@ -199,6 +228,8 @@ static unsigned int ingress_drop(struct Qdisc *sch) return 0; } +#ifndef CONFIG_NET_CLS_ACT +#ifdef CONFIG_NETFILTER static unsigned int ing_hook(unsigned int hook, struct sk_buff **pskb, const struct net_device *indev, @@ -240,10 +271,29 @@ static struct nf_hook_ops ing_ops = { .priority = NF_IP_PRI_FILTER + 1, }; +#endif +#endif + int ingress_init(struct Qdisc *sch,struct rtattr *opt) { struct ingress_qdisc_data *p = PRIV(sch); +/* Make sure either netfilter or preferably CLS_ACT is +* compiled in */ +#ifndef CONFIG_NET_CLS_ACT +#ifndef CONFIG_NETFILTER + printk("You MUST compile classifier actions into the kernel\n"); + goto error; +#else + printk("Ingress scheduler: Classifier actions prefered over netfilter\n"); +#endif +#endif + + if (NULL == p) + goto error; + +#ifndef CONFIG_NET_CLS_ACT +#ifdef CONFIG_NETFILTER if (!nf_registered) { if (nf_register_hook(&ing_ops) < 0) { printk("ingress qdisc registration error \n"); @@ -251,6 +301,8 @@ int ingress_init(struct Qdisc *sch,struct rtattr *opt) } nf_registered++; } +#endif +#endif DPRINTK("ingress_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt); memset(p, 0, sizeof(*p)); @@ -364,8 +416,12 @@ static int __init ingress_module_init(void) static void __exit ingress_module_exit(void) { unregister_qdisc(&ingress_qdisc_ops); +#ifndef CONFIG_NET_CLS_ACT +#ifdef CONFIG_NETFILTER if (nf_registered) nf_unregister_hook(&ing_ops); +#endif +#endif } module_init(ingress_module_init) module_exit(ingress_module_exit) diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index f8eafc507644..52a4c2e28272 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -47,60 +47,104 @@ struct prio_sched_data }; -static __inline__ unsigned prio_classify(struct sk_buff *skb, struct Qdisc *sch) +struct Qdisc *prio_classify(struct sk_buff *skb, struct Qdisc *sch,int *r) { struct prio_sched_data *q = (struct prio_sched_data *)sch->data; struct tcf_result res; u32 band; + int result = 0; band = skb->priority; + if (TC_H_MAJ(skb->priority) != sch->handle) { +#ifdef CONFIG_NET_CLS_ACT + *r = result = tc_classify(skb, q->filter_list, &res); + + switch (result) { + case TC_ACT_SHOT: + case TC_ACT_STOLEN: + case TC_ACT_QUEUED: + kfree_skb(skb); + return NULL; + case TC_ACT_RECLASSIFY: + case TC_ACT_OK: + case TC_ACT_UNSPEC: + default: + break; + }; + + if (!q->filter_list ) { +#else if (!q->filter_list || tc_classify(skb, q->filter_list, &res)) { +#endif if (TC_H_MAJ(band)) band = 0; - return q->prio2band[band&TC_PRIO_MAX]; + return q->queues[q->prio2band[band&TC_PRIO_MAX]]; } band = res.classid; } band = TC_H_MIN(band) - 1; - return band < q->bands ? band : q->prio2band[0]; + if (band > q->bands) + return q->queues[q->prio2band[0]]; + + return q->queues[band]; } static int prio_enqueue(struct sk_buff *skb, struct Qdisc* sch) { - struct prio_sched_data *q = (struct prio_sched_data *)sch->data; struct Qdisc *qdisc; int ret; - qdisc = q->queues[prio_classify(skb, sch)]; + /* moving these up here changes things from before + * packets counted now include everything that was ever + * seen + */ + sch->stats.bytes += skb->len; + sch->stats.packets++; + qdisc = prio_classify(skb, sch, &ret); + if (NULL == qdisc) + goto dropped; if ((ret = qdisc->enqueue(skb, qdisc)) == 0) { - sch->stats.bytes += skb->len; - sch->stats.packets++; sch->q.qlen++; - return 0; + return NET_XMIT_SUCCESS; } - sch->stats.drops++; - return ret; + +dropped: +#ifdef CONFIG_NET_CLS_ACT + if (TC_ACT_SHOT == ret || NET_XMIT_DROP == ret) { +#endif + sch->stats.drops++; + return NET_XMIT_DROP; +#ifdef CONFIG_NET_CLS_ACT + } else { + sch->stats.overlimits++; /* abuse, but noone uses it */ + return NET_XMIT_BYPASS; /* we dont want to confuse TCP */ + } +#endif } static int prio_requeue(struct sk_buff *skb, struct Qdisc* sch) { - struct prio_sched_data *q = (struct prio_sched_data *)sch->data; + //struct prio_sched_data *q = (struct prio_sched_data *)sch->data; struct Qdisc *qdisc; - int ret; + int ret = NET_XMIT_DROP; - qdisc = q->queues[prio_classify(skb, sch)]; + sch->stats.reqs++; + qdisc = prio_classify(skb, sch, &ret); + if (qdisc == NULL) + goto dropped; if ((ret = qdisc->ops->requeue(skb, qdisc)) == 0) { sch->q.qlen++; return 0; } +dropped: sch->stats.drops++; - return ret; + return NET_XMIT_DROP; } -- cgit v1.2.3 From 3a15d11b78fc3d9a1d62fb7ce56092d87f0e9b43 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 16 Jun 2004 15:29:08 -0400 Subject: [IDE] Introduce SATA enable/disable config option This config option is introduced to help reduce user confusion, and eliminate conflicts between the IDE driver (which is often built into user kernels) and the new libata SATA driver. --- drivers/ide/Kconfig | 20 ++++++++++++++++++++ drivers/ide/pci/generic.c | 2 ++ drivers/ide/pci/piix.c | 4 ++-- drivers/ide/pci/siimage.c | 3 +++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 91e9282b449e..3dcbb03e5ce9 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -95,6 +95,26 @@ if BLK_DEV_IDE comment "Please see Documentation/ide.txt for help/info on IDE drives" +config BLK_DEV_IDE_SATA + bool "Support for SATA (deprecated; conflicts with libata SATA driver)" + default n + ---help--- + There are two drivers for Serial ATA controllers. + + The main driver, "libata", exists inside the SCSI subsystem + and supports most modern SATA controllers. + + The IDE driver (which you are currently configuring) supports + a few first-generation SATA controllers. + + In order to eliminate conflicts between the two subsystems, + this config option enables the IDE driver's SATA support. + Normally this is disabled, as it is preferred that libata + supports SATA controllers, and this (IDE) driver supports + PATA controllers. + + If unsure, say N. + config BLK_DEV_HD_IDE bool "Use old disk-only driver on primary interface" depends on ((X86 && X86_PC9800!=y) || SH_MPC1211) diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c index e73279563a58..2150a18a8252 100644 --- a/drivers/ide/pci/generic.c +++ b/drivers/ide/pci/generic.c @@ -127,7 +127,9 @@ static struct pci_device_id generic_pci_tbl[] = { { PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, +#ifdef CONFIG_BLK_DEV_IDE_SATA { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, +#endif { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10}, { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11}, { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12}, diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index fec700bbacbc..26719f2c7932 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -793,9 +793,9 @@ static struct pci_device_id piix_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17}, -#ifndef CONFIG_SCSI_SATA +#ifdef CONFIG_BLK_DEV_IDE_SATA { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18}, -#endif /* !CONFIG_SCSI_SATA */ +#endif { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_19, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 20}, { 0, }, diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 5a7483ef6003..b1c9e8cd5d7c 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -21,6 +21,7 @@ * if neccessary */ +#include #include #include #include @@ -1127,8 +1128,10 @@ static int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_devi static struct pci_device_id siimage_pci_tbl[] = { { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +#ifdef CONFIG_BLK_DEV_IDE_SATA { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, +#endif { 0, }, }; MODULE_DEVICE_TABLE(pci, siimage_pci_tbl); -- cgit v1.2.3 From 0cac88798dc5f0a6a927315019451e8b117777bf Mon Sep 17 00:00:00 2001 From: Andrew Chew Date: Wed, 16 Jun 2004 15:42:01 -0400 Subject: [libata] Add NVIDIA SATA driver --- drivers/scsi/Kconfig | 8 ++ drivers/scsi/Makefile | 1 + drivers/scsi/sata_nv.c | 345 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 354 insertions(+) create mode 100644 drivers/scsi/sata_nv.c diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 4390af7a12ea..6c17ff057451 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -470,6 +470,14 @@ config SCSI_SATA_VITESSE If unsure, say N. +config SCSI_SATA_NV + tristate "NVIDIA SATA support" + depends on SCSI_SATA && PCI && EXPERIMENTAL + help + This option enables support for NVIDIA Serial ATA. + + If unsure, say N. + config SCSI_BUSLOGIC tristate "BusLogic SCSI support" depends on (PCI || ISA || MCA) && SCSI diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 73e462e5d658..342d5d950bc9 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -127,6 +127,7 @@ obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o obj-$(CONFIG_SCSI_SATA_VITESSE) += libata.o sata_vsc.o obj-$(CONFIG_SCSI_SATA_SIS) += libata.o sata_sis.o obj-$(CONFIG_SCSI_SATA_SX4) += libata.o sata_sx4.o +obj-$(CONFIG_SCSI_SATA_NV) += libata.o sata_nv.o obj-$(CONFIG_ARM) += arm/ diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c new file mode 100644 index 000000000000..5d6530081f1d --- /dev/null +++ b/drivers/scsi/sata_nv.c @@ -0,0 +1,345 @@ +/* + * sata_nv.c - NVIDIA nForce SATA + * + * Copyright 2004 NVIDIA Corp. All rights reserved. + * Copyright 2004 Andrew Chew + * + * The contents of this file are subject to the Open + * Software License version 1.1 that can be found at + * http://www.opensource.org/licenses/osl-1.1.txt and is included herein + * by reference. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License version 2 (the "GPL") as distributed + * in the kernel source COPYING file, in which case the provisions of + * the GPL are applicable instead of the above. If you wish to allow + * the use of your version of this file only under the terms of the + * GPL and not to allow others to use your version of this file under + * the OSL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the GPL. + * If you do not delete the provisions above, a recipient may use your + * version of this file under either the OSL or the GPL. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" +#include + +#define DRV_NAME "sata_nv" +#define DRV_VERSION "0.01" + +#define NV_PORTS 2 +#define NV_PIO_MASK 0x1f +#define NV_UDMA_MASK 0x7f +#define NV_PORT0_BMDMA_REG_OFFSET 0x00 +#define NV_PORT1_BMDMA_REG_OFFSET 0x08 +#define NV_PORT0_SCR_REG_OFFSET 0x00 +#define NV_PORT1_SCR_REG_OFFSET 0x40 + +#define NV_INT_STATUS 0x10 +#define NV_INT_STATUS_PDEV_INT 0x01 +#define NV_INT_STATUS_PDEV_PM 0x02 +#define NV_INT_STATUS_PDEV_ADDED 0x04 +#define NV_INT_STATUS_PDEV_REMOVED 0x08 +#define NV_INT_STATUS_SDEV_INT 0x10 +#define NV_INT_STATUS_SDEV_PM 0x20 +#define NV_INT_STATUS_SDEV_ADDED 0x40 +#define NV_INT_STATUS_SDEV_REMOVED 0x80 +#define NV_INT_STATUS_PDEV_HOTPLUG (NV_INT_STATUS_PDEV_ADDED | \ + NV_INT_STATUS_PDEV_REMOVED) +#define NV_INT_STATUS_SDEV_HOTPLUG (NV_INT_STATUS_SDEV_ADDED | \ + NV_INT_STATUS_SDEV_REMOVED) +#define NV_INT_STATUS_HOTPLUG (NV_INT_STATUS_PDEV_HOTPLUG | \ + NV_INT_STATUS_SDEV_HOTPLUG) + +#define NV_INT_ENABLE 0x11 +#define NV_INT_ENABLE_PDEV_MASK 0x01 +#define NV_INT_ENABLE_PDEV_PM 0x02 +#define NV_INT_ENABLE_PDEV_ADDED 0x04 +#define NV_INT_ENABLE_PDEV_REMOVED 0x08 +#define NV_INT_ENABLE_SDEV_MASK 0x10 +#define NV_INT_ENABLE_SDEV_PM 0x20 +#define NV_INT_ENABLE_SDEV_ADDED 0x40 +#define NV_INT_ENABLE_SDEV_REMOVED 0x80 +#define NV_INT_ENABLE_PDEV_HOTPLUG (NV_INT_ENABLE_PDEV_ADDED | \ + NV_INT_ENABLE_PDEV_REMOVED) +#define NV_INT_ENABLE_SDEV_HOTPLUG (NV_INT_ENABLE_SDEV_ADDED | \ + NV_INT_ENABLE_SDEV_REMOVED) +#define NV_INT_ENABLE_HOTPLUG (NV_INT_ENABLE_PDEV_HOTPLUG | \ + NV_INT_ENABLE_SDEV_HOTPLUG) + +#define NV_INT_CONFIG 0x12 +#define NV_INT_CONFIG_METHD 0x01 // 0 = INT, 1 = SMI + +static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +irqreturn_t nv_interrupt (int irq, void *dev_instance, struct pt_regs *regs); +static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg); +static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static void nv_host_stop (struct ata_host_set *host_set); + +static struct pci_device_id nv_pci_tbl[] = { + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, + { 0, } /* terminate list */ +}; + +static struct pci_driver nv_pci_driver = { + .name = DRV_NAME, + .id_table = nv_pci_tbl, + .probe = nv_init_one, + .remove = ata_pci_remove_one, +}; + +static Scsi_Host_Template nv_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = ATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations nv_ops = { + .port_disable = ata_port_disable, + .tf_load = ata_tf_load_pio, + .tf_read = ata_tf_read_pio, + .exec_command = ata_exec_command_pio, + .check_status = ata_check_status_pio, + .phy_reset = sata_phy_reset, + .bmdma_setup = ata_bmdma_setup_pio, + .bmdma_start = ata_bmdma_start_pio, + .qc_prep = ata_qc_prep, + .eng_timeout = ata_eng_timeout, + .irq_handler = nv_interrupt, + .scr_read = nv_scr_read, + .scr_write = nv_scr_write, + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = nv_host_stop, +}; + +MODULE_AUTHOR("NVIDIA"); +MODULE_DESCRIPTION("low-level driver for NVIDIA nForce SATA controller"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, nv_pci_tbl); + +irqreturn_t nv_interrupt (int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ata_host_set *host_set = dev_instance; + unsigned int i; + unsigned int handled = 0; + unsigned long flags; + u8 intr_status; + u8 intr_enable; + + spin_lock_irqsave(&host_set->lock, flags); + + for (i = 0; i < host_set->n_ports; i++) { + struct ata_port *ap; + + ap = host_set->ports[i]; + if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + struct ata_queued_cmd *qc; + + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc && (!(qc->tf.ctl & ATA_NIEN))) + handled += ata_host_intr(ap, qc); + } + + intr_status = inb(ap->ioaddr.scr_addr + NV_INT_STATUS); + intr_enable = inb(ap->ioaddr.scr_addr + NV_INT_ENABLE); + + // Clear interrupt status. + outb(0xff, ap->ioaddr.scr_addr + NV_INT_STATUS); + + if (intr_status & NV_INT_STATUS_HOTPLUG) { + if (intr_status & NV_INT_STATUS_PDEV_ADDED) { + printk(KERN_WARNING "ata%u: " + "Primary device added\n", ap->id); + } + + if (intr_status & NV_INT_STATUS_PDEV_REMOVED) { + printk(KERN_WARNING "ata%u: " + "Primary device removed\n", ap->id); + } + + if (intr_status & NV_INT_STATUS_SDEV_ADDED) { + printk(KERN_WARNING "ata%u: " + "Secondary device added\n", ap->id); + } + + if (intr_status & NV_INT_STATUS_SDEV_REMOVED) { + printk(KERN_WARNING "ata%u: " + "Secondary device removed\n", ap->id); + } + } + } + + spin_unlock_irqrestore(&host_set->lock, flags); + + return IRQ_RETVAL(handled); +} + +static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg) +{ + if (sc_reg > SCR_CONTROL) + return 0xffffffffU; + + return inl(ap->ioaddr.scr_addr + (sc_reg * 4)); +} + +static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) +{ + if (sc_reg > SCR_CONTROL) + return; + + outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)); +} + +static void nv_host_stop (struct ata_host_set *host_set) +{ + int i; + + for (i=0; in_ports; i++) { + u8 intr_mask; + + // Disable hotplug event interrupts. + intr_mask = inb(host_set->ports[i]->ioaddr.scr_addr + + NV_INT_ENABLE); + intr_mask &= ~(NV_INT_ENABLE_HOTPLUG); + outb(intr_mask, host_set->ports[i]->ioaddr.scr_addr + + NV_INT_ENABLE); + } +} + +static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version = 0; + struct ata_probe_ent *probe_ent = NULL; + int i; + int rc; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + + probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent) { + rc = -ENOMEM; + goto err_out_regions; + } + + memset(probe_ent, 0, sizeof(*probe_ent)); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->pdev = pdev; + probe_ent->sht = &nv_sht; + probe_ent->host_flags = ATA_FLAG_SATA | + ATA_FLAG_SATA_RESET | + ATA_FLAG_SRST | + ATA_FLAG_NO_LEGACY; + probe_ent->port_ops = &nv_ops; + probe_ent->n_ports = NV_PORTS; + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + probe_ent->pio_mask = NV_PIO_MASK; + probe_ent->udma_mask = NV_UDMA_MASK; + + probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); + ata_std_ports(&probe_ent->port[0]); + probe_ent->port[0].altstatus_addr = + probe_ent->port[0].ctl_addr = + pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; + probe_ent->port[0].bmdma_addr = + pci_resource_start(pdev, 4) | NV_PORT0_BMDMA_REG_OFFSET; + probe_ent->port[0].scr_addr = + pci_resource_start(pdev, 5) | NV_PORT0_SCR_REG_OFFSET; + + probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); + ata_std_ports(&probe_ent->port[1]); + probe_ent->port[1].altstatus_addr = + probe_ent->port[1].ctl_addr = + pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; + probe_ent->port[1].bmdma_addr = + pci_resource_start(pdev, 4) | NV_PORT1_BMDMA_REG_OFFSET; + probe_ent->port[1].scr_addr = + pci_resource_start(pdev, 5) | NV_PORT1_SCR_REG_OFFSET; + + pci_set_master(pdev); + + rc = ata_device_add(probe_ent); + if (rc != NV_PORTS) + goto err_out_regions; + + // Enable hotplug event interrupts. + for (i=0; in_ports; i++) { + u8 intr_mask; + + outb(NV_INT_STATUS_HOTPLUG, probe_ent->port[i].scr_addr + + NV_INT_STATUS); + + intr_mask = inb(probe_ent->port[i].scr_addr + NV_INT_ENABLE); + intr_mask |= NV_INT_ENABLE_HOTPLUG; + outb(intr_mask, probe_ent->port[i].scr_addr + NV_INT_ENABLE); + } + + kfree(probe_ent); + + return 0; + +err_out_regions: + pci_release_regions(pdev); + +err_out: + pci_disable_device(pdev); + return rc; +} + +static int __init nv_init(void) +{ + return pci_module_init(&nv_pci_driver); +} + +static void __exit nv_exit(void) +{ + pci_unregister_driver(&nv_pci_driver); +} + +module_init(nv_init); +module_exit(nv_exit); -- cgit v1.2.3 From 1f191e7782263cec08869744cfb434dfeeec0d8c Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 16 Jun 2004 15:44:40 -0400 Subject: [libata] put nvidia in Kconfig, in alphabetical order --- drivers/scsi/Kconfig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 6c17ff057451..8db8e93d3d37 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -422,6 +422,14 @@ config SCSI_ATA_PIIX If unsure, say N. +config SCSI_SATA_NV + tristate "NVIDIA SATA support" + depends on SCSI_SATA && PCI && EXPERIMENTAL + help + This option enables support for NVIDIA Serial ATA. + + If unsure, say N. + config SCSI_SATA_PROMISE tristate "Promise SATA TX2/TX4 support" depends on SCSI_SATA && PCI @@ -470,14 +478,6 @@ config SCSI_SATA_VITESSE If unsure, say N. -config SCSI_SATA_NV - tristate "NVIDIA SATA support" - depends on SCSI_SATA && PCI && EXPERIMENTAL - help - This option enables support for NVIDIA Serial ATA. - - If unsure, say N. - config SCSI_BUSLOGIC tristate "BusLogic SCSI support" depends on (PCI || ISA || MCA) && SCSI -- cgit v1.2.3 From 6ea59cd95e1b18cf31ea958b9e70385fbaedf9e0 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 16 Jun 2004 16:24:34 -0400 Subject: [libata/IDE nvidia] shuffle pci ids * Mark conflicting PCI ids with CONFIG_BLK_DEV_IDE_SATA * Move not-yet-released PCI ids to libata sata_nv driver --- drivers/ide/pci/amd74xx.c | 20 ++++++-------------- drivers/scsi/sata_nv.c | 14 +++++++++++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index d6b052300dfa..30bdcb3ec22f 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -71,11 +71,7 @@ static struct amd_ide_chip { { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, 0x50, AMD_UDMA_133 }, { 0 } }; @@ -487,11 +483,7 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = { /* 11 */ DECLARE_NV_DEV("NFORCE3-250-SATA"), /* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2"), /* 13 */ DECLARE_NV_DEV("NFORCE-CK804"), - /* 14 */ DECLARE_NV_DEV("NFORCE-CK804-SATA"), - /* 15 */ DECLARE_NV_DEV("NFORCE-CK804-SATA2"), - /* 16 */ DECLARE_NV_DEV("NFORCE-MCP04"), - /* 17 */ DECLARE_NV_DEV("NFORCE-MCP04-SATA"), - /* 18 */ DECLARE_NV_DEV("NFORCE-MCP04-SATA2") + /* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"), }; static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id) @@ -512,17 +504,17 @@ static struct pci_device_id amd74xx_pci_tbl[] = { { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, +#ifdef CONFIG_BLK_DEV_IDE_SATA { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, +#endif { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 }, +#ifdef CONFIG_BLK_DEV_IDE_SATA { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 }, +#endif { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, { 0, }, }; MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index 5d6530081f1d..e6a7bb0c444f 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -88,11 +88,19 @@ static void nv_host_stop (struct ata_host_set *host_set); static struct pci_device_id nv_pci_tbl[] = { { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, + PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, + PCI_ANY_ID, PCI_ANY_ID, }, { 0, } /* terminate list */ }; -- cgit v1.2.3 From d0b53c036d6fd4cab93bd52c56e4e2bd6d39af92 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Thu, 17 Jun 2004 00:21:35 -0700 Subject: [ARM] Consolidate various ARM timer fns. into single timer_tick() call. Signed-off-by: Deepak Saxena --- arch/arm/kernel/time.c | 24 ++++++++++++++++-------- arch/arm/mach-clps711x/time.c | 4 +--- arch/arm/mach-clps7500/core.c | 5 ++--- arch/arm/mach-ebsa110/core.c | 4 +--- arch/arm/mach-epxa10db/time.c | 4 +--- arch/arm/mach-footbridge/time.c | 13 ++----------- arch/arm/mach-integrator/time.c | 4 +--- arch/arm/mach-iop3xx/iop321-time.c | 2 +- arch/arm/mach-ixp4xx/common.c | 2 +- arch/arm/mach-lh7a40x/time.c | 5 +---- arch/arm/mach-omap/time.c | 4 +--- arch/arm/mach-pxa/time.c | 6 +----- arch/arm/mach-rpc/riscpc.c | 4 +--- arch/arm/mach-s3c2410/time.c | 7 +------ arch/arm/mach-sa1100/time.c | 6 +----- arch/arm/mach-shark/core.c | 4 +--- arch/arm/mach-versatile/core.c | 4 +--- include/asm-arm/mach/time.h | 8 ++------ 18 files changed, 36 insertions(+), 74 deletions(-) diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index f8c164e94733..efcb44a9e6ab 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -52,15 +52,11 @@ EXPORT_SYMBOL(rtc_lock); /* change this if you have some constant time drift */ #define USECS_PER_JIFFY (1000000/HZ) -static int dummy_set_rtc(void) -{ - return 0; -} /* * hook for setting the RTC's idea of the current time. */ -int (*set_rtc)(void) = dummy_set_rtc; +int (*set_rtc)(void); static unsigned long dummy_gettimeoffset(void) { @@ -86,7 +82,7 @@ unsigned long long __attribute__((weak)) sched_clock(void) /* * Handle kernel profile stuff... */ -void do_profile(struct pt_regs *regs) +static inline void do_profile(struct pt_regs *regs) { profile_hook(regs); @@ -116,7 +112,7 @@ static unsigned long next_rtc_update; * called as close as possible to 500 ms before the new second * starts. */ -void do_set_rtc(void) +static inline void do_set_rtc(void) { if (time_status & STA_UNSYNC || set_rtc == NULL) return; @@ -240,7 +236,8 @@ device_initcall(leds_init); EXPORT_SYMBOL(leds_event); #endif -void do_leds(void) +#ifdef CONFIG_LEDS_TIMER +static inline void do_leds(void) { static unsigned int count = 50; @@ -249,6 +246,9 @@ void do_leds(void) leds_event(led_timer); } } +#else +#define do_leds() +#endif void do_gettimeofday(struct timeval *tv) { @@ -315,6 +315,14 @@ int do_settimeofday(struct timespec *tv) EXPORT_SYMBOL(do_settimeofday); +void timer_tick(struct pt_regs *regs) +{ + do_profile(regs); + do_leds(); + do_set_rtc(); + do_timer(regs); +} + void (*init_arch_time)(void); void __init time_init(void) diff --git a/arch/arm/mach-clps711x/time.c b/arch/arm/mach-clps711x/time.c index 9c732d18ddc0..58da84effd5e 100644 --- a/arch/arm/mach-clps711x/time.c +++ b/arch/arm/mach-clps711x/time.c @@ -49,9 +49,7 @@ static unsigned long clps711x_gettimeoffset(void) static irqreturn_t p720t_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - do_leds(); - do_timer(regs); - do_profile(regs); + timer_tick(regs); return IRQ_HANDLED; } diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c index 2214f739768a..ee1a3192ad7b 100644 --- a/arch/arm/mach-clps7500/core.c +++ b/arch/arm/mach-clps7500/core.c @@ -271,10 +271,9 @@ extern void ioctime_init(void); static irqreturn_t clps7500_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - do_timer(regs); - do_set_rtc(); - do_profile(regs); + timer_tick(regs); + /* Why not using do_leds interface?? */ { /* Twinkle the lights. */ static int count, state = 0xff00; diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c index eddce7348095..6f20b86a69c4 100644 --- a/arch/arm/mach-ebsa110/core.c +++ b/arch/arm/mach-ebsa110/core.c @@ -160,9 +160,7 @@ ebsa110_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) __raw_writeb(count & 0xff, PIT_T1); __raw_writeb(count >> 8, PIT_T1); - do_leds(); - do_timer(regs); - do_profile(regs); + timer_tick(regs); return IRQ_HANDLED; } diff --git a/arch/arm/mach-epxa10db/time.c b/arch/arm/mach-epxa10db/time.c index 1b3766a46069..7d72a433dad7 100644 --- a/arch/arm/mach-epxa10db/time.c +++ b/arch/arm/mach-epxa10db/time.c @@ -47,9 +47,7 @@ epxa10db_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) // ...clear the interrupt *TIMER0_CR(IO_ADDRESS(EXC_TIMER00_BASE))|=TIMER0_CR_CI_MSK; - do_leds(); - do_timer(regs); - do_profile(regs); + timer_tick(regs); return IRQ_HANDLED; } diff --git a/arch/arm/mach-footbridge/time.c b/arch/arm/mach-footbridge/time.c index c32dd9a5c9b9..d4b9c9f87fff 100644 --- a/arch/arm/mach-footbridge/time.c +++ b/arch/arm/mach-footbridge/time.c @@ -83,12 +83,7 @@ static unsigned long isa_gettimeoffset(void) static irqreturn_t isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - if (machine_is_netwinder()) - do_leds(); - - do_timer(regs); - do_set_rtc(); - do_profile(regs); + timer_tick(regs); return IRQ_HANDLED; } @@ -206,11 +201,7 @@ timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs) { *CSR_TIMER1_CLR = 0; - /* Do the LEDs things */ - do_leds(); - do_timer(regs); - do_set_rtc(); - do_profile(regs); + timer_tick(regs); return IRQ_HANDLED; } diff --git a/arch/arm/mach-integrator/time.c b/arch/arm/mach-integrator/time.c index d791f1e41896..e12bcf814d95 100644 --- a/arch/arm/mach-integrator/time.c +++ b/arch/arm/mach-integrator/time.c @@ -139,9 +139,7 @@ integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) // ...clear the interrupt timer1->TimerClear = 1; - do_leds(); - do_timer(regs); - do_profile(regs); + timer_tick(regs); return IRQ_HANDLED; } diff --git a/arch/arm/mach-iop3xx/iop321-time.c b/arch/arm/mach-iop3xx/iop321-time.c index 3af8823cda37..be36c70690b1 100644 --- a/arch/arm/mach-iop3xx/iop321-time.c +++ b/arch/arm/mach-iop3xx/iop321-time.c @@ -63,7 +63,7 @@ iop321_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (tisr)); - do_timer(regs); + timer_tick(regs); return IRQ_HANDLED; } diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 986f2d43db28..a4edbe0eb909 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -228,7 +228,7 @@ static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id, struct pt_regs * Catch up with the real idea of time */ do { - do_timer(regs); + timer_tick(regs); last_jiffy_time += LATCH; } while((*IXP4XX_OSTS - last_jiffy_time) > LATCH); diff --git a/arch/arm/mach-lh7a40x/time.c b/arch/arm/mach-lh7a40x/time.c index 52c20c3bf248..61ada24c78a7 100644 --- a/arch/arm/mach-lh7a40x/time.c +++ b/arch/arm/mach-lh7a40x/time.c @@ -41,10 +41,7 @@ static irqreturn_t lh7a40x_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { TIMER_EOI = 0; - do_profile (regs); - do_leds(); - do_set_rtc(); - do_timer (regs); + timer_tick(regs); return IRQ_HANDLED; } diff --git a/arch/arm/mach-omap/time.c b/arch/arm/mach-omap/time.c index 57e9bd3a0579..d62e22614394 100644 --- a/arch/arm/mach-omap/time.c +++ b/arch/arm/mach-omap/time.c @@ -183,9 +183,7 @@ omap_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) ilatency = MPUTICKS_PER_SEC / 100 - read_mputimer2(); systimer_mark = now - ilatency; - do_leds(); - do_timer(regs); - do_profile(regs); + timer_tick(regs); return IRQ_HANDLED; } diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c index 432f65db19b7..7e89235632f8 100644 --- a/arch/arm/mach-pxa/time.c +++ b/arch/arm/mach-pxa/time.c @@ -74,8 +74,6 @@ pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int next_match; - do_profile(regs); - /* Loop until we get ahead of the free running timer. * This ensures an exact clock tick count and time accuracy. * IRQs are disabled inside the loop to ensure coherence between @@ -92,9 +90,7 @@ pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * exactly one tick period which should be a pretty rare event. */ do { - do_leds(); - do_set_rtc(); - do_timer(regs); + timer_tick(regs); OSSR = OSSR_M0; /* Clear match on timer 0 */ next_match = (OSMR0 += LATCH); } while( (signed long)(next_match - OSCR) <= 8 ); diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c index 7dae14b39103..d5a1a3af216c 100644 --- a/arch/arm/mach-rpc/riscpc.c +++ b/arch/arm/mach-rpc/riscpc.c @@ -88,9 +88,7 @@ void __init rpc_map_io(void) static irqreturn_t rpc_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - do_timer(regs); - do_set_rtc(); - do_profile(regs); + timer_tick(regs); return IRQ_HANDLED; } diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/mach-s3c2410/time.c index e86250e69b65..62d89d98c423 100644 --- a/arch/arm/mach-s3c2410/time.c +++ b/arch/arm/mach-s3c2410/time.c @@ -74,12 +74,7 @@ static unsigned long s3c2410_gettimeoffset (void) static irqreturn_t s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - do_leds(); - do_timer(regs); - - do_set_rtc(); - //s3c2410_rtc_check(); - do_profile(regs); + timer_tick(regs); return IRQ_HANDLED; } diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c index caff78e1c61f..e58463b02e67 100644 --- a/arch/arm/mach-sa1100/time.c +++ b/arch/arm/mach-sa1100/time.c @@ -78,15 +78,11 @@ sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) unsigned int next_match; do { - do_leds(); - do_timer(regs); + timer_tick(regs); OSSR = OSSR_M0; /* Clear match on timer 0 */ next_match = (OSMR0 += LATCH); - do_set_rtc(); } while ((signed long)(next_match - OSCR) <= 0); - do_profile(regs); - return IRQ_HANDLED; } diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c index 28504c990829..e4ae688899c1 100644 --- a/arch/arm/mach-shark/core.c +++ b/arch/arm/mach-shark/core.c @@ -35,9 +35,7 @@ static void __init shark_map_io(void) static irqreturn_t shark_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - do_leds(); - do_timer(regs); - do_profile(regs); + timer_tick(regs); return IRQ_HANDLED; } diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 27b4b95f2508..a2f88df44ab9 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -606,9 +606,7 @@ static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_re // ...clear the interrupt timer0->TimerClear = 1; - do_leds(); - do_timer(regs); - do_profile(regs); + timer_tick(regs); return IRQ_HANDLED; } diff --git a/include/asm-arm/mach/time.h b/include/asm-arm/mach/time.h index a473e6dfc878..edb6fcc6a200 100644 --- a/include/asm-arm/mach/time.h +++ b/include/asm-arm/mach/time.h @@ -12,13 +12,9 @@ extern void (*init_arch_time)(void); -void do_set_rtc(void); - -void do_profile(struct pt_regs *); - -void do_leds(void); - extern int (*set_rtc)(void); extern unsigned long(*gettimeoffset)(void); +void timer_tick(struct pt_regs *); + #endif -- cgit v1.2.3 From f0b3c84e7da94fd7a174bba885d3bb26090683f5 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Thu, 17 Jun 2004 01:41:52 -0700 Subject: [ARM] Remove ADIFCC machine type The code is completely out of date, I am no longer maintaining it, and nobdy has volunteered to do so; therefore, I am killing it. Signed-off-by: Deepak Saxena --- arch/arm/Kconfig | 3 - arch/arm/Makefile | 1 - arch/arm/boot/Makefile | 2 - arch/arm/boot/compressed/head-xscale.S | 3 - arch/arm/configs/adi_evb_defconfig | 678 ------------------------------- arch/arm/kernel/debug.S | 26 -- arch/arm/kernel/entry-armv.S | 2 +- arch/arm/mach-adifcc/Makefile | 11 - arch/arm/mach-adifcc/arch.c | 32 -- arch/arm/mach-adifcc/irq.c | 61 --- arch/arm/mach-adifcc/mm.c | 23 -- arch/arm/mm/Kconfig | 2 +- include/asm-arm/arch-adifcc/adi_evb.h | 19 - include/asm-arm/arch-adifcc/dma.h | 18 - include/asm-arm/arch-adifcc/hardware.h | 27 -- include/asm-arm/arch-adifcc/io.h | 22 - include/asm-arm/arch-adifcc/irqs.h | 20 - include/asm-arm/arch-adifcc/memory.h | 27 -- include/asm-arm/arch-adifcc/param.h | 3 - include/asm-arm/arch-adifcc/serial.h | 34 -- include/asm-arm/arch-adifcc/system.h | 28 -- include/asm-arm/arch-adifcc/timex.h | 10 - include/asm-arm/arch-adifcc/uncompress.h | 35 -- include/asm-arm/arch-adifcc/vmalloc.h | 15 - 24 files changed, 2 insertions(+), 1100 deletions(-) delete mode 100644 arch/arm/configs/adi_evb_defconfig delete mode 100644 arch/arm/mach-adifcc/Makefile delete mode 100644 arch/arm/mach-adifcc/arch.c delete mode 100644 arch/arm/mach-adifcc/irq.c delete mode 100644 arch/arm/mach-adifcc/mm.c delete mode 100644 include/asm-arm/arch-adifcc/adi_evb.h delete mode 100644 include/asm-arm/arch-adifcc/dma.h delete mode 100644 include/asm-arm/arch-adifcc/hardware.h delete mode 100644 include/asm-arm/arch-adifcc/io.h delete mode 100644 include/asm-arm/arch-adifcc/irqs.h delete mode 100644 include/asm-arm/arch-adifcc/memory.h delete mode 100644 include/asm-arm/arch-adifcc/param.h delete mode 100644 include/asm-arm/arch-adifcc/serial.h delete mode 100644 include/asm-arm/arch-adifcc/system.h delete mode 100644 include/asm-arm/arch-adifcc/timex.h delete mode 100644 include/asm-arm/arch-adifcc/uncompress.h delete mode 100644 include/asm-arm/arch-adifcc/vmalloc.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 21e8c8c42903..08241dfd49c6 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -72,9 +72,6 @@ choice prompt "ARM system type" default ARCH_RPC -config ARCH_ADIFCC - bool "ADIFCC-based" - config ARCH_CLPS7500 bool "Cirrus-CL-PS7500FE" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 85eeb2b1e1cd..e6d43f3eccf4 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -91,7 +91,6 @@ textaddr-$(CONFIG_ARCH_CLPS711X) := 0xc0028000 machine-$(CONFIG_ARCH_CLPS711X) := clps711x textaddr-$(CONFIG_ARCH_FORTUNET) := 0xc0008000 machine-$(CONFIG_ARCH_IOP3XX) := iop3xx - machine-$(CONFIG_ARCH_ADIFCC) := adifcc machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx machine-$(CONFIG_ARCH_OMAP) := omap machine-$(CONFIG_ARCH_S3C2410) := s3c2410 diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile index 72be85c543ed..8c42a9132ce3 100644 --- a/arch/arm/boot/Makefile +++ b/arch/arm/boot/Makefile @@ -49,8 +49,6 @@ initrd_phys-$(CONFIG_ARCH_SA1100) := 0xc0800000 zreladdr-$(CONFIG_ARCH_PXA) := 0xa0008000 zreladdr-$(CONFIG_ARCH_IOP3XX) := 0xa0008000 params_phys-$(CONFIG_ARCH_IOP3XX) := 0xa0000100 - zreladdr-$(CONFIG_ARCH_ADIFCC) := 0xc0008000 -params_phys-$(CONFIG_ARCH_ADIFCC) := 0xc0000100 zreladdr-$(CONFIG_ARCH_IXP4XX) := 0x00008000 params-phys-$(CONFIG_ARCH_IXP4XX) := 0x00000100 zreladdr-$(CONFIG_ARCH_OMAP) := 0x10008000 diff --git a/arch/arm/boot/compressed/head-xscale.S b/arch/arm/boot/compressed/head-xscale.S index e6656d4ef5c8..f9194499e863 100644 --- a/arch/arm/boot/compressed/head-xscale.S +++ b/arch/arm/boot/compressed/head-xscale.S @@ -66,7 +66,4 @@ __XScale_start: mov r7, #MACH_TYPE_IQ80310 #endif -#ifdef CONFIG_ARCH_ADI_EVB - mov r7, #MACH_TYPE_ADI_EVB -#endif diff --git a/arch/arm/configs/adi_evb_defconfig b/arch/arm/configs/adi_evb_defconfig deleted file mode 100644 index bae486663bb4..000000000000 --- a/arch/arm/configs/adi_evb_defconfig +++ /dev/null @@ -1,678 +0,0 @@ -# -# Automatically generated by make menuconfig: don't edit -# -CONFIG_ARM=y -# CONFIG_EISA is not set -# CONFIG_SBUS is not set -# CONFIG_MCA is not set -CONFIG_UID16=y -CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -# CONFIG_GENERIC_BUST_SPINLOCK is not set -# CONFIG_GENERIC_ISA_DMA is not set - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y -# CONFIG_OBSOLETE is not set - -# -# Loadable module support -# -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -# CONFIG_KMOD is not set - -# -# System Type -# -CONFIG_ARCH_ADIFCC=y -# CONFIG_ARCH_ARCA5K is not set -# CONFIG_ARCH_CLPS7500 is not set -# CONFIG_ARCH_CLPS711X is not set -# CONFIG_ARCH_CO285 is not set -# CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set -# CONFIG_ARCH_FOOTBRIDGE is not set -# CONFIG_ARCH_INTEGRATOR is not set -# CONFIG_ARCH_IOP310 is not set -# CONFIG_ARCH_L7200 is not set -# CONFIG_ARCH_RPC is not set -# CONFIG_ARCH_SA1100 is not set -# CONFIG_ARCH_SHARK is not set - -# -# Archimedes/A5000 Implementations -# -# CONFIG_ARCH_ARC is not set -# CONFIG_ARCH_A5K is not set - -# -# Footbridge Implementations -# -# CONFIG_ARCH_CATS is not set -# CONFIG_ARCH_PERSONAL_SERVER is not set -# CONFIG_ARCH_EBSA285_ADDIN is not set -# CONFIG_ARCH_EBSA285_HOST is not set -# CONFIG_ARCH_NETWINDER is not set - -# -# SA11x0 Implementations -# -# CONFIG_SA1100_ASSABET is not set -# CONFIG_ASSABET_NEPONSET is not set -# CONFIG_SA1100_ADSBITSY is not set -# CONFIG_SA1100_BRUTUS is not set -# CONFIG_SA1100_CERF is not set -# CONFIG_SA1100_H3600 is not set -# CONFIG_SA1100_EXTENEX1 is not set -# CONFIG_SA1100_FLEXANET is not set -# CONFIG_SA1100_FREEBIRD is not set -# CONFIG_SA1100_GRAPHICSCLIENT is not set -# CONFIG_SA1100_GRAPHICSMASTER is not set -# CONFIG_SA1100_JORNADA720 is not set -# CONFIG_SA1100_HUW_WEBPANEL is not set -# CONFIG_SA1100_ITSY is not set -# CONFIG_SA1100_LART is not set -# CONFIG_SA1100_NANOENGINE is not set -# CONFIG_SA1100_OMNIMETER is not set -# CONFIG_SA1100_PANGOLIN is not set -# CONFIG_SA1100_PLEB is not set -# CONFIG_SA1100_SHERMAN is not set -# CONFIG_SA1100_SIMPAD is not set -# CONFIG_SA1100_PFS168 is not set -# CONFIG_SA1100_VICTOR is not set -# CONFIG_SA1100_XP860 is not set -# CONFIG_SA1100_YOPY is not set -# CONFIG_SA1100_USB is not set -# CONFIG_SA1100_USB_NETLINK is not set -# CONFIG_SA1100_USB_CHAR is not set - -# -# CLPS711X/EP721X Implementations -# -# CONFIG_ARCH_CDB89712 is not set -# CONFIG_ARCH_CLEP7312 is not set -# CONFIG_ARCH_EDB7211 is not set -# CONFIG_ARCH_P720T is not set -# CONFIG_ARCH_EP7211 is not set -# CONFIG_ARCH_EP7212 is not set -CONFIG_ARCH_ADI_EVB=y -CONFIG_XSCALE_PMU_TIMER=y -# CONFIG_ARCH_ACORN is not set -# CONFIG_FOOTBRIDGE is not set -# CONFIG_FOOTBRIDGE_HOST is not set -# CONFIG_FOOTBRIDGE_ADDIN is not set -CONFIG_CPU_32=y -# CONFIG_CPU_26 is not set -# CONFIG_CPU_32v3 is not set -# CONFIG_CPU_32v4 is not set -# CONFIG_CPU_ARM610 is not set -# CONFIG_CPU_ARM710 is not set -# CONFIG_CPU_ARM720T is not set -# CONFIG_CPU_ARM920T is not set -# CONFIG_CPU_ARM926T is not set -# CONFIG_CPU_ARM1020 is not set -# CONFIG_CPU_SA110 is not set -# CONFIG_CPU_SA1100 is not set -CONFIG_CPU_32v4=y -CONFIG_CPU_XSCALE=y -CONFIG_ARM_THUMB=y -# CONFIG_XSCALE_TOOLS is not set -CONFIG_XSCALE_WRITE_ALLOC=y -CONFIG_XSCALE_PMU=y -CONFIG_ARM_THUMB=y -# CONFIG_DISCONTIGMEM is not set - -# -# General setup -# -# CONFIG_PCI is not set -# CONFIG_ISA is not set -# CONFIG_ISA_DMA is not set -# CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set -CONFIG_NET=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_FPE_NWFPE=y -# CONFIG_FPE_FASTFPE is not set -CONFIG_KCORE_ELF=y -# CONFIG_KCORE_AOUT is not set -CONFIG_BINFMT_AOUT=y -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_PM is not set -# CONFIG_ARTHUR is not set -CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/mtdblock1 mem=32M initrd=0xc0800000,3M" -CONFIG_ALIGNMENT_TRAP=y - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Memory Technology Devices (MTD) -# -CONFIG_MTD=y -# CONFIG_MTD_DEBUG is not set -CONFIG_MTD_PARTITIONS=y -# CONFIG_MTD_REDBOOT_PARTS is not set -# CONFIG_MTD_BOOTLDR_PARTS is not set -# CONFIG_MTD_AFS_PARTS is not set -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -# CONFIG_FTL is not set -# CONFIG_NFTL is not set - -# -# RAM/ROM/Flash chip drivers -# -CONFIG_MTD_CFI=y -# CONFIG_MTD_JEDECPROBE is not set -CONFIG_MTD_GEN_PROBE=y -# CONFIG_MTD_CFI_ADV_OPTIONS is not set -CONFIG_MTD_CFI_INTELEXT=y -# CONFIG_MTD_CFI_AMDSTD is not set -# CONFIG_MTD_RAM is not set -# CONFIG_MTD_ROM is not set -# CONFIG_MTD_ABSENT is not set -# CONFIG_MTD_OBSOLETE_CHIPS is not set -# CONFIG_MTD_AMDSTD is not set -# CONFIG_MTD_SHARP is not set -# CONFIG_MTD_JEDEC is not set - -# -# Mapping drivers for chip access -# -# CONFIG_MTD_PHYSMAP is not set -# CONFIG_MTD_NORA is not set -# CONFIG_MTD_ARM_INTEGRATOR is not set -# CONFIG_MTD_CDB89712 is not set -# CONFIG_MTD_SA1100 is not set -# CONFIG_MTD_DC21285 is not set -# CONFIG_MTD_IQ80310 is not set -CONFIG_MTD_ADI_EVB=y -# CONFIG_MTD_PCI is not set - -# -# Self-contained MTD device drivers -# -# CONFIG_MTD_PMC551 is not set -# CONFIG_MTD_SLRAM is not set -# CONFIG_MTD_MTDRAM is not set -# CONFIG_MTD_BLKMTD is not set -# CONFIG_MTD_DOC1000 is not set -# CONFIG_MTD_DOC2000 is not set -# CONFIG_MTD_DOC2001 is not set -# CONFIG_MTD_DOCPROBE is not set - -# -# NAND Flash Device Drivers -# -# CONFIG_MTD_NAND is not set - -# -# Plug and Play configuration -# -# CONFIG_PNP is not set -# CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_CISS_SCSI_TAPE is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_BLK_DEV_INITRD=y - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# Networking options -# -# CONFIG_PACKET is not set -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -# CONFIG_NETLINK_DEV is not set -# CONFIG_NETFILTER is not set -# CONFIG_FILTER is not set -CONFIG_UNIX=y -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -# CONFIG_IP_PNP_DHCP is not set -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_IPV6 is not set -# CONFIG_KHTTPD is not set -# CONFIG_ATM is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_LLC is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set -# CONFIG_ETHERTAP is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -# CONFIG_ARM_AM79C961A is not set -# CONFIG_SUNLANCE is not set -# CONFIG_SUNBMAC is not set -# CONFIG_SUNQE is not set -# CONFIG_SUNLANCE is not set -# CONFIG_SUNGEM is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_NET_ISA is not set -# CONFIG_NET_PCI is not set -# CONFIG_NET_POCKET is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_MYRI_SBUS is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_SK98LIN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PLIP is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# -# ATA/IDE/MFM/RLL support -# -# CONFIG_IDE is not set -# CONFIG_BLK_DEV_HD is not set - -# -# SCSI support -# -# CONFIG_SCSI is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# Input core support -# -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - -# -# Character devices -# -# CONFIG_VT is not set -CONFIG_SERIAL=y -CONFIG_SERIAL_CONSOLE=y -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set - -# -# Serial drivers -# -# CONFIG_SERIAL_AMBA is not set -# CONFIG_SERIAL_AMBA_CONSOLE is not set -# CONFIG_SERIAL_CLPS711X is not set -# CONFIG_SERIAL_CLPS711X_CONSOLE is not set -# CONFIG_SERIAL_21285 is not set -# CONFIG_SERIAL_21285_OLD is not set -# CONFIG_SERIAL_21285_CONSOLE is not set -# CONFIG_SERIAL_UART00 is not set -# CONFIG_SERIAL_UART00_CONSOLE is not set -# CONFIG_SERIAL_SA1100 is not set -# CONFIG_SERIAL_SA1100_CONSOLE is not set -# CONFIG_SERIAL_8250 is not set -# CONFIG_SERIAL_8250_CONSOLE is not set -# CONFIG_SERIAL_8250_EXTENDED is not set -# CONFIG_SERIAL_8250_MANY_PORTS is not set -# CONFIG_SERIAL_8250_SHARE_IRQ is not set -# CONFIG_SERIAL_8250_DETECT_IRQ is not set -# CONFIG_SERIAL_8250_MULTIPORT is not set -# CONFIG_SERIAL_8250_HUB6 is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# L3 serial bus support -# -# CONFIG_L3 is not set -# CONFIG_L3_ALGOBIT is not set -# CONFIG_L3_BIT_SA1100_GPIO is not set -# CONFIG_L3_SA1111 is not set -# CONFIG_BIT_SA1100_GPIO is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -CONFIG_MOUSE=y -CONFIG_PSMOUSE=y -# CONFIG_82C710_MOUSE is not set -# CONFIG_PC110_PAD is not set - -# -# Joysticks -# -# CONFIG_INPUT_GAMEPORT is not set -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_INTEL_RNG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# File systems -# -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set -# CONFIG_EXT3_FS is not set -# CONFIG_JBD is not set -# CONFIG_JBD_DEBUG is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -CONFIG_JFFS2_FS=y -CONFIG_JFFS2_FS_DEBUG=0 -# CONFIG_CRAMFS is not set -# CONFIG_TMPFS is not set -CONFIG_RAMFS=y -# CONFIG_ISO9660_FS is not set -# CONFIG_JOLIET is not set -# CONFIG_ZISOFS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_DEBUG is not set -# CONFIG_NTFS_RW is not set -# CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set -# CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -# CONFIG_INTERMEZZO_FS is not set -# CONFIG_NFS_FS is not set -# CONFIG_NFS_V3 is not set -# CONFIG_ROOT_NFS is not set -# CONFIG_NFSD is not set -# CONFIG_NFSD_V3 is not set -# CONFIG_SUNRPC is not set -# CONFIG_LOCKD is not set -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set -# CONFIG_NCPFS_PACKET_SIGNING is not set -# CONFIG_NCPFS_IOCTL_LOCKING is not set -# CONFIG_NCPFS_STRONG is not set -# CONFIG_NCPFS_NFS_NS is not set -# CONFIG_NCPFS_OS2_NS is not set -# CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set -# CONFIG_ZISOFS_FS is not set -# CONFIG_ZLIB_FS_INFLATE is not set - -# -# Partition Types -# -CONFIG_PARTITION_ADVANCED=y -# CONFIG_ACORN_PARTITION is not set -# CONFIG_OSF_PARTITION is not set -# CONFIG_AMIGA_PARTITION is not set -# CONFIG_ATARI_PARTITION is not set -# CONFIG_MAC_PARTITION is not set -# CONFIG_MSDOS_PARTITION is not set -# CONFIG_LDM_PARTITION is not set -# CONFIG_SGI_PARTITION is not set -# CONFIG_ULTRIX_PARTITION is not set -# CONFIG_SUN_PARTITION is not set -# CONFIG_SMB_NLS is not set -# CONFIG_NLS is not set - -# -# Multimedia Capabilities Port drivers -# -# CONFIG_MCP is not set -# CONFIG_MCP_SA1100 is not set -# CONFIG_MCP_UCB1200 is not set -# CONFIG_MCP_UCB1200_AUDIO is not set -# CONFIG_MCP_UCB1200_TS is not set - -# -# USB support -# -# CONFIG_USB is not set -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -# CONFIG_USB_OHCI is not set -# CONFIG_USB_OHCI_SA1111 is not set -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set -# CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_KAWETH is not set -# CONFIG_USB_CATC is not set -# CONFIG_USB_CDCETHER is not set -# CONFIG_USB_USBNET is not set -# CONFIG_USB_USS720 is not set - -# -# USB Serial Converter support -# -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set -# CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set - -# -# Bluetooth support -# -# CONFIG_BT is not set - -# -# Kernel hacking -# -CONFIG_FRAME_POINTER=y -CONFIG_DEBUG_ERRORS=y -CONFIG_DEBUG_USER=y -# CONFIG_DEBUG_INFO is not set -CONFIG_DEBUG_SLAB=y -# CONFIG_MAGIC_SYSRQ is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_NO_PGT_CACHE is not set -CONFIG_DEBUG_LL=y -# CONFIG_DEBUG_DC21285_PORT is not set -# CONFIG_DEBUG_CLPS711X_UART2 is not set diff --git a/arch/arm/kernel/debug.S b/arch/arm/kernel/debug.S index 2ae6eae420e4..0b3b9ab5b41d 100644 --- a/arch/arm/kernel/debug.S +++ b/arch/arm/kernel/debug.S @@ -439,32 +439,6 @@ #endif .endm -#elif defined(CONFIG_ARCH_ADI_EVB) - - .macro addruart,rx - mrc p15, 0, \rx, c1, c0 - tst \rx, #1 @ MMU enabled? - mov \rx, #0x00400000 @ physical base address - orrne \rx, \rx, #0xff000000 @ virtual base - .endm - - .macro senduart,rd,rx - strb \rd, [\rx] - .endm - - .macro busyuart,rd,rx -1002: ldrb \rd, [\rx, #0x5] - and \rd, \rd, #0x60 - teq \rd, #0x60 - bne 1002b - .endm - - .macro waituart,rd,rx -1001: ldrb \rd, [\rx, #0x6] - tst \rd, #0x10 - beq 1001b - .endm - #elif defined(CONFIG_ARCH_IXP4XX) .macro addruart,rx diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 8af6251f3c3a..c43df2218298 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -561,7 +561,7 @@ ENTRY(soft_irq_mask) .macro irq_prio_table .endm -#elif defined(CONFIG_ARCH_IOP310) || defined(CONFIG_ARCH_ADIFCC) +#elif defined(CONFIG_ARCH_IOP310) .macro disable_fiq .endm diff --git a/arch/arm/mach-adifcc/Makefile b/arch/arm/mach-adifcc/Makefile deleted file mode 100644 index d8c1959e9483..000000000000 --- a/arch/arm/mach-adifcc/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for the linux kernel. -# - -# Object file lists. - -obj-y := arch.o irq.o mm.o -obj-m := -obj-n := -obj- := - diff --git a/arch/arm/mach-adifcc/arch.c b/arch/arm/mach-adifcc/arch.c deleted file mode 100644 index bfc59556d9da..000000000000 --- a/arch/arm/mach-adifcc/arch.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * linux/arch/arm/mach-adifcc/arch.c - * - * Copyright (C) 2001 MontaVista Software, Inc. - * - * This program 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. - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -extern void adifcc_map_io(void); -extern void adifcc_init_irq(void); - -#ifdef CONFIG_ARCH_ADI_EVB -MACHINE_START(ADI_EVB, "ADI 80200FCC Evaluation Board") - MAINTAINER("MontaVista Software Inc.") - BOOT_MEM(0xc0000000, 0x00400000, 0xff400000) - MAPIO(adifcc_map_io) - INITIRQ(adifcc_init_irq) -MACHINE_END -#endif - diff --git a/arch/arm/mach-adifcc/irq.c b/arch/arm/mach-adifcc/irq.c deleted file mode 100644 index 4163c602dc2f..000000000000 --- a/arch/arm/mach-adifcc/irq.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * linux/arch/arm/mach-xscale/irq.c - * - * Author: Deepak Saxena - * Copyright: (C) 2001 MontaVista Software Inc. - * - * This program 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. - * - * Based on IOP80310 code. Currently there's nothing more than the - * 80200 on chip interrupts. That'll change once the hardware adds - * support for PCI though. - */ -#include -#include - -#include -#include -#include - -static void xs80200_irq_mask (unsigned int irq) -{ - long INTCTL; - asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (INTCTL)); - switch (irq) { - case IRQ_XS80200_BCU: INTCTL &= ~(1<<3); break; - case IRQ_XS80200_PMU: INTCTL &= ~(1<<2); break; - case IRQ_XS80200_EXTIRQ: INTCTL &= ~(1<<1); break; - case IRQ_XS80200_EXTFIQ: INTCTL &= ~(1<<0); break; - } - asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (INTCTL)); -} - -static void xs80200_irq_unmask (unsigned int irq) -{ - long INTCTL; - asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (INTCTL)); - switch (irq) { - case IRQ_XS80200_BCU: INTCTL |= (1<<3); break; - case IRQ_XS80200_PMU: INTCTL |= (1<<2); break; - case IRQ_XS80200_EXTIRQ: INTCTL |= (1<<1); break; - case IRQ_XS80200_EXTFIQ: INTCTL |= (1<<0); break; - } - asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (INTCTL)); -} - -void __init adifcc_init_irq(void) -{ - int i; - - for (i = 0; i < NR_XS80200_IRQS; i++) { - irq_desc[i].valid = 1; - irq_desc[i].probe_ok = 0; - irq_desc[i].mask_ack = xs80200_irq_mask; - irq_desc[i].mask = xs80200_irq_mask; - irq_desc[i].unmask = xs80200_irq_unmask; - } -} - - diff --git a/arch/arm/mach-adifcc/mm.c b/arch/arm/mach-adifcc/mm.c deleted file mode 100644 index a81a9794ff10..000000000000 --- a/arch/arm/mach-adifcc/mm.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * linux/arch/arm/mach-xscale/mm.c - */ -#include -#include -#include - -#include -#include -#include - -#include - - -static struct map_desc adifcc_io_desc[] __initdata = { - /* on-board devices */ - { 0xff400000, 0x00400000, 0x00300000, MT_DEVICE } -}; - -void __init adifcc_map_io(void) -{ - iotable_init(adifcc_io_desc, ARRAY_SIZE(adifcc_io_desc)); -} diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index ba32817ad59f..545a548b1f69 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -220,7 +220,7 @@ config CPU_SA1100 # XScale config CPU_XSCALE bool - depends on ARCH_IOP3XX || ARCH_ADIFCC || ARCH_PXA || ARCH_IXP4XX + depends on ARCH_IOP3XX || ARCH_PXA || ARCH_IXP4XX default y select CPU_32v5 select CPU_ABRT_EV5T diff --git a/include/asm-arm/arch-adifcc/adi_evb.h b/include/asm-arm/arch-adifcc/adi_evb.h deleted file mode 100644 index f4b74c6fcf9a..000000000000 --- a/include/asm-arm/arch-adifcc/adi_evb.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * linux/include/asm/arch-80200fcc/adi_evb.h - * - * ADI 80200FCC evaluation board definitions - * - * Author: Deepak Saxena - * - * Copyright (C) 2001 MontaVista Software Inc. - * - * 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; either version 2 of the License, or (at your - * option) any later version. - */ - -#define ADI_EVB__RAMBASE 0xa0000000 -#define ADI_EVB__UART 0x00400000 /* UART */ -#define ADI_EVB_7SEG_1 0x00500000 /* 7-Segment */ - diff --git a/include/asm-arm/arch-adifcc/dma.h b/include/asm-arm/arch-adifcc/dma.h deleted file mode 100644 index 19aa1dbc3be7..000000000000 --- a/include/asm-arm/arch-adifcc/dma.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * linux/include/asm-arm/arch-80200fcc/dma.h - * - * Copyright (C) 2001 MontaVista Software, Inc. - * - * This program 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. - */ -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H - -#define MAX_DMA_ADDRESS 0xffffffff - -/* No DMA */ -#define MAX_DMA_CHANNELS 0 - -#endif /* _ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-adifcc/hardware.h b/include/asm-arm/arch-adifcc/hardware.h deleted file mode 100644 index 9eeb3cb507da..000000000000 --- a/include/asm-arm/arch-adifcc/hardware.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * linux/include/asm-arm/arch-adifcc/hardware.h - * - * Hardware definitions for ADI based systems - * - * Author: Deepak Saxena - * - * Copyright (C) 2000-2001 MontaVista Software Inc. - * - * 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; either version 2 of the License, or (at your - * option) any later version. - */ - -#ifndef __ASM_ARCH_HARDWARE_H -#define __ASM_ARCH_HARDWARE_H - -#include - -#define PCIO_BASE 0 - -#if defined(CONFIG_ARCH_ADI_EVB) -#include "adi_evb.h" -#endif - -#endif /* _ASM_ARCH_HARDWARE_H */ diff --git a/include/asm-arm/arch-adifcc/io.h b/include/asm-arm/arch-adifcc/io.h deleted file mode 100644 index bdcaec08bddf..000000000000 --- a/include/asm-arm/arch-adifcc/io.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * linux/include/asm-arm/arch-adifcc/io.h - * - * Author: Deepak Saxena - * - * Copyright (C) 2001 MontaVista Software, Inc. - * - * This program 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. - */ - -#ifndef __ASM_ARM_ARCH_IO_H -#define __ASM_ARM_ARCH_IO_H - -#define IO_SPACE_LIMIT 0xffffffff - -#define __io(a) (PCIO_BASE + (a)) -#define __mem_pci(a) ((unsigned long)(a)) -#define __mem_isa(a) ((unsigned long)(a)) - -#endif diff --git a/include/asm-arm/arch-adifcc/irqs.h b/include/asm-arm/arch-adifcc/irqs.h deleted file mode 100644 index b559ca79ef80..000000000000 --- a/include/asm-arm/arch-adifcc/irqs.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * linux/include/asm-arm/arch-80200fcc/irqs.h - * - * Author: Deepak Saxena - * Copyright: (C) 2001 MontaVista Software Inc. - * - * This program 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. - */ - -#define IRQ_XS80200_BCU 0 /* Bus Control Unit */ -#define IRQ_XS80200_PMU 1 /* Performance Monitoring Unit */ -#define IRQ_XS80200_EXTIRQ 2 /* external IRQ signal */ -#define IRQ_XS80200_EXTFIQ 3 /* external IRQ signal */ - -#define NR_XS80200_IRQS 4 -#define NR_IRQS NR_XS80200_IRQS - -#define IRQ_XSCALE_PMU IRQ_XS80200_PMU diff --git a/include/asm-arm/arch-adifcc/memory.h b/include/asm-arm/arch-adifcc/memory.h deleted file mode 100644 index b76187d8d42b..000000000000 --- a/include/asm-arm/arch-adifcc/memory.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * linux/include/asm-arm/arch-adifcc/memory.h - * - * Copyright (c) 2001 MontaVista Software, Inc. - */ - -#ifndef __ASM_ARCH_MEMORY_H -#define __ASM_ARCH_MEMORY_H - -/* - * Physical DRAM offset. - */ -#define PHYS_OFFSET (0xC0000000UL) - -/* - * Virtual view <-> DMA view memory address translations - * virt_to_bus: Used to translate the virtual address to an - * address suitable to be passed to set_dma_addr - * bus_to_virt: Used to convert an address for DMA operations - * to an address that the kernel can use. - * - * These are dummies for now. - */ -#define __virt_to_bus(x) __virt_to_phys(x) -#define __bus_to_virt(x) __phys_to_virt(x) - -#endif diff --git a/include/asm-arm/arch-adifcc/param.h b/include/asm-arm/arch-adifcc/param.h deleted file mode 100644 index b1a410eff447..000000000000 --- a/include/asm-arm/arch-adifcc/param.h +++ /dev/null @@ -1,3 +0,0 @@ -/* - * linux/include/asm-arm/arch-adifcc/param.h - */ diff --git a/include/asm-arm/arch-adifcc/serial.h b/include/asm-arm/arch-adifcc/serial.h deleted file mode 100644 index ce4e87699c91..000000000000 --- a/include/asm-arm/arch-adifcc/serial.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * include/asm-arm/arch-adifcc/serial.h - * - * Author: Deepak Saxena - * - * Copyright (c) 2001 MontaVista Software, Inc. - */ -#include - -/* - * This assumes you have a 1.8432 MHz clock for your UART. - * - * It'd be nice if someone built a serial card with a 24.576 MHz - * clock, since the 16550A is capable of handling a top speed of 1.5 - * megabits/second; but this requires the faster clock. - */ -#define BASE_BAUD ( 1852000 / 16 ) - -/* Standard COM flags */ -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) - -#ifdef CONFIG_ARCH_ADI_EVB - -/* - * One serial port, int goes to FIQ, so we run in polled mode - */ -#define STD_SERIAL_PORT_DEFNS \ - /* UART CLK PORT IRQ FLAGS */ \ - { 0, BASE_BAUD, 0xff400000, 0, STD_COM_FLAGS } /* ttyS0 */ - -#define EXTRA_SERIAL_PORT_DEFNS - -#endif - diff --git a/include/asm-arm/arch-adifcc/system.h b/include/asm-arm/arch-adifcc/system.h deleted file mode 100644 index 4bffbdc294a0..000000000000 --- a/include/asm-arm/arch-adifcc/system.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * linux/include/asm-arm/arch-adifcc/system.h - * - * Copyright (C) 2001 MontaVista Software, Inc. - * - * This program 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. - */ - -static inline void arch_idle(void) -{ -#if 0 - cpu_do_idle(); -#endif -} - - -static inline void arch_reset(char mode) -{ - if ( 1 && mode == 's') { - /* Jump into ROM at address 0 */ - cpu_reset(0); - } else { - /* Use on-chip reset capability */ - } -} - diff --git a/include/asm-arm/arch-adifcc/timex.h b/include/asm-arm/arch-adifcc/timex.h deleted file mode 100644 index d994c8abecd5..000000000000 --- a/include/asm-arm/arch-adifcc/timex.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * linux/include/asm-arm/arch-adifcc/timex.h - * - * XScale architecture timex specifications - */ - -/* This is for a timer based on the XS80200's PMU counter */ - -#define CLOCK_TICK_RATE 600000000 /* Underlying HZ */ - diff --git a/include/asm-arm/arch-adifcc/uncompress.h b/include/asm-arm/arch-adifcc/uncompress.h deleted file mode 100644 index 792b4e17aa86..000000000000 --- a/include/asm-arm/arch-adifcc/uncompress.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * linux/include/asm-arm/arch-adifcc/uncompress.h - * - * Author: Deepak Saxena - * - * Copyright (c) 2001 MontaVista Software, Inc. - * - */ - -#define UART_BASE ((volatile unsigned char *)0x00400000) - -static __inline__ void putc(char c) -{ - while ((UART_BASE[5] & 0x60) != 0x60); - UART_BASE[0] = c; -} - -/* - * This does not append a newline - */ -static void puts(const char *s) -{ - while (*s) { - putc(*s); - if (*s == '\n') - putc('\r'); - s++; - } -} - -/* - * nothing to do - */ -#define arch_decomp_setup() -#define arch_decomp_wdog() diff --git a/include/asm-arm/arch-adifcc/vmalloc.h b/include/asm-arm/arch-adifcc/vmalloc.h deleted file mode 100644 index d45b27e1ad0e..000000000000 --- a/include/asm-arm/arch-adifcc/vmalloc.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * linux/include/asm-arm/arch-adifcc/vmalloc.h - */ - -/* - * Just any arbitrary offset to the start of the vmalloc VM area: the - * current 8MB value just means that there will be a 8MB "hole" after the - * physical memory until the kernel virtual memory starts. That means that - * any out-of-bounds memory accesses will hopefully be caught. - * The vmalloc() routines leaves a hole of 4kB between each vmalloced - * area for the same reason. ;) - */ -#define VMALLOC_OFFSET (8*1024*1024) -#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) -#define VMALLOC_END (0xe8000000) -- cgit v1.2.3 From c4a9c8212b8e954da29dc2e9002842729c0ba6d1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 17 Jun 2004 23:37:04 -0700 Subject: [PATCH] Couple of sysfs patches On Wed, Jun 16, 2004 at 05:51:03PM -0500, Dmitry Torokhov wrote: > What about freeing the resources? Can it be put in platform_device_unregister > or is it release handler task? I'd put it in unregister because when I call > unregister I expect device be half-dead and release as much resources as it > can. Here's the updated patch - to be applied on top of the platform_get_resource() patch sent previously. Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 91 ++++++++++++++++++++++++++++--------------------- include/linux/device.h | 1 - 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index aca1717eddd2..dcb875e487d2 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -54,39 +54,6 @@ int platform_get_irq(struct platform_device *dev, unsigned int num) return r ? r->start : 0; } -/** - * platform_add_device - add one platform device - * @dev: platform device - * - * Adds one platform device, claiming the memory resources - */ -int platform_add_device(struct platform_device *dev) -{ - int i; - - for (i = 0; i < dev->num_resources; i++) { - struct resource *p, *r = &dev->resource[i]; - - r->name = dev->dev.bus_id; - - p = NULL; - if (r->flags & IORESOURCE_MEM) - p = &iomem_resource; - else if (r->flags & IORESOURCE_IO) - p = &ioport_resource; - - if (p && request_resource(p, r)) { - printk(KERN_ERR - "%s%d: failed to claim resource %d\n", - dev->name, dev->id, i); - break; - } - } - if (i == dev->num_resources) - platform_device_register(dev); - return 0; -} - /** * platform_add_devices - add a numbers of platform devices * @devs: array of platform devices to add @@ -94,12 +61,18 @@ int platform_add_device(struct platform_device *dev) */ int platform_add_devices(struct platform_device **devs, int num) { - int i; + int i, ret = 0; - for (i = 0; i < num; i++) - platform_add_device(devs[i]); + for (i = 0; i < num; i++) { + ret = platform_device_register(devs[i]); + if (ret) { + while (--i >= 0) + platform_device_unregister(devs[i]); + break; + } + } - return 0; + return ret; } /** @@ -109,6 +82,8 @@ int platform_add_devices(struct platform_device **devs, int num) */ int platform_device_register(struct platform_device * pdev) { + int i, ret = 0; + if (!pdev) return -EINVAL; @@ -122,15 +97,53 @@ int platform_device_register(struct platform_device * pdev) else strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE); + for (i = 0; i < pdev->num_resources; i++) { + struct resource *p, *r = &pdev->resource[i]; + + r->name = pdev->dev.bus_id; + + p = NULL; + if (r->flags & IORESOURCE_MEM) + p = &iomem_resource; + else if (r->flags & IORESOURCE_IO) + p = &ioport_resource; + + if (p && request_resource(p, r)) { + printk(KERN_ERR + "%s: failed to claim resource %d\n", + pdev->dev.bus_id, i); + ret = -EBUSY; + goto failed; + } + } + pr_debug("Registering platform device '%s'. Parent at %s\n", pdev->dev.bus_id, pdev->dev.parent->bus_id); - return device_register(&pdev->dev); + + ret = device_register(&pdev->dev); + if (ret == 0) + return ret; + + failed: + while (--i >= 0) + if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO)) + release_resource(&pdev->resource[i]); + return ret; } void platform_device_unregister(struct platform_device * pdev) { - if (pdev) + int i; + + if (pdev) { device_unregister(&pdev->dev); + + for (i = 0; i < pdev->num_resources; i++) { + struct resource *r = &pdev->resource[i]; + if (r->flags & (IORESOURCE_MEM|IORESOURCE_IO)) + release_resource(r); + } + } } diff --git a/include/linux/device.h b/include/linux/device.h index ed170f81ab60..3f6e14c099e2 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -379,7 +379,6 @@ extern struct device platform_bus; extern struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int); extern int platform_get_irq(struct platform_device *, unsigned int); -extern int platform_add_device(struct platform_device *); extern int platform_add_devices(struct platform_device **, int); /* drivers/base/power.c */ -- cgit v1.2.3 From d51d5d95df511761ed5493df34aa8c2a7e33e900 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sun, 20 Jun 2004 00:18:46 -0700 Subject: [NET]: Fix module refcounting of TC actions. --- include/linux/pkt_cls.h | 27 ++++++++++++------ include/linux/pkt_sched.h | 6 ++++ include/net/pkt_act.h | 14 +++++----- include/net/pkt_sched.h | 15 ++++++---- net/sched/Kconfig | 12 +++++--- net/sched/act_api.c | 70 ++++++++++++++++++++++++++++++++++++----------- net/sched/cls_u32.c | 25 ++++++++--------- net/sched/police.c | 27 ++++++++++-------- net/sched/sch_prio.c | 3 +- 9 files changed, 133 insertions(+), 66 deletions(-) diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index 74daa67e81c9..06e4e728d4fc 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -71,16 +71,14 @@ bits 9,10,11: redirect counter - redirect TTL. Loop avoidance #define V_TC_AT(x) _TC_MAKEVALUE(x,S_TC_AT) #define SET_TC_AT(v,n) ((V_TC_AT(n)) | (v & ~M_TC_AT)) -/* Action types */ +/* Action attributes */ enum { - TCA_ACT_UNSPEC=0, - TCA_ACT_KIND=1, - TCA_ACT_OPTIONS=2, - TCA_ACT_INDEX=3, - TCA_ACT_POLICE=4, - /* other actions go here */ - __TCA_ACT_MAX=255 + TCA_ACT_UNSPEC, + TCA_ACT_KIND, + TCA_ACT_OPTIONS, + TCA_ACT_INDEX, + __TCA_ACT_MAX }; #define TCA_ACT_MAX __TCA_ACT_MAX @@ -105,6 +103,17 @@ enum #define TC_ACT_REPEAT 6 #define TC_ACT_JUMP 0x10000000 +/* Action type identifiers*/ +enum +{ + TCA_ID_UNSPEC=0, + TCA_ID_POLICE=1, + /* other actions go here */ + __TCA_ID_MAX=255 +}; + +#define TCA_ID_MAX __TCA_ID_MAX + struct tc_police { __u32 index; @@ -213,7 +222,9 @@ struct tc_u32_sel unsigned char flags; unsigned char offshift; unsigned char nkeys; +#ifdef fix_u32_bug unsigned char fshift; /* fold shift */ +#endif __u16 offmask; __u16 off; diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index 437cf3206e0e..86f98b500fa6 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -37,7 +37,13 @@ struct tc_stats __u32 bps; /* Current flow byte rate */ __u32 pps; /* Current flow packet rate */ __u32 qlen; +#ifdef CONFIG_NET_CLS_ACT +/* eventually remove the define here; adding this(useful) +field at least fixes the 8 byte layout problems we +have with MIPS and PPC because we have a u64 +*/ __u32 reqs; /* number of requeues happened */ +#endif __u32 backlog; #ifdef __KERNEL__ spinlock_t *lock; diff --git a/include/net/pkt_act.h b/include/net/pkt_act.h index 390b82aea577..9f37ac40f1a0 100644 --- a/include/net/pkt_act.h +++ b/include/net/pkt_act.h @@ -69,20 +69,21 @@ tcf_hash_destroy(struct tcf_st *p) BUG_TRAP(0); } -static inline void +static inline int tcf_hash_release(struct tcf_st *p, int bind ) { + int ret = 0; if (p) { if (bind) { p->bindcnt--; } p->refcnt--; - if (p->refcnt > 0) - MOD_DEC_USE_COUNT; if(p->bindcnt <=0 && p->refcnt <= 0) { tcf_hash_destroy(p); + ret = 1; } } + return ret; } static __inline__ int @@ -117,7 +118,6 @@ tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb, r->rta_len = skb->tail - (u8*)r; n_i++; if (n_i >= TCA_ACT_MAX_PRIO) { - printk("Jamal Dump Exceeded batch limit\n"); goto done; } } @@ -148,8 +148,9 @@ tcf_del_walker(struct sk_buff *skb, struct tc_action *a) while (p != NULL) { s_p = p->next; - printk("tcf_del_walker deleting ..\n"); - tcf_hash_release(p, 0); + if (ACT_P_DELETED == tcf_hash_release(p, 0)) { + module_put(a->ops->owner); + } n_i++; p = s_p; } @@ -250,7 +251,6 @@ tcf_hash_create(struct tc_st *parm, struct rtattr *est, struct tc_action *a, int p->bindcnt = 1; } - MOD_INC_USE_COUNT; spin_lock_init(&p->lock); p->stats.lock = &p->lock; p->index = parm->index ? : tcf_hash_new_index(); diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index eb6c344ddd95..f0d5fc3b66cc 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -414,6 +414,8 @@ struct tcf_police #ifdef CONFIG_NET_CLS_ACT +#define ACT_P_CREATED 1 +#define ACT_P_DELETED 1 #define tca_gen(name) \ struct tcf_##name *next; \ u32 index; \ @@ -442,10 +444,11 @@ struct tc_action_ops char kind[IFNAMSIZ]; __u32 type; /* TBD to match kind */ __u32 capab; /* capabilities includes 4 bit version */ + struct module *owner; int (*act)(struct sk_buff **, struct tc_action *); int (*get_stats)(struct sk_buff *, struct tc_action *); int (*dump)(struct sk_buff *, struct tc_action *,int , int); - void (*cleanup)(struct tc_action *, int bind); + int (*cleanup)(struct tc_action *, int bind); int (*lookup)(struct tc_action *, u32 ); int (*init)(struct rtattr *,struct rtattr *,struct tc_action *, int , int ); int (*walk)(struct sk_buff *, struct netlink_callback *, int , struct tc_action *); @@ -472,24 +475,26 @@ extern void tcf_police_destroy(struct tcf_police *p); extern struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est); extern int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p); -static inline void tcf_police_release(struct tcf_police *p, int bind) +static inline int tcf_police_release(struct tcf_police *p, int bind) { + int ret = 0; #ifdef CONFIG_NET_CLS_ACT if (p) { if (bind) { p->bindcnt--; } p->refcnt--; - if (p->refcnt > 0) - MOD_DEC_USE_COUNT; - if (p->refcnt <= 0 && !p->bindcnt) + if (p->refcnt <= 0 && !p->bindcnt) { tcf_police_destroy(p); + ret = 1; + } } #else if (p && --p->refcnt == 0) tcf_police_destroy(p); #endif + return ret; } extern struct Qdisc noop_qdisc; diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 481b8ad2b84c..924e9f2dcee7 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -280,6 +280,7 @@ config CLS_U32_PERF help gathers stats that could be used to tune u32 classifier perfomance. Requires a new iproute2 + You MUST NOT turn this on if you dont have an update iproute2. config NET_CLS_IND bool "classify input device (slows things u32/fw) " @@ -289,6 +290,7 @@ config NET_CLS_IND metadata action appears because it slows things a little Available only for u32 and fw classifiers. Requires a new iproute2 + You MUST NOT turn this on if you dont have an update iproute2. config NET_CLS_RSVP tristate "Special RSVP classifier" @@ -321,22 +323,24 @@ config NET_CLS_RSVP6 config NET_CLS_ACT bool ' Packet ACTION ' - depends on NET_CLS && NET_QOS + depends on EXPERIMENTAL && NET_CLS && NET_QOS ---help--- This option requires you have a new iproute2. It enables tc extensions which can be used with tc classifiers. Only the u32 and fw classifiers are supported at the moment. + You MUST NOT turn this on if you dont have an update iproute2. config NET_ACT_POLICE tristate ' Policing Actions' - depends on NET_CLS_ACT + depends on NET_CLS_ACT ---help--- If you are using a newer iproute2 select this one, otherwise use one - NET_CLS_POLICE below + below to select a policer. + You MUST NOT turn this on if you dont have an update iproute2. config NET_CLS_POLICE bool "Traffic policing (needed for in/egress)" - depends on NET_CLS && NET_QOS && !NET_ACT_POLICE + depends on NET_CLS && NET_QOS && NET_ACT_POLICE!=y && NET_ACT_POLICE!=m help Say Y to support traffic policing (bandwidth limits). Needed for ingress and egress rate limiting. diff --git a/net/sched/act_api.c b/net/sched/act_api.c index a0ba2f6363e9..91076dc78b5d 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -48,11 +48,12 @@ int tcf_register_action(struct tc_action_ops *act) write_lock(&act_mod_lock); for (ap = &act_base; (a=*ap)!=NULL; ap = &a->next) { - if (strcmp(act->kind, a->kind) == 0) { + if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) { write_unlock(&act_mod_lock); return -EEXIST; } } + act->next = NULL; *ap = act; @@ -89,8 +90,13 @@ struct tc_action_ops *tc_lookup_action_n(char *kind) if (kind) { read_lock(&act_mod_lock); for (a = act_base; a; a = a->next) { - if (strcmp(kind,a->kind) == 0) + if (strcmp(kind,a->kind) == 0) { + if (!try_module_get(a->owner)) { + read_unlock(&act_mod_lock); + return NULL; + } break; + } } read_unlock(&act_mod_lock); } @@ -108,8 +114,13 @@ struct tc_action_ops *tc_lookup_action(struct rtattr *kind) read_lock(&act_mod_lock); for (a = act_base; a; a = a->next) { - if (strcmp((char*)RTA_DATA(kind),a->kind) == 0) + if (strcmp((char*)RTA_DATA(kind),a->kind) == 0){ + if (!try_module_get(a->owner)) { + read_unlock(&act_mod_lock); + return NULL; + } break; + } } read_unlock(&act_mod_lock); } @@ -125,8 +136,13 @@ struct tc_action_ops *tc_lookup_action_id(u32 type) if (type) { read_lock(&act_mod_lock); for (a = act_base; a; a = a->next) { - if (a->type == type) + if (a->type == type) { + if (!try_module_get(a->owner)) { + read_unlock(&act_mod_lock); + return NULL; + } break; + } } read_unlock(&act_mod_lock); } @@ -177,7 +193,10 @@ void tcf_action_destroy(struct tc_action *act, int bind) if (a && a->ops && a->ops->cleanup) { DPRINTK("tcf_action_destroy destroying %p next %p\n", a,a->next?a->next:NULL); act = act->next; - a->ops->cleanup(a, bind); + if (ACT_P_DELETED == a->ops->cleanup(a, bind)) { + module_put(a->ops->owner); + } + a->ops = NULL; kfree(a); } else { /*FIXME: Remove later - catch insertion bugs*/ @@ -270,7 +289,6 @@ int tcf_action_init_1(struct rtattr *rta, struct rtattr *est, struct tc_action * int err = -EINVAL; - if (NULL == name) { if (rtattr_parse(tb, TCA_ACT_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta))<0) goto err_out; @@ -306,27 +324,37 @@ int tcf_action_init_1(struct rtattr *rta, struct rtattr *est, struct tc_action * } if (NULL == a) { - goto err_out; + goto err_mod; } /* backward compatibility for policer */ if (NULL == name) { err = a_o->init(tb[TCA_ACT_OPTIONS-1], est, a, ovr, bind); if (0 > err ) { - return -EINVAL; + err = -EINVAL; + goto err_mod; } } else { err = a_o->init(rta, est, a, ovr, bind); if (0 > err ) { - return -EINVAL; + err = -EINVAL; + goto err_mod; } } - DPRINTK("tcf_action_init_1: sucess %s\n",act_name); - + /* module count goes up only when brand new policy is created + if it exists and is only bound to in a_o->init() then + ACT_P_CREATED is not returned (a zero is). + */ + if (ACT_P_CREATED != err) { + module_put(a_o->owner); + } a->ops = a_o; + DPRINTK("tcf_action_init_1: successfull %s \n",act_name); return 0; +err_mod: + module_put(a_o->owner); err_out: return err; } @@ -350,7 +378,7 @@ int tcf_action_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, err = -ENOMEM; goto bad_ret; } - memset(act, 0,sizeof(*act)); + memset(act, 0,sizeof(*act)); } act->next = NULL; if (0 > tcf_action_init_1(tb[i],est,act,name,ovr,bind)) { @@ -489,15 +517,21 @@ int tcf_action_get_1(struct rtattr *rta, struct tc_action *a, struct nlmsghdr *n } if (NULL == a) { - goto err_out; + goto err_mod; } a->ops = a_o; - if (NULL == a_o->lookup || 0 == a_o->lookup(a, index)) - return -EINVAL; + if (NULL == a_o->lookup || 0 == a_o->lookup(a, index)) { + a->ops = NULL; + err = -EINVAL; + goto err_mod; + } + module_put(a_o->owner); return 0; +err_mod: + module_put(a_o->owner); err_out: return err; } @@ -621,6 +655,7 @@ int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid) nlh->nlmsg_len = skb->tail - b; nlh->nlmsg_flags |= NLM_F_ROOT; + module_put(a->ops->owner); kfree(a); err = rtnetlink_send(skb, pid, RTMGRP_TC, n->nlmsg_flags&NLM_F_ECHO); if (err > 0) @@ -630,6 +665,7 @@ int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid) rtattr_failure: + module_put(a->ops->owner); nlmsg_failure: err_out: kfree_skb(skb); @@ -852,7 +888,7 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg) char * find_dump_kind(struct nlmsghdr *n) { - struct rtattr *tb1, *tb2[TCA_ACT_MAX_PRIO+1]; + struct rtattr *tb1, *tb2[TCA_ACT_MAX+1]; struct rtattr *tb[TCA_ACT_MAX_PRIO + 1]; struct rtattr *rta[TCAA_MAX + 1]; struct rtattr *kind = NULL; @@ -941,10 +977,12 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) nlh->nlmsg_len = skb->tail - b; if (NETLINK_CB(cb->skb).pid && ret) nlh->nlmsg_flags |= NLM_F_MULTI; + module_put(a_o->owner); return skb->len; rtattr_failure: nlmsg_failure: + module_put(a_o->owner); skb_trim(skb, b - skb->data); return skb->len; } diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 7ea20b622fc8..24620274d6b8 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -101,12 +101,14 @@ static struct tc_u_common *u32_list; static __inline__ unsigned u32_hash_fold(u32 key, struct tc_u32_sel *sel) { +#ifdef fix_u32_bug unsigned h = (key & sel->hmask)>>sel->fshift; +#else + unsigned h = (key & sel->hmask); - /* h ^= h>>16; h ^= h>>8; - */ +#endif return h; } @@ -684,6 +686,14 @@ static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, return -EINVAL; s = RTA_DATA(tb[TCA_U32_SEL-1]); + +#ifdef CONFIG_CLS_U32_PERF + if (RTA_PAYLOAD(tb[TCA_U32_SEL-1]) < + (s->nkeys*sizeof(struct tc_u32_key)) + sizeof(struct tc_u32_sel)) { + printk("Please upgrade your iproute2 tools or compile proper options in!\n"); + return -EINVAL; +} +#endif n = kmalloc(sizeof(*n) + s->nkeys*sizeof(struct tc_u32_key), GFP_KERNEL); if (n == NULL) return -ENOBUFS; @@ -775,18 +785,7 @@ static int u32_dump(struct tcf_proto *tp, unsigned long fh, if (n->ht_down) RTA_PUT(skb, TCA_U32_LINK, 4, &n->ht_down->handle); #ifdef CONFIG_CLS_U32_PERF2 - printk("fh %x cnt %lu hit %lu\n",n->handle,n->sel.rcnt,n->sel.rhit); n->sel.rcnt = n->sel.rhit = 0; - /* dump key cnt */ - { - int i = 0; - struct tc_u32_key *key = n->sel.keys; - for (i = n->sel.nkeys; i>0; i--, key++) { - printk("\t key%d success %lu\n",i,key->kcnt); - key->cnt = 0; - } - } - #endif #ifdef CONFIG_NET_CLS_ACT /* again for backward compatible mode - we want diff --git a/net/sched/police.c b/net/sched/police.c index 14ccbae43858..2556651b7366 100644 --- a/net/sched/police.c +++ b/net/sched/police.c @@ -166,6 +166,7 @@ void tcf_police_destroy(struct tcf_police *p) int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_action *a, int ovr, int bind) { unsigned h; + int ret = 0; struct rtattr *tb[TCA_POLICE_MAX]; struct tc_police *parm; struct tcf_police *p; @@ -195,7 +196,7 @@ int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_actio goto override; } spin_unlock(&p->lock); - return 1; + return ret; } p = kmalloc(sizeof(*p), GFP_KERNEL); @@ -203,7 +204,7 @@ int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_actio return -1; memset(p, 0, sizeof(*p)); - MOD_INC_USE_COUNT; + ret = 1; p->refcnt = 1; spin_lock_init(&p->lock); p->stats.lock = &p->lock; @@ -211,11 +212,13 @@ int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_actio p->bindcnt = 1; override: if (parm->rate.rate) { - if ((p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1])) == NULL) + if ((p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1])) == NULL) { goto failure; + } if (parm->peakrate.rate && - (p->P_tab = qdisc_get_rtab(&parm->peakrate, tb[TCA_POLICE_PEAKRATE-1])) == NULL) + (p->P_tab = qdisc_get_rtab(&parm->peakrate, tb[TCA_POLICE_PEAKRATE-1])) == NULL) { goto failure; + } } if (tb[TCA_POLICE_RESULT-1]) p->result = *(int*)RTA_DATA(tb[TCA_POLICE_RESULT-1]); @@ -236,7 +239,7 @@ override: if (ovr) { spin_unlock(&p->lock); - return 1; + return ret; } PSCHED_GET_TIME(p->t_c); p->index = parm->index ? : tcf_police_new_index(); @@ -250,9 +253,8 @@ override: tcf_police_ht[h] = p; write_unlock_bh(&police_lock); - MOD_INC_USE_COUNT; a->priv = (void *)p; - return 1; + return ret; failure: if (p->R_tab) @@ -263,12 +265,14 @@ failure: return -1; } -void tcf_act_police_cleanup(struct tc_action *a, int bind) +int tcf_act_police_cleanup(struct tc_action *a, int bind) { struct tcf_police *p; p = PRIV(a); if (NULL != p) - tcf_police_release(p, bind); + return tcf_police_release(p, bind); + + return 0; } int tcf_act_police_stats(struct sk_buff *skb, struct tc_action *a) @@ -392,8 +396,9 @@ MODULE_LICENSE("GPL"); struct tc_action_ops act_police_ops = { NULL, "police", - TCA_ACT_POLICE, + TCA_ID_POLICE, TCA_CAP_NONE, + THIS_MODULE, tcf_act_police, tcf_act_police_stats, tcf_act_police_dump, @@ -437,7 +442,6 @@ struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) if (parm->index && (p = tcf_police_lookup(parm->index)) != NULL) { p->refcnt++; - MOD_INC_USE_COUNT; return p; } @@ -483,7 +487,6 @@ struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) p->next = tcf_police_ht[h]; tcf_police_ht[h] = p; write_unlock_bh(&police_lock); - MOD_INC_USE_COUNT; return p; failure: diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 52a4c2e28272..fa6741d96a27 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -129,11 +129,12 @@ dropped: static int prio_requeue(struct sk_buff *skb, struct Qdisc* sch) { - //struct prio_sched_data *q = (struct prio_sched_data *)sch->data; struct Qdisc *qdisc; int ret = NET_XMIT_DROP; +#ifdef CONFIG_NET_CLS_ACT sch->stats.reqs++; +#endif qdisc = prio_classify(skb, sch, &ret); if (qdisc == NULL) goto dropped; -- cgit v1.2.3 From ba5d92231e4cdea031a85e91aefca3e14c12ae8e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 20 Jun 2004 03:40:34 -0700 Subject: [SPARC64]: bug.h needs compiler.h Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- include/asm-sparc64/bug.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/asm-sparc64/bug.h b/include/asm-sparc64/bug.h index bdaba5ccc11e..bfac1afa9983 100644 --- a/include/asm-sparc64/bug.h +++ b/include/asm-sparc64/bug.h @@ -3,6 +3,8 @@ #ifndef _SPARC64_BUG_H #define _SPARC64_BUG_H +#include + #ifdef CONFIG_DEBUG_BUGVERBOSE extern void do_BUG(const char *file, int line); #define BUG() do { \ -- cgit v1.2.3 From 3beb5b3948aaf0d09956039f9e4414566465b7f9 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 20 Jun 2004 17:33:23 -0300 Subject: [NET] generalise wait_for_tcp_connect This will be used by the poor cousins, look, for instance, at x25_wait_for_connection_establishment :-) Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/tcp.h | 2 -- include/net/sock.h | 4 ++++ net/core/sock.c | 1 + net/core/stream.c | 37 +++++++++++++++++++++++++++++++++++++ net/ipv4/tcp.c | 43 ++++--------------------------------------- net/ipv4/tcp_input.c | 2 +- 6 files changed, 47 insertions(+), 42 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 39e2d22619dc..f807f0507815 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -371,8 +371,6 @@ struct tcp_opt { struct open_request *accept_queue; struct open_request *accept_queue_tail; - int write_pending; /* A write to socket waits to start. */ - unsigned int keepalive_time; /* time before keep alive takes place */ unsigned int keepalive_intvl; /* time interval between keep alive probes */ int linger2; diff --git a/include/net/sock.h b/include/net/sock.h index 0ee6ccddca40..0a7546a9957c 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -167,6 +167,7 @@ struct sock_common { * @sk_socket - Identd and reporting IO signals * @sk_user_data - RPC layer private data * @sk_owner - module that owns this socket + * @sk_write_pending - a write to stream socket waits to start * @sk_state_change - callback to indicate change in the state of the sock * @sk_data_ready - callback to indicate there is data to be processed * @sk_write_space - callback to indicate there is bf sending space available @@ -247,6 +248,7 @@ struct sock { struct socket *sk_socket; void *sk_user_data; struct module *sk_owner; + int sk_write_pending; void *sk_security; void (*sk_state_change)(struct sock *sk); void (*sk_data_ready)(struct sock *sk, int bytes); @@ -458,6 +460,8 @@ do { if (!(__sk)->sk_backlog.tail) { \ rc; \ }) +extern int sk_stream_wait_connect(struct sock *sk, long *timeo_p); + extern int sk_wait_data(struct sock *sk, long *timeo); /* IP protocol blocks we attach to sockets. diff --git a/net/core/sock.c b/net/core/sock.c index 289f5824e97c..cc84b85f5b0f 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1176,6 +1176,7 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_peercred.pid = 0; sk->sk_peercred.uid = -1; sk->sk_peercred.gid = -1; + sk->sk_write_pending = 0; sk->sk_rcvlowat = 1; sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; diff --git a/net/core/stream.c b/net/core/stream.c index 24a6f72a0594..04330ba71e03 100644 --- a/net/core/stream.c +++ b/net/core/stream.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -39,3 +40,39 @@ void sk_stream_write_space(struct sock *sk) } EXPORT_SYMBOL(sk_stream_write_space); + +/** + * sk_stream_wait_connect - Wait for a socket to get into the connected state + * @sk - sock to wait on + * @timeo_p - for how long to wait + * + * Must be called with the socket locked. + */ +int sk_stream_wait_connect(struct sock *sk, long *timeo_p) +{ + struct task_struct *tsk = current; + DEFINE_WAIT(wait); + + while (1) { + if (sk->sk_err) + return sock_error(sk); + if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) + return -EPIPE; + if (!*timeo_p) + return -EAGAIN; + if (signal_pending(tsk)) + return sock_intr_errno(*timeo_p); + + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); + sk->sk_write_pending++; + if (sk_wait_event(sk, timeo_p, + !((1 << sk->sk_state) & + ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)))) + break; + finish_wait(sk->sk_sleep, &wait); + sk->sk_write_pending--; + } + return 0; +} + +EXPORT_SYMBOL(sk_stream_wait_connect); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 476716f4bc30..30b04f122ecd 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -636,46 +636,11 @@ static void tcp_listen_stop (struct sock *sk) BUG_TRAP(!sk->sk_ack_backlog); } -/* - * Wait for a socket to get into the connected state - * - * Note: Must be called with the socket locked. - */ -static int wait_for_tcp_connect(struct sock *sk, int flags, long *timeo_p) -{ - struct tcp_opt *tp = tcp_sk(sk); - struct task_struct *tsk = current; - DEFINE_WAIT(wait); - - while ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) { - if (sk->sk_err) - return sock_error(sk); - if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) - return -EPIPE; - if (!*timeo_p) - return -EAGAIN; - if (signal_pending(tsk)) - return sock_intr_errno(*timeo_p); - - prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); - tp->write_pending++; - - release_sock(sk); - *timeo_p = schedule_timeout(*timeo_p); - lock_sock(sk); - - finish_wait(sk->sk_sleep, &wait); - tp->write_pending--; - } - return 0; -} - /* * Wait for more memory for a socket */ static int wait_for_tcp_memory(struct sock *sk, long *timeo) { - struct tcp_opt *tp = tcp_sk(sk); int err = 0; long vm_wait = 0; long current_timeo = *timeo; @@ -700,12 +665,12 @@ static int wait_for_tcp_memory(struct sock *sk, long *timeo) break; set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); - tp->write_pending++; + sk->sk_write_pending++; release_sock(sk); if (!sk_stream_memory_free(sk) || vm_wait) current_timeo = schedule_timeout(current_timeo); lock_sock(sk); - tp->write_pending--; + sk->sk_write_pending--; if (vm_wait) { vm_wait -= current_timeo; @@ -812,7 +777,7 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffse /* Wait for a connection to finish. */ if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) - if ((err = wait_for_tcp_connect(sk, 0, &timeo)) != 0) + if ((err = sk_stream_wait_connect(sk, &timeo)) != 0) goto out_err; clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); @@ -965,7 +930,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, /* Wait for a connection to finish. */ if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) - if ((err = wait_for_tcp_connect(sk, flags, &timeo)) != 0) + if ((err = sk_stream_wait_connect(sk, &timeo)) != 0) goto out_err; /* This should be in poll */ diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 708005f0d0b0..e310b09964fd 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4474,7 +4474,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, sk_wake_async(sk, 0, POLL_OUT); } - if (tp->write_pending || tp->defer_accept || tp->ack.pingpong) { + if (sk->sk_write_pending || tp->defer_accept || tp->ack.pingpong) { /* Save one ACK. Data will be ready after * several ticks, if write_pending is set. * -- cgit v1.2.3 From 16a9e6dc86af9a6ca6935d13884ec4f2ecd9ac55 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 20 Jun 2004 17:47:17 -0300 Subject: [NET] introduce sk_stream_wait_close, from tcp code Will be used by the poor cousins. Signed-off-by: Arnaldo Carvalho de Melo --- include/net/sock.h | 1 + net/core/stream.c | 28 ++++++++++++++++++++++++++++ net/ipv4/tcp.c | 28 +--------------------------- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 0a7546a9957c..e5bc2560bc2e 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -461,6 +461,7 @@ do { if (!(__sk)->sk_backlog.tail) { \ }) extern int sk_stream_wait_connect(struct sock *sk, long *timeo_p); +extern void sk_stream_wait_close(struct sock *sk, long timeo_p); extern int sk_wait_data(struct sock *sk, long *timeo); diff --git a/net/core/stream.c b/net/core/stream.c index 04330ba71e03..8f5a63532ef8 100644 --- a/net/core/stream.c +++ b/net/core/stream.c @@ -76,3 +76,31 @@ int sk_stream_wait_connect(struct sock *sk, long *timeo_p) } EXPORT_SYMBOL(sk_stream_wait_connect); + +/** + * sk_stream_closing - Return 1 if we still have things to send in our buffers. + * @sk - socket to verify + */ +static inline int sk_stream_closing(struct sock *sk) +{ + return (1 << sk->sk_state) & + (TCPF_FIN_WAIT1 | TCPF_CLOSING | TCPF_LAST_ACK); +} + +void sk_stream_wait_close(struct sock *sk, long timeout) +{ + if (timeout) { + DEFINE_WAIT(wait); + + do { + prepare_to_wait(sk->sk_sleep, &wait, + TASK_INTERRUPTIBLE); + if (sk_wait_event(sk, &timeout, !sk_stream_closing(sk))) + break; + } while (!signal_pending(current) && timeout); + + finish_wait(sk->sk_sleep, &wait); + } +} + +EXPORT_SYMBOL(sk_stream_wait_close); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 30b04f122ecd..fec54474867b 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1712,17 +1712,6 @@ void tcp_shutdown(struct sock *sk, int how) } } - -/* - * Return 1 if we still have things to send in our buffers. - */ - -static inline int closing(struct sock *sk) -{ - return (1 << sk->sk_state) & - (TCPF_FIN_WAIT1 | TCPF_CLOSING | TCPF_LAST_ACK); -} - static __inline__ void tcp_kill_sk_queues(struct sock *sk) { /* First the read buffer. */ @@ -1865,22 +1854,7 @@ void tcp_close(struct sock *sk, long timeout) tcp_send_fin(sk); } - if (timeout) { - struct task_struct *tsk = current; - DEFINE_WAIT(wait); - - do { - prepare_to_wait(sk->sk_sleep, &wait, - TASK_INTERRUPTIBLE); - if (!closing(sk)) - break; - release_sock(sk); - timeout = schedule_timeout(timeout); - lock_sock(sk); - } while (!signal_pending(tsk) && timeout); - - finish_wait(sk->sk_sleep, &wait); - } + sk_stream_wait_close(sk, timeout); adjudge_to_death: /* It is the last release_sock in its life. It will remove backlog. */ -- cgit v1.2.3 From ce2ae3b7fa0285b0af84e1aeeb4450ea3862289f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 20 Jun 2004 17:57:54 -0300 Subject: [NET] generalise wait_for_tcp_memory Renaming it to sk_stream_wait_memory Signed-off-by: Arnaldo Carvalho de Melo --- include/net/sock.h | 1 + net/core/stream.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++ net/ipv4/tcp.c | 65 ++---------------------------------------------------- net/sctp/socket.c | 2 +- 4 files changed, 67 insertions(+), 64 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index e5bc2560bc2e..54a494a657fc 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -461,6 +461,7 @@ do { if (!(__sk)->sk_backlog.tail) { \ }) extern int sk_stream_wait_connect(struct sock *sk, long *timeo_p); +extern int sk_stream_wait_memory(struct sock *sk, long *timeo_p); extern void sk_stream_wait_close(struct sock *sk, long timeo_p); extern int sk_wait_data(struct sock *sk, long *timeo); diff --git a/net/core/stream.c b/net/core/stream.c index 8f5a63532ef8..eaeea6843b0a 100644 --- a/net/core/stream.c +++ b/net/core/stream.c @@ -104,3 +104,66 @@ void sk_stream_wait_close(struct sock *sk, long timeout) } EXPORT_SYMBOL(sk_stream_wait_close); + +/** + * sk_stream_wait_memory - Wait for more memory for a socket + * @sk - socket to wait for memory + * @timeo_p - for how long + */ +int sk_stream_wait_memory(struct sock *sk, long *timeo_p) +{ + int err = 0; + long vm_wait = 0; + long current_timeo = *timeo_p; + DEFINE_WAIT(wait); + + if (sk_stream_memory_free(sk)) + current_timeo = vm_wait = (net_random() % (HZ / 5)) + 2; + + while (1) { + set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); + + if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) + goto do_error; + if (!*timeo_p) + goto do_nonblock; + if (signal_pending(current)) + goto do_interrupted; + clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + if (sk_stream_memory_free(sk) && !vm_wait) + break; + + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); + sk->sk_write_pending++; + sk_wait_event(sk, ¤t_timeo, sk_stream_memory_free(sk) && + vm_wait); + sk->sk_write_pending--; + + if (vm_wait) { + vm_wait -= current_timeo; + current_timeo = *timeo_p; + if (current_timeo != MAX_SCHEDULE_TIMEOUT && + (current_timeo -= vm_wait) < 0) + current_timeo = 0; + vm_wait = 0; + } + *timeo_p = current_timeo; + } +out: + finish_wait(sk->sk_sleep, &wait); + return err; + +do_error: + err = -EPIPE; + goto out; +do_nonblock: + err = -EAGAIN; + goto out; +do_interrupted: + err = sock_intr_errno(*timeo_p); + goto out; +} + +EXPORT_SYMBOL(sk_stream_wait_memory); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index fec54474867b..ba5cb0beb71d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -636,67 +636,6 @@ static void tcp_listen_stop (struct sock *sk) BUG_TRAP(!sk->sk_ack_backlog); } -/* - * Wait for more memory for a socket - */ -static int wait_for_tcp_memory(struct sock *sk, long *timeo) -{ - int err = 0; - long vm_wait = 0; - long current_timeo = *timeo; - DEFINE_WAIT(wait); - - if (sk_stream_memory_free(sk)) - current_timeo = vm_wait = (net_random() % (HZ / 5)) + 2; - - for (;;) { - set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); - - prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); - - if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) - goto do_error; - if (!*timeo) - goto do_nonblock; - if (signal_pending(current)) - goto do_interrupted; - clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); - if (sk_stream_memory_free(sk) && !vm_wait) - break; - - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); - sk->sk_write_pending++; - release_sock(sk); - if (!sk_stream_memory_free(sk) || vm_wait) - current_timeo = schedule_timeout(current_timeo); - lock_sock(sk); - sk->sk_write_pending--; - - if (vm_wait) { - vm_wait -= current_timeo; - current_timeo = *timeo; - if (current_timeo != MAX_SCHEDULE_TIMEOUT && - (current_timeo -= vm_wait) < 0) - current_timeo = 0; - vm_wait = 0; - } - *timeo = current_timeo; - } -out: - finish_wait(sk->sk_sleep, &wait); - return err; - -do_error: - err = -EPIPE; - goto out; -do_nonblock: - err = -EAGAIN; - goto out; -do_interrupted: - err = sock_intr_errno(*timeo); - goto out; -} - static inline void fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size) { @@ -854,7 +793,7 @@ wait_for_memory: if (copied) tcp_push(sk, tp, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH); - if ((err = wait_for_tcp_memory(sk, &timeo)) != 0) + if ((err = sk_stream_wait_memory(sk, &timeo)) != 0) goto do_error; mss_now = tcp_current_mss(sk, !(flags&MSG_OOB)); @@ -1097,7 +1036,7 @@ wait_for_memory: if (copied) tcp_push(sk, tp, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH); - if ((err = wait_for_tcp_memory(sk, &timeo)) != 0) + if ((err = sk_stream_wait_memory(sk, &timeo)) != 0) goto do_error; mss_now = tcp_current_mss(sk, !(flags&MSG_OOB)); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 491b510b0782..d1b683952499 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -990,7 +990,7 @@ static int sctp_error(struct sock *sk, int flags, int err) * Note: This function could use a rewrite especially when explicit * connect support comes in. */ -/* BUG: We do not implement the equivalent of wait_for_tcp_memory(). */ +/* BUG: We do not implement the equivalent of sk_stream_wait_memory(). */ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *); -- cgit v1.2.3 From 6d6b21c5a556959f318dad249de9cdc2285f30e8 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 20 Jun 2004 19:32:44 -0700 Subject: [NET]: Fix dev_queue_xmit build with older gcc. Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- net/core/dev.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 9729210ca4cb..95a2b344e949 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1406,13 +1406,12 @@ int dev_queue_xmit(struct sk_buff *skb) Either shot noqueue qdisc, it is even simpler 8) */ if (dev->flags & IFF_UP) { - preempt_disable(); - int cpu = smp_processor_id(); + int cpu = get_cpu(); if (dev->xmit_lock_owner != cpu) { HARD_TX_LOCK_BH(dev, cpu); - preempt_enable(); + put_cpu(); if (!netif_queue_stopped(dev)) { if (netdev_nit) @@ -1430,7 +1429,7 @@ int dev_queue_xmit(struct sk_buff *skb) "queue packet!\n", dev->name); goto out_enetdown; } else { - preempt_enable(); + put_cpu(); /* Recursion is detected! It is possible, * unfortunately */ if (net_ratelimit()) -- cgit v1.2.3 From 113dc07d842a96c51de3dfc1a91e1f550812acb5 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 20 Jun 2004 19:34:33 -0700 Subject: [NET]: Loopback, allocate per-cpu stats statically and fix cpu refcounting. Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/loopback.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 53dc879651e4..318b1d60350c 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -55,8 +55,9 @@ #include /* For ARPHRD_ETHER */ #include #include +#include -static struct net_device_stats *loopback_stats; +static DEFINE_PER_CPU(struct net_device_stats, loopback_stats); #define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16) @@ -124,6 +125,7 @@ static void emulate_large_send_offload(struct sk_buff *skb) */ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) { + struct net_device_stats *lb_stats; skb_orphan(skb); @@ -142,13 +144,13 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) } dev->last_rx = jiffies; - if (likely(loopback_stats)) { - get_cpu_ptr(loopback_stats)->rx_bytes += skb->len; - get_cpu_ptr(loopback_stats)->tx_bytes += skb->len; - get_cpu_ptr(loopback_stats)->rx_packets++; - get_cpu_ptr(loopback_stats)->tx_packets++; - put_cpu_ptr(loopback_stats); - } + + lb_stats = &per_cpu(loopback_stats, get_cpu()); + lb_stats->rx_bytes += skb->len; + lb_stats->tx_bytes += skb->len; + lb_stats->rx_packets++; + lb_stats->tx_packets++; + put_cpu(); netif_rx(skb); @@ -165,17 +167,18 @@ static struct net_device_stats *get_stats(struct net_device *dev) } memset(stats, 0, sizeof(struct net_device_stats)); - if (!loopback_stats) { - return stats; - } for (i=0; i < NR_CPUS; i++) { + struct net_device_stats *lb_stats; + if (!cpu_possible(i)) continue; - stats->rx_bytes += per_cpu_ptr(loopback_stats, i)->rx_bytes; - stats->tx_bytes += per_cpu_ptr(loopback_stats, i)->tx_bytes; - stats->rx_packets += per_cpu_ptr(loopback_stats, i)->rx_packets; - stats->tx_packets += per_cpu_ptr(loopback_stats, i)->tx_packets; + lb_stats = &per_cpu(loopback_stats, get_cpu()); + stats->rx_bytes += lb_stats->rx_bytes; + stats->tx_bytes += lb_stats->tx_bytes; + stats->rx_packets += lb_stats->rx_packets; + stats->tx_packets += lb_stats->tx_packets; + put_cpu(); } return stats; @@ -211,8 +214,6 @@ int __init loopback_init(void) loopback_dev.priv = stats; loopback_dev.get_stats = &get_stats; } - - loopback_stats = alloc_percpu(struct net_device_stats); return register_netdev(&loopback_dev); }; -- cgit v1.2.3 From a58333d24414a71c162bb63c8d8c59b625a33a39 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 21 Jun 2004 00:07:06 -0700 Subject: [NET]: In sungem driver, keep track of rx buffer alloc size based upon MTU. --- drivers/net/sungem.c | 12 ++++++++---- drivers/net/sungem.h | 3 ++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index b831eef1bca2..6fe6f3601a98 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -742,7 +743,7 @@ static void gem_rx(struct gem *gp) PCI_DMA_FROMDEVICE); gp->rx_skbs[entry] = new_skb; new_skb->dev = gp->dev; - skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET)); + skb_put(new_skb, (gp->rx_buf_sz + RX_OFFSET)); rxd->buffer = cpu_to_le64(pci_map_page(gp->pdev, virt_to_page(new_skb->data), offset_in_page(new_skb->data), @@ -1482,6 +1483,9 @@ static void gem_init_rings(struct gem *gp) gem_clean_rings(gp); + gp->rx_buf_sz = max(dev->mtu + ETH_HLEN + VLAN_HLEN, + (unsigned)VLAN_ETH_FRAME_LEN); + for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; struct gem_rxd *rxd = &gb->rxd[i]; @@ -1495,7 +1499,7 @@ static void gem_init_rings(struct gem *gp) gp->rx_skbs[i] = skb; skb->dev = dev; - skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET)); + skb_put(skb, (gp->rx_buf_sz + RX_OFFSET)); dma_addr = pci_map_page(gp->pdev, virt_to_page(skb->data), offset_in_page(skb->data), @@ -1750,7 +1754,7 @@ static void gem_init_mac(struct gem *gp) writel(0x40, gp->regs + MAC_MINFSZ); /* Ethernet payload + header + FCS + optional VLAN tag. */ - writel(0x20000000 | (gp->dev->mtu + ETH_HLEN + 4 + 4), gp->regs + MAC_MAXFSZ); + writel(0x20000000 | (gp->rx_buf_sz + 4), gp->regs + MAC_MAXFSZ); writel(0x07, gp->regs + MAC_PASIZE); writel(0x04, gp->regs + MAC_JAMSIZE); @@ -1827,7 +1831,7 @@ static void gem_init_pause_thresholds(struct gem *gp) if (gp->rx_fifo_sz <= (2 * 1024)) { gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz; } else { - int max_frame = (gp->dev->mtu + ETH_HLEN + 4 + 4 + 64) & ~63; + int max_frame = (gp->rx_buf_sz + 4 + 64) & ~63; int off = (gp->rx_fifo_sz - (max_frame * 2)); int on = off - max_frame; diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h index ab83530f20ae..eed77bfe1b60 100644 --- a/drivers/net/sungem.h +++ b/drivers/net/sungem.h @@ -911,7 +911,7 @@ struct gem_rxd { (GP)->tx_old - (GP)->tx_new - 1) #define RX_OFFSET 2 -#define RX_BUF_ALLOC_SIZE(gp) ((gp)->dev->mtu + 46 + RX_OFFSET + 64) +#define RX_BUF_ALLOC_SIZE(gp) ((gp)->rx_buf_sz + 28 + RX_OFFSET + 64) #define RX_COPY_THRESHOLD 256 @@ -979,6 +979,7 @@ struct gem { int rx_fifo_sz; int rx_pause_off; int rx_pause_on; + int rx_buf_sz; int mii_phy_addr; u32 mac_rx_cfg; -- cgit v1.2.3 From 30962905aa5bfcd061496ff9f6dc22006dfd4c09 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:28:23 -0700 Subject: [NETFILTER]: Fix non-existant config option for IP_NF_ASSERT, fix some broken assertions Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_conntrack.h | 2 +- net/ipv4/netfilter/ip_conntrack_core.c | 4 +--- net/ipv4/netfilter/ip_nat_core.c | 5 +++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index 26d7f3a11fd7..1974f162f5a0 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h @@ -103,7 +103,7 @@ union ip_conntrack_nat_help { #include #include -#ifdef CONFIG_NF_DEBUG +#ifdef CONFIG_NETFILTER_DEBUG #define IP_NF_ASSERT(x) \ do { \ if (!(x)) \ diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 1f47e9bbc4eb..35b7e8f3330d 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -174,13 +174,12 @@ static void destroy_expect(struct ip_conntrack_expect *exp) { DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use)); - IP_NF_ASSERT(atomic_read(&exp->use)); + IP_NF_ASSERT(atomic_read(&exp->use) == 0); IP_NF_ASSERT(!timer_pending(&exp->timeout)); kfree(exp); } - inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp) { IP_NF_ASSERT(exp); @@ -716,7 +715,6 @@ init_conntrack(const struct ip_conntrack_tuple *tuple, DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n", conntrack, expected); /* Welcome, Mr. Bond. We've been expecting you... */ - IP_NF_ASSERT(master_ct(conntrack)); __set_bit(IPS_EXPECTED_BIT, &conntrack->status); conntrack->master = expected; expected->sibling = conntrack; diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 3e5ca975459d..40116b9850d1 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c @@ -528,6 +528,7 @@ ip_nat_setup_info(struct ip_conntrack *conntrack, MUST_BE_WRITE_LOCKED(&ip_nat_lock); IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_POST_ROUTING + || hooknum == NF_IP_LOCAL_IN || hooknum == NF_IP_LOCAL_OUT); IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS); IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); @@ -899,10 +900,10 @@ icmp_reply_translation(struct sk_buff **pskb, /* Must be RELATED */ IP_NF_ASSERT((*pskb)->nfct - - (struct ip_conntrack *)(*pskb)->nfct->master + - ((struct ip_conntrack *)(*pskb)->nfct->master)->infos == IP_CT_RELATED || (*pskb)->nfct - - (struct ip_conntrack *)(*pskb)->nfct->master + - ((struct ip_conntrack *)(*pskb)->nfct->master)->infos == IP_CT_RELATED+IP_CT_IS_REPLY); /* Redirects on non-null nats must be dropped, else they'll -- cgit v1.2.3 From c804c71ab5748fea65e53b3880010de28c5c3ca0 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:28:57 -0700 Subject: [NETFILTER]: complain about brokeness on SMP for pid, sid and command matching in ipt_owner Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- net/ipv4/netfilter/ipt_owner.c | 10 +++++++++- net/ipv6/netfilter/ip6t_owner.c | 9 ++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c index 91c3fd3f1f8f..3b9065e06381 100644 --- a/net/ipv4/netfilter/ipt_owner.c +++ b/net/ipv4/netfilter/ipt_owner.c @@ -184,7 +184,15 @@ checkentry(const char *tablename, IPT_ALIGN(sizeof(struct ipt_owner_info))); return 0; } - +#ifdef CONFIG_SMP + /* files->file_lock can not be used in a BH */ + if (((struct ipt_owner_info *)matchinfo)->match + & (IPT_OWNER_PID|IPT_OWNER_SID|IPT_OWNER_COMM)) { + printk("ipt_owner: pid, sid and command matching is broken " + "on SMP.\n"); + return 0; + } +#endif return 1; } diff --git a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c index 0bb9c661b73c..272257b3b637 100644 --- a/net/ipv6/netfilter/ip6t_owner.c +++ b/net/ipv6/netfilter/ip6t_owner.c @@ -143,7 +143,14 @@ checkentry(const char *tablename, if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_owner_info))) return 0; - +#ifdef CONFIG_SMP + /* files->file_lock can not be used in a BH */ + if (((struct ip6t_owner_info *)matchinfo)->match + & (IP6T_OWNER_PID|IP6T_OWNER_SID)) { + printk("ip6t_owner: pid and sid matching is broken on SMP.\n"); + return 0; + } +#endif return 1; } -- cgit v1.2.3 From 6683078131334f36b104eabba31b88c3a0d05b23 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:29:41 -0700 Subject: [NETFILTER]: Change permissions of /proc/net/ip_conntrack to 0440 Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_conntrack_standalone.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index fbe26d1ca0ad..80edac904188 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -503,7 +503,7 @@ static int init_or_cleanup(int init) if (ret < 0) goto cleanup_nothing; - proc = proc_net_create("ip_conntrack",0,list_conntracks); + proc = proc_net_create("ip_conntrack", 0440, list_conntracks); if (!proc) goto cleanup_init; proc->owner = THIS_MODULE; -- cgit v1.2.3 From 68b229be05d44f706d22c902bcce0785cc8808c4 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:30:19 -0700 Subject: [NETFILTER]: skip internal targets in iptables proc listing Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_tables.c | 11 ++++++++++- net/ipv6/netfilter/ip6_tables.c | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 2d433b69d099..a612865a5635 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1731,6 +1731,15 @@ static inline int print_name(const char *i, return 0; } +static inline int print_target(const struct ipt_target *t, + off_t start_offset, char *buffer, int length, + off_t *pos, unsigned int *count) +{ + if (t == &ipt_standard_target || t == &ipt_error_target) + return 0; + return print_name((char *)t, start_offset, buffer, length, pos, count); +} + static int ipt_get_tables(char *buffer, char **start, off_t offset, int length) { off_t pos = 0; @@ -1757,7 +1766,7 @@ static int ipt_get_targets(char *buffer, char **start, off_t offset, int length) if (down_interruptible(&ipt_mutex) != 0) return 0; - LIST_FIND(&ipt_target, print_name, void *, + LIST_FIND(&ipt_target, print_target, struct ipt_target *, offset, buffer, length, &pos, &count); up(&ipt_mutex); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 223212888321..d2ce00d81d4c 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1845,6 +1845,15 @@ static inline int print_name(const char *i, return 0; } +static inline int print_target(const struct ip6t_target *t, + off_t start_offset, char *buffer, int length, + off_t *pos, unsigned int *count) +{ + if (t == &ip6t_standard_target || t == &ip6t_error_target) + return 0; + return print_name((char *)t, start_offset, buffer, length, pos, count); +} + static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length) { off_t pos = 0; @@ -1871,7 +1880,7 @@ static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length if (down_interruptible(&ip6t_mutex) != 0) return 0; - LIST_FIND(&ip6t_target, print_name, char *, + LIST_FIND(&ip6t_target, print_target, struct ip6t_target *, offset, buffer, length, &pos, &count); up(&ip6t_mutex); -- cgit v1.2.3 From bf1ca4c5ecf99d0d41fd183b44f021a10562c30c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:30:52 -0700 Subject: [NETFILTER]: Fix inverted matching in ipt_helper Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- net/ipv4/netfilter/ipt_helper.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/net/ipv4/netfilter/ipt_helper.c b/net/ipv4/netfilter/ipt_helper.c index bed83c79e3cc..53e62f6a436c 100644 --- a/net/ipv4/netfilter/ipt_helper.c +++ b/net/ipv4/netfilter/ipt_helper.c @@ -41,17 +41,17 @@ match(const struct sk_buff *skb, struct ip_conntrack_expect *exp; struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; - int ret = 0; + int ret = info->invert; ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); if (!ct) { DEBUGP("ipt_helper: Eek! invalid conntrack?\n"); - return 0; + return ret; } if (!ct->master) { DEBUGP("ipt_helper: conntrack %p has no master\n", ct); - return 0; + return ret; } exp = ct->master; @@ -71,8 +71,8 @@ match(const struct sk_buff *skb, DEBUGP("master's name = %s , info->name = %s\n", exp->expectant->helper->name, info->name); - ret = !strncmp(exp->expectant->helper->name, info->name, - strlen(exp->expectant->helper->name)) ^ info->invert; + ret ^= !strncmp(exp->expectant->helper->name, info->name, + strlen(exp->expectant->helper->name)); out_unlock: READ_UNLOCK(&ip_conntrack_lock); return ret; @@ -108,7 +108,6 @@ static struct ipt_match helper_match = { static int __init init(void) { - need_ip_conntrack(); return ipt_register_match(&helper_match); } -- cgit v1.2.3 From 56bbcc53119db9eb1f20d2b979cf00cc0f0827b2 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:31:28 -0700 Subject: [NETFILTER]: 'any' matching in ipt_helper Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- net/ipv4/netfilter/ipt_helper.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/net/ipv4/netfilter/ipt_helper.c b/net/ipv4/netfilter/ipt_helper.c index 53e62f6a436c..ee9881ece49f 100644 --- a/net/ipv4/netfilter/ipt_helper.c +++ b/net/ipv4/netfilter/ipt_helper.c @@ -71,8 +71,11 @@ match(const struct sk_buff *skb, DEBUGP("master's name = %s , info->name = %s\n", exp->expectant->helper->name, info->name); - ret ^= !strncmp(exp->expectant->helper->name, info->name, - strlen(exp->expectant->helper->name)); + if (info->name[0] == '\0') + ret ^= 1; + else + ret ^= !strncmp(exp->expectant->helper->name, info->name, + strlen(exp->expectant->helper->name)); out_unlock: READ_UNLOCK(&ip_conntrack_lock); return ret; @@ -92,10 +95,6 @@ static int check(const char *tablename, if (matchsize != IPT_ALIGN(sizeof(struct ipt_helper_info))) return 0; - /* verify that we actually should match anything */ - if ( strlen(info->name) == 0 ) - return 0; - return 1; } -- cgit v1.2.3 From b5924be6446be89d58fef86840582fcc7d608a80 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:32:04 -0700 Subject: [NETFILTER]: Don't reroute on nfmark change in mangle table when routing by nfmark is not enabled Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- net/ipv4/netfilter/iptable_mangle.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 1c3d96b5f7f7..b5b43b277fe2 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -173,7 +173,9 @@ ipt_local_hook(unsigned int hook, if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE && ((*pskb)->nh.iph->saddr != saddr || (*pskb)->nh.iph->daddr != daddr +#ifdef CONFIG_IP_ROUTE_FWMARK || (*pskb)->nfmark != nfmark +#endif || (*pskb)->nh.iph->tos != tos)) return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; -- cgit v1.2.3 From 1c77f2777f63c5666301c1af4b343796ad77c931 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:32:37 -0700 Subject: [NETFILTER]: Fix expectation eviction order Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_conntrack_core.c | 23 +++++++---------------- net/ipv4/netfilter/ip_nat_core.c | 2 +- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 35b7e8f3330d..00a89f4f8d8b 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -947,9 +947,8 @@ ip_conntrack_expect_insert(struct ip_conntrack_expect *new, atomic_set(&new->use, 1); /* add to expected list for this connection */ - list_add(&new->expected_list, &related_to->sibling_list); + list_add_tail(&new->expected_list, &related_to->sibling_list); /* add to global list of expectations */ - list_prepend(&ip_conntrack_expect_list, &new->list); /* add and start timer if required */ if (related_to->helper->timeout) { @@ -1003,7 +1002,6 @@ int ip_conntrack_expect_related(struct ip_conntrack_expect *expect, } else if (related_to->helper->max_expected && related_to->expecting >= related_to->helper->max_expected) { - struct list_head *cur_item; /* old == NULL */ if (!(related_to->helper->flags & IP_CT_HELPER_F_REUSE_EXPECT)) { @@ -1029,21 +1027,14 @@ int ip_conntrack_expect_related(struct ip_conntrack_expect *expect, NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip)); /* choose the the oldest expectation to evict */ - list_for_each(cur_item, &related_to->sibling_list) { - struct ip_conntrack_expect *cur; - - cur = list_entry(cur_item, - struct ip_conntrack_expect, - expected_list); - if (cur->sibling == NULL) { - old = cur; + list_for_each_entry(old, &related_to->sibling_list, + expected_list) + if (old->sibling == NULL) break; - } - } - /* (!old) cannot happen, since related_to->expecting is the - * number of unconfirmed expects */ - IP_NF_ASSERT(old); + /* We cannot fail since related_to->expecting is the number + * of unconfirmed expectations */ + IP_NF_ASSERT(old && old->sibling == NULL); /* newnat14 does not reuse the real allocated memory * structures but rather unexpects the old and diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 40116b9850d1..1c6b7810655a 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c @@ -817,7 +817,7 @@ do_bindings(struct ip_conntrack *ct, /* Have to grab read lock before sibling_list traversal */ READ_LOCK(&ip_conntrack_lock); - list_for_each(cur_item, &ct->sibling_list) { + list_for_each_prev(cur_item, &ct->sibling_list) { exp = list_entry(cur_item, struct ip_conntrack_expect, expected_list); -- cgit v1.2.3 From f55fe5a9c5f7b79f4dac75ce6bbfdca367e50992 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:33:13 -0700 Subject: [NETFILTER]: Fix offset calculation in amanda conntrack helper Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_conntrack_amanda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c index ae1bc2509dd2..4e8f4d83baf2 100644 --- a/net/ipv4/netfilter/ip_conntrack_amanda.c +++ b/net/ipv4/netfilter/ip_conntrack_amanda.c @@ -107,7 +107,7 @@ static int help(struct sk_buff *skb, exp->mask.dst.u.tcp.port = 0xFFFF; exp_amanda_info = &exp->help.exp_amanda_info; - exp_amanda_info->offset = data - amanda_buffer; + exp_amanda_info->offset = tmp - amanda_buffer; exp_amanda_info->port = port; exp_amanda_info->len = len; -- cgit v1.2.3 From d1cbbe08201b0ad4fddaf14fe4de6e70b0b8af55 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:33:48 -0700 Subject: [NETFILTER]: Relax hook check in ipt_CLASSIFY Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- net/ipv4/netfilter/ipt_CLASSIFY.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/net/ipv4/netfilter/ipt_CLASSIFY.c b/net/ipv4/netfilter/ipt_CLASSIFY.c index e7b300465532..9842e6e23184 100644 --- a/net/ipv4/netfilter/ipt_CLASSIFY.c +++ b/net/ipv4/netfilter/ipt_CLASSIFY.c @@ -54,15 +54,17 @@ checkentry(const char *tablename, return 0; } - if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) { - printk(KERN_ERR "CLASSIFY: only valid in POST_ROUTING.\n"); + if (hook_mask & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) | + (1 << NF_IP_POST_ROUTING))) { + printk(KERN_ERR "CLASSIFY: only valid in LOCAL_OUT, FORWARD " + "and POST_ROUTING.\n"); return 0; } if (strcmp(tablename, "mangle") != 0) { - printk(KERN_WARNING "CLASSIFY: can only be called from " - "\"mangle\" table, not \"%s\".\n", - tablename); + printk(KERN_ERR "CLASSIFY: can only be called from " + "\"mangle\" table, not \"%s\".\n", + tablename); return 0; } -- cgit v1.2.3 From 02c83c2e15de9b2a06275388f0b288a2af92ad3e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:34:20 -0700 Subject: [NETFILTER]: Add new function 'nf_reset' to reset netfilter related skb-fields Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- include/linux/skbuff.h | 15 ++++++++++++--- net/ipv4/ip_gre.c | 16 ++-------------- net/ipv4/ip_input.c | 6 +----- net/ipv4/ipip.c | 16 ++-------------- net/ipv4/ipmr.c | 15 +++------------ net/ipv4/netfilter/ipt_REJECT.c | 6 +----- net/ipv6/ip6_tunnel.c | 8 +------- net/ipv6/sit.c | 16 ++-------------- 8 files changed, 24 insertions(+), 74 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 1b33d607f276..f47163e84760 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1109,6 +1109,14 @@ static inline void nf_conntrack_get(struct nf_ct_info *nfct) if (nfct) atomic_inc(&nfct->master->use); } +static inline void nf_reset(struct sk_buff *skb) +{ + nf_conntrack_put(skb->nfct); + skb->nfct = NULL; +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; +#endif +} #ifdef CONFIG_BRIDGE_NETFILTER static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge) @@ -1121,9 +1129,10 @@ static inline void nf_bridge_get(struct nf_bridge_info *nf_bridge) if (nf_bridge) atomic_inc(&nf_bridge->use); } -#endif - -#endif +#endif /* CONFIG_BRIDGE_NETFILTER */ +#else /* CONFIG_NETFILTER */ +static inline void nf_reset(struct sk_buff *skb) {} +#endif /* CONFIG_NETFILTER */ #endif /* __KERNEL__ */ #endif /* _LINUX_SKBUFF_H */ diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 4a227f51b2c1..0c2f8ca5ae83 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -643,13 +643,7 @@ int ipgre_rcv(struct sk_buff *skb) skb->dev = tunnel->dev; dst_release(skb->dst); skb->dst = NULL; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -#endif + nf_reset(skb); ipgre_ecn_decapsulate(iph, skb); netif_rx(skb); read_unlock(&ipgre_lock); @@ -877,13 +871,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } } -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -#endif + nf_reset(skb); IPTUNNEL_XMIT(); tunnel->recursion--; diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 2f71ed5cfcc9..5b473004fab9 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -202,17 +202,13 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb) #ifdef CONFIG_NETFILTER_DEBUG nf_debug_ip_local_deliver(skb); - skb->nf_debug = 0; #endif /*CONFIG_NETFILTER_DEBUG*/ __skb_pull(skb, ihl); -#ifdef CONFIG_NETFILTER /* Free reference early: we don't need it any more, and it may hold ip_conntrack module loaded indefinitely. */ - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#endif /*CONFIG_NETFILTER*/ + nf_reset(skb); /* Point into the IP datagram, just past the header. */ skb->h.raw = skb->data; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 757b1d3f6aa2..98ba22404ac3 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -497,13 +497,7 @@ static int ipip_rcv(struct sk_buff *skb) skb->dev = tunnel->dev; dst_release(skb->dst); skb->dst = NULL; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -#endif + nf_reset(skb); ipip_ecn_decapsulate(iph, skb); netif_rx(skb); read_unlock(&ipip_lock); @@ -648,13 +642,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if ((iph->ttl = tiph->ttl) == 0) iph->ttl = old_iph->ttl; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -#endif + nf_reset(skb); IPTUNNEL_XMIT(); tunnel->recursion--; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index a25e56077072..3aecdcf5e085 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1105,10 +1105,7 @@ static void ip_encap(struct sk_buff *skb, u32 saddr, u32 daddr) skb->h.ipiph = skb->nh.iph; skb->nh.iph = iph; memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#endif + nf_reset(skb); } static inline int ipmr_forward_finish(struct sk_buff *skb) @@ -1461,10 +1458,7 @@ int pim_rcv_v1(struct sk_buff * skb) skb->dst = NULL; ((struct net_device_stats*)reg_dev->priv)->rx_bytes += skb->len; ((struct net_device_stats*)reg_dev->priv)->rx_packets++; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#endif + nf_reset(skb); netif_rx(skb); dev_put(reg_dev); return 0; @@ -1520,10 +1514,7 @@ static int pim_rcv(struct sk_buff * skb) ((struct net_device_stats*)reg_dev->priv)->rx_bytes += skb->len; ((struct net_device_stats*)reg_dev->priv)->rx_packets++; skb->dst = NULL; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#endif + nf_reset(skb); netif_rx(skb); dev_put(reg_dev); return 0; diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index f6183f968b2b..b8018cb023ff 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -142,12 +142,8 @@ static void send_reset(struct sk_buff *oldskb, int hook) nskb->dst = &rt->u.dst; /* This packet will not be the same as the other: clear nf fields */ - nf_conntrack_put(nskb->nfct); - nskb->nfct = NULL; + nf_reset(nskb); nskb->nfcache = 0; -#ifdef CONFIG_NETFILTER_DEBUG - nskb->nf_debug = 0; -#endif nskb->nfmark = 0; #ifdef CONFIG_BRIDGE_NETFILTER nf_bridge_put(nskb->nf_bridge); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 9e5677dd45a2..0c8db0391a78 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -722,13 +722,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) ipv6h->nexthdr = proto; ipv6_addr_copy(&ipv6h->saddr, &fl.fl6_src); ipv6_addr_copy(&ipv6h->daddr, &fl.fl6_dst); -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -#endif + nf_reset(skb); pkt_len = skb->len; err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 2fac873fdd3d..2958bb9c76fe 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -388,13 +388,7 @@ static int ipip6_rcv(struct sk_buff *skb) skb->dev = tunnel->dev; dst_release(skb->dst); skb->dst = NULL; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -#endif + nf_reset(skb); ipip6_ecn_decapsulate(iph, skb); netif_rx(skb); read_unlock(&ipip6_lock); @@ -580,13 +574,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if ((iph->ttl = tiph->ttl) == 0) iph->ttl = iph6->hop_limit; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -#endif + nf_reset(skb); IPTUNNEL_XMIT(); tunnel->recursion--; -- cgit v1.2.3 From fd4daaf7b32473367b25c2936d2cc71eb72e1e72 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:36:31 -0700 Subject: [NETFILTER]: Add addrtype match Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ipt_addrtype.h | 11 +++++ net/ipv4/netfilter/Kconfig | 10 ++++ net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/ipt_addrtype.c | 77 +++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 include/linux/netfilter_ipv4/ipt_addrtype.h create mode 100644 net/ipv4/netfilter/ipt_addrtype.c diff --git a/include/linux/netfilter_ipv4/ipt_addrtype.h b/include/linux/netfilter_ipv4/ipt_addrtype.h new file mode 100644 index 000000000000..166ed01a8122 --- /dev/null +++ b/include/linux/netfilter_ipv4/ipt_addrtype.h @@ -0,0 +1,11 @@ +#ifndef _IPT_ADDRTYPE_H +#define _IPT_ADDRTYPE_H + +struct ipt_addrtype_info { + u_int16_t source; /* source-type mask */ + u_int16_t dest; /* dest-type mask */ + u_int32_t invert_source; + u_int32_t invert_dest; +}; + +#endif diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index f5a5110f97da..5e9b01f74c30 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -603,5 +603,15 @@ config IP_NF_RAW . If unsure, say `N'. help +config IP_NF_MATCH_ADDRTYPE + tristate 'address type match support' + depends on IP_NF_IPTABLES + help + This option allows you to match what routing thinks of an address, + eg. UNICAST, LOCAL, BROADCAST, ... + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + endmenu diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 52bedf2d7c62..5893bc654ab0 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o +obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c new file mode 100644 index 000000000000..7392ba6bd23f --- /dev/null +++ b/net/ipv4/netfilter/ipt_addrtype.c @@ -0,0 +1,77 @@ +/* + * iptables module to match inet_addr_type() of an ip. + * + * Copyright (c) 2004 Patrick McHardy + * + * This program 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. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Patrick McHardy "); +MODULE_DESCRIPTION("iptables addrtype match"); + +static inline int match_type(u_int32_t addr, u_int16_t mask) +{ + return !!(mask & (1 << inet_addr_type(addr))); +} + +static int match(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *matchinfo, + int offset, int *hotdrop) +{ + const struct ipt_addrtype_info *info = matchinfo; + const struct iphdr *iph = skb->nh.iph; + int ret = 1; + + if (info->source) + ret &= match_type(iph->saddr, info->source)^info->invert_source; + if (info->dest) + ret &= match_type(iph->daddr, info->dest)^info->invert_dest; + + return ret; +} + +static int checkentry(const char *tablename, const struct ipt_ip *ip, + void *matchinfo, unsigned int matchsize, + unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_addrtype_info))) { + printk(KERN_ERR "ipt_addrtype: invalid size (%u != %u)\n.", + matchsize, IPT_ALIGN(sizeof(struct ipt_addrtype_info))); + return 0; + } + + return 1; +} + +static struct ipt_match addrtype_match = { + .name = "addrtype", + .match = match, + .checkentry = checkentry, + .me = THIS_MODULE +}; + +static int __init init(void) +{ + return ipt_register_match(&addrtype_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&addrtype_match); +} + +module_init(init); +module_exit(fini); -- cgit v1.2.3 From e07d39a4fe747af843ca8ec76edc5531cc2fa551 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:38:44 -0700 Subject: [NETFILTER]: Add realm match Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ipt_realm.h | 10 +++++ net/ipv4/netfilter/Kconfig | 14 ++++++ net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/ipt_realm.c | 76 ++++++++++++++++++++++++++++++++ net/sched/Kconfig | 4 +- 5 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 include/linux/netfilter_ipv4/ipt_realm.h create mode 100644 net/ipv4/netfilter/ipt_realm.c diff --git a/include/linux/netfilter_ipv4/ipt_realm.h b/include/linux/netfilter_ipv4/ipt_realm.h new file mode 100644 index 000000000000..a4d6698723ac --- /dev/null +++ b/include/linux/netfilter_ipv4/ipt_realm.h @@ -0,0 +1,10 @@ +#ifndef _IPT_REALM_H +#define _IPT_REALM_H + +struct ipt_realm_info { + u_int32_t id; + u_int32_t mask; + u_int8_t invert; +}; + +#endif /* _IPT_REALM_H */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 5e9b01f74c30..eaf79408bc03 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -613,5 +613,19 @@ config IP_NF_MATCH_ADDRTYPE If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. +config IP_NF_MATCH_REALM + tristate 'realm match support' + depends on IP_NF_IPTABLES + select NET_CLS_ROUTE + help + This option adds a `realm' match, which allows you to use the realm + key from the routing subsytem inside iptables. + + This match pretty much resembles the CONFIG_NET_CLS_ROUTE4 option + in tc world. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + endmenu diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 5893bc654ab0..bdb23fde133f 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o +obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o diff --git a/net/ipv4/netfilter/ipt_realm.c b/net/ipv4/netfilter/ipt_realm.c new file mode 100644 index 000000000000..54a6897ebaa6 --- /dev/null +++ b/net/ipv4/netfilter/ipt_realm.c @@ -0,0 +1,76 @@ +/* IP tables module for matching the routing realm + * + * $Id: ipt_realm.c,v 1.3 2004/03/05 13:25:40 laforge Exp $ + * + * (C) 2003 by Sampsa Ranta + * + * This program 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. + */ + +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Sampsa Ranta "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("iptables realm match"); + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + int *hotdrop) +{ + const struct ipt_realm_info *info = matchinfo; + struct dst_entry *dst = skb->dst; + + return (info->id == (dst->tclassid & info->mask)) ^ info->invert; +} + +static int check(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (hook_mask + & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) | + (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_LOCAL_IN))) { + printk("ipt_realm: only valid for POST_ROUTING, LOCAL_OUT, " + "LOCAL_IN or FORWARD.\n"); + return 0; + } + if (matchsize != IPT_ALIGN(sizeof(struct ipt_realm_info))) { + printk("ipt_realm: invalid matchsize.\n"); + return 0; + } + return 1; +} + +static struct ipt_match realm_match = { + .name = "realm", + .match = match, + .checkentry = check, + .me = THIS_MODULE +}; + +static int __init init(void) +{ + return ipt_register_match(&realm_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&realm_match); +} + +module_init(init); +module_exit(fini); diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 8931426e0243..293655830d98 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -242,6 +242,7 @@ config NET_CLS_TCINDEX config NET_CLS_ROUTE4 tristate "Routing table based classifier" depends on NET_CLS + select NET_CLS_ROUTE help If you say Y here, you will be able to classify outgoing packets according to the route table entry they matched. If unsure, say Y. @@ -251,8 +252,7 @@ config NET_CLS_ROUTE4 config NET_CLS_ROUTE bool - depends on NET_CLS_ROUTE4 - default y + default n config NET_CLS_FW tristate "Firewall based classifier" -- cgit v1.2.3 From 41d63bb62614d5db0621397ba1dd77666d0e46ba Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:39:33 -0700 Subject: [NETFILTER]: ip_table_raw C99 initialization Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- net/ipv4/netfilter/iptable_raw.c | 95 ++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 37 deletions(-) diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index 4c2266d2013b..0fd648ac0df3 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -32,43 +32,64 @@ static struct struct ipt_replace repl; struct ipt_standard entries[2]; struct ipt_error term; -} initial_table __initdata -= { { "raw", RAW_VALID_HOOKS, 3, - sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error), - { [NF_IP_PRE_ROUTING] 0, - [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) }, - { [NF_IP_PRE_ROUTING] 0, - [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) }, - 0, NULL, { } }, - { - /* PRE_ROUTING */ - { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, - 0, - sizeof(struct ipt_entry), - sizeof(struct ipt_standard), - 0, { 0, 0 }, { } }, - { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, - -NF_ACCEPT - 1 } }, - /* LOCAL_OUT */ - { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, - 0, - sizeof(struct ipt_entry), - sizeof(struct ipt_standard), - 0, { 0, 0 }, { } }, - { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, - -NF_ACCEPT - 1 } } - }, - /* ERROR */ - { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, - 0, - sizeof(struct ipt_entry), - sizeof(struct ipt_error), - 0, { 0, 0 }, { } }, - { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } }, - { } }, - "ERROR" - } - } +} initial_table __initdata = { + .repl = { + .name = "raw", + .valid_hooks = RAW_VALID_HOOKS, + .num_entries = 3, + .size = sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error), + .hook_entry = { + [NF_IP_PRE_ROUTING] = 0, + [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) }, + .underflow = { + [NF_IP_PRE_ROUTING] = 0, + [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) }, + }, + .entries = { + /* PRE_ROUTING */ + { + .entry = { + .target_offset = sizeof(struct ipt_entry), + .next_offset = sizeof(struct ipt_standard), + }, + .target = { + .target = { + .u.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), + }, + .verdict = -NF_ACCEPT - 1, + }, + }, + + /* LOCAL_OUT */ + { + .entry = { + .target_offset = sizeof(struct ipt_entry), + .next_offset = sizeof(struct ipt_standard), + }, + .target = { + .target = { + .u.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), + }, + .verdict = -NF_ACCEPT - 1, + }, + }, + }, + /* ERROR */ + .term = { + .entry = { + .target_offset = sizeof(struct ipt_entry), + .next_offset = sizeof(struct ipt_error), + }, + .target = { + .target = { + .u.user = { + .target_size = IPT_ALIGN(sizeof(struct ipt_error_target)), + .name = IPT_ERROR_TARGET, + }, + }, + .errorname = "ERROR", + }, + } }; static struct ipt_table packet_raw = { -- cgit v1.2.3 From 76729985066c83358ad4a297b22ffc016a85046d Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Mon, 21 Jun 2004 02:04:04 -0700 Subject: [PKT_SCHED]: C99'ify act_police_ops. --- net/sched/police.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/net/sched/police.c b/net/sched/police.c index 2556651b7366..1e8d5607f651 100644 --- a/net/sched/police.c +++ b/net/sched/police.c @@ -393,19 +393,19 @@ MODULE_DESCRIPTION("Policing actions"); MODULE_LICENSE("GPL"); -struct tc_action_ops act_police_ops = { - NULL, - "police", - TCA_ID_POLICE, - TCA_CAP_NONE, - THIS_MODULE, - tcf_act_police, - tcf_act_police_stats, - tcf_act_police_dump, - tcf_act_police_cleanup, - tcf_hash_search, - tcf_act_police_locate, - tcf_generic_walker +static struct tc_action_ops act_police_ops = { + .next = NULL, + .kind = "police", + .type = TCA_ID_POLICE, + .capab = TCA_CAP_NONE, + .owner = THIS_MODULE, + .act = tcf_act_police, + .get_stats = tcf_act_police_stats, + .dump = tcf_act_police_dump, + .cleanup = tcf_act_police_cleanup, + .lookup = tcf_hash_search, + .init = tcf_act_police_locate, + .walk = tcf_generic_walker }; static int __init -- cgit v1.2.3 From 2285857c352e92de7f1a95594875739038890e72 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 21 Jun 2004 03:04:23 -0700 Subject: merge fixups. --- drivers/scsi/scsi_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index f20e5a787e9f..4067ba593d9c 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1450,7 +1450,7 @@ static ssize_t sdebug_ptype_store(struct device_driver * ddp, } return -EINVAL; } -DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store) +DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store); static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf) { -- cgit v1.2.3 From a47b157e456fecc7bc09dead9ef3e1733ebdfc56 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 21 Jun 2004 07:14:12 -0300 Subject: [NET] generalise tcp_set_owner_r and tcp_rfree Will be used by the poor cousins Signed-off-by: Arnaldo Carvalho de Melo --- include/net/sock.h | 10 ++++++++++ include/net/tcp.h | 10 ---------- net/core/stream.c | 10 ++++++++++ net/ipv4/tcp.c | 8 -------- net/ipv4/tcp_input.c | 8 ++++---- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 54a494a657fc..60f8c869b5bd 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -436,6 +436,16 @@ static inline int sk_stream_memory_free(struct sock *sk) return sk->sk_wmem_queued < sk->sk_sndbuf; } +extern void sk_stream_rfree(struct sk_buff *skb); + +static inline void sk_stream_set_owner_r(struct sk_buff *skb, struct sock *sk) +{ + skb->sk = sk; + skb->destructor = sk_stream_rfree; + atomic_add(skb->truesize, &sk->sk_rmem_alloc); + sk->sk_forward_alloc -= skb->truesize; +} + /* The per-socket spinlock must be held here. */ #define sk_add_backlog(__sk, __skb) \ do { if (!(__sk)->sk_backlog.tail) { \ diff --git a/include/net/tcp.h b/include/net/tcp.h index 3a323cd1e79f..aaef4bf548be 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1955,16 +1955,6 @@ static inline void tcp_writequeue_purge(struct sock *sk) tcp_mem_reclaim(sk); } -extern void tcp_rfree(struct sk_buff *skb); - -static inline void tcp_set_owner_r(struct sk_buff *skb, struct sock *sk) -{ - skb->sk = sk; - skb->destructor = tcp_rfree; - atomic_add(skb->truesize, &sk->sk_rmem_alloc); - sk->sk_forward_alloc -= skb->truesize; -} - extern void tcp_listen_wlock(void); /* - We may sleep inside this lock. diff --git a/net/core/stream.c b/net/core/stream.c index eaeea6843b0a..d5357897830a 100644 --- a/net/core/stream.c +++ b/net/core/stream.c @@ -167,3 +167,13 @@ do_interrupted: } EXPORT_SYMBOL(sk_stream_wait_memory); + +void sk_stream_rfree(struct sk_buff *skb) +{ + struct sock *sk = skb->sk; + + atomic_sub(skb->truesize, &sk->sk_rmem_alloc); + sk->sk_forward_alloc += skb->truesize; +} + +EXPORT_SYMBOL(sk_stream_rfree); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index ba5cb0beb71d..77525aa5274e 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -360,14 +360,6 @@ void __tcp_mem_reclaim(struct sock *sk) } } -void tcp_rfree(struct sk_buff *skb) -{ - struct sock *sk = skb->sk; - - atomic_sub(skb->truesize, &sk->sk_rmem_alloc); - sk->sk_forward_alloc += skb->truesize; -} - /* * LISTEN is a special case for poll.. */ diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e310b09964fd..d0ad5def4629 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3453,7 +3453,7 @@ queue_and_out: if (tcp_prune_queue(sk) < 0 || !tcp_rmem_schedule(sk, skb)) goto drop; } - tcp_set_owner_r(skb, sk); + sk_stream_set_owner_r(skb, sk); __skb_queue_tail(&sk->sk_receive_queue, skb); } tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; @@ -3534,7 +3534,7 @@ drop: SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n", tp->rcv_nxt, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); - tcp_set_owner_r(skb, sk); + sk_stream_set_owner_r(skb, sk); if (!skb_peek(&tp->out_of_order_queue)) { /* Initial out of order segment, build 1 SACK. */ @@ -3673,7 +3673,7 @@ tcp_collapse(struct sock *sk, struct sk_buff *head, memcpy(nskb->cb, skb->cb, sizeof(skb->cb)); TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(nskb)->end_seq = start; __skb_insert(nskb, skb->prev, skb, skb->list); - tcp_set_owner_r(nskb, sk); + sk_stream_set_owner_r(nskb, sk); /* Copy data, releasing collapsed skbs. */ while (copy > 0) { @@ -4234,7 +4234,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, /* Bulk data transfer: receiver */ __skb_pull(skb,tcp_header_len); __skb_queue_tail(&sk->sk_receive_queue, skb); - tcp_set_owner_r(skb, sk); + sk_stream_set_owner_r(skb, sk); tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; } -- cgit v1.2.3 From 7791fddca543e7e39746e80227d60a4fc772d0cf Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 21 Jun 2004 06:52:56 -0400 Subject: Rename 'carmel' block driver to 'sx8'. Requested by Promise. The hardware isn't widely deployed yet, with almost all users being early evaluators, so this should be OK. --- Documentation/devices.txt | 28 +- drivers/block/Kconfig | 8 +- drivers/block/Makefile | 2 +- drivers/block/carmel.c | 1763 --------------------------------------------- drivers/block/sx8.c | 1763 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1782 insertions(+), 1782 deletions(-) delete mode 100644 drivers/block/carmel.c create mode 100644 drivers/block/sx8.c diff --git a/Documentation/devices.txt b/Documentation/devices.txt index d5ee998d6317..0257f2566e43 100644 --- a/Documentation/devices.txt +++ b/Documentation/devices.txt @@ -2377,16 +2377,16 @@ Your cooperation is appreciated. 1 = /dev/gpib1 Second GPIB bus ... -160 block Carmel 8-port SATA Disks on First Controller - 0 = /dev/carmel/0 SATA disk 0 whole disk - 1 = /dev/carmel/0p1 SATA disk 0 partition 1 +160 block Promise SX8 8-port SATA Disks on First Controller + 0 = /dev/sx8/0 SATA disk 0 whole disk + 1 = /dev/sx8/0p1 SATA disk 0 partition 1 ... - 31 = /dev/carmel/0p31 SATA disk 0 partition 31 + 31 = /dev/sx8/0p31 SATA disk 0 partition 31 - 32 = /dev/carmel/1 SATA disk 1 whole disk - 64 = /dev/carmel/2 SATA disk 2 whole disk + 32 = /dev/sx8/1 SATA disk 1 whole disk + 64 = /dev/sx8/2 SATA disk 2 whole disk ... - 224 = /dev/carmel/7 SATA disk 7 whole disk + 224 = /dev/sx8/7 SATA disk 7 whole disk Partitions are handled in the same way as for IDE disks (see major number 3) except that the limit on @@ -2400,16 +2400,16 @@ Your cooperation is appreciated. 17 = /dev/irlpt1 Second IrLPT device ... -161 block Carmel 8-port SATA Disks on Second Controller - 0 = /dev/carmel/8 SATA disk 8 whole disk - 1 = /dev/carmel/8p1 SATA disk 8 partition 1 +161 block Promise SX8 8-port SATA Disks on Second Controller + 0 = /dev/sx8/8 SATA disk 8 whole disk + 1 = /dev/sx8/8p1 SATA disk 8 partition 1 ... - 31 = /dev/carmel/8p31 SATA disk 8 partition 31 + 31 = /dev/sx8/8p31 SATA disk 8 partition 31 - 32 = /dev/carmel/9 SATA disk 9 whole disk - 64 = /dev/carmel/10 SATA disk 10 whole disk + 32 = /dev/sx8/9 SATA disk 9 whole disk + 64 = /dev/sx8/10 SATA disk 10 whole disk ... - 224 = /dev/carmel/15 SATA disk 15 whole disk + 224 = /dev/sx8/15 SATA disk 15 whole disk Partitions are handled in the same way as for IDE disks (see major number 3) except that the limit on diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 0e18df6b76e5..afb9d4391a7a 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -285,14 +285,14 @@ config BLK_DEV_NBD If unsure, say N. -config BLK_DEV_CARMEL - tristate "Promise SATA SX8 (carmel) support" +config BLK_DEV_SX8 + tristate "Promise SATA SX8 support" depends on PCI ---help--- Saying Y or M here will enable support for the - Promise SATA SX8 ("carmel") controllers. + Promise SATA SX8 controllers. - Use devices /dev/carmel/$N and /dev/carmel/$Np$M. + Use devices /dev/sx8/$N and /dev/sx8/$Np$M. config BLK_DEV_RAM tristate "RAM disk support" diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 33b14e84cd8c..2654b5b7615e 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -41,5 +41,5 @@ obj-$(CONFIG_BLK_DEV_NBD) += nbd.o obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryptoloop.o obj-$(CONFIG_VIODASD) += viodasd.o -obj-$(CONFIG_BLK_DEV_CARMEL) += carmel.o +obj-$(CONFIG_BLK_DEV_SX8) += sx8.o diff --git a/drivers/block/carmel.c b/drivers/block/carmel.c deleted file mode 100644 index 38fd6fe42d07..000000000000 --- a/drivers/block/carmel.c +++ /dev/null @@ -1,1763 +0,0 @@ -/* - * carmel.c: Driver for Promise SATA SX8 looks-like-I2O hardware - * - * Copyright 2004 Red Hat, Inc. - * - * Author/maintainer: Jeff Garzik - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Jeff Garzik"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Promise SATA SX8 (carmel) block driver"); - -#if 0 -#define CARM_DEBUG -#define CARM_VERBOSE_DEBUG -#else -#undef CARM_DEBUG -#undef CARM_VERBOSE_DEBUG -#endif -#undef CARM_NDEBUG - -#define DRV_NAME "carmel" -#define DRV_VERSION "0.8" -#define PFX DRV_NAME ": " - -#define NEXT_RESP(idx) ((idx + 1) % RMSG_Q_LEN) - -/* 0xf is just arbitrary, non-zero noise; this is sorta like poisoning */ -#define TAG_ENCODE(tag) (((tag) << 16) | 0xf) -#define TAG_DECODE(tag) (((tag) >> 16) & 0x1f) -#define TAG_VALID(tag) ((((tag) & 0xf) == 0xf) && (TAG_DECODE(tag) < 32)) - -/* note: prints function name for you */ -#ifdef CARM_DEBUG -#define DPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) -#ifdef CARM_VERBOSE_DEBUG -#define VPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) -#else -#define VPRINTK(fmt, args...) -#endif /* CARM_VERBOSE_DEBUG */ -#else -#define DPRINTK(fmt, args...) -#define VPRINTK(fmt, args...) -#endif /* CARM_DEBUG */ - -#ifdef CARM_NDEBUG -#define assert(expr) -#else -#define assert(expr) \ - if(unlikely(!(expr))) { \ - printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \ - #expr,__FILE__,__FUNCTION__,__LINE__); \ - } -#endif - -/* defines only for the constants which don't work well as enums */ -struct carm_host; - -enum { - /* adapter-wide limits */ - CARM_MAX_PORTS = 8, - CARM_SHM_SIZE = (4096 << 7), - CARM_MINORS_PER_MAJOR = 256 / CARM_MAX_PORTS, - CARM_MAX_WAIT_Q = CARM_MAX_PORTS + 1, - - /* command message queue limits */ - CARM_MAX_REQ = 64, /* max command msgs per host */ - CARM_MAX_Q = 1, /* one command at a time */ - CARM_MSG_LOW_WATER = (CARM_MAX_REQ / 4), /* refill mark */ - - /* S/G limits, host-wide and per-request */ - CARM_MAX_REQ_SG = 32, /* max s/g entries per request */ - CARM_SG_BOUNDARY = 0xffffUL, /* s/g segment boundary */ - CARM_MAX_HOST_SG = 600, /* max s/g entries per host */ - CARM_SG_LOW_WATER = (CARM_MAX_HOST_SG / 4), /* re-fill mark */ - - /* hardware registers */ - CARM_IHQP = 0x1c, - CARM_INT_STAT = 0x10, /* interrupt status */ - CARM_INT_MASK = 0x14, /* interrupt mask */ - CARM_HMUC = 0x18, /* host message unit control */ - RBUF_ADDR_LO = 0x20, /* response msg DMA buf low 32 bits */ - RBUF_ADDR_HI = 0x24, /* response msg DMA buf high 32 bits */ - RBUF_BYTE_SZ = 0x28, - CARM_RESP_IDX = 0x2c, - CARM_CMS0 = 0x30, /* command message size reg 0 */ - CARM_LMUC = 0x48, - CARM_HMPHA = 0x6c, - CARM_INITC = 0xb5, - - /* bits in CARM_INT_{STAT,MASK} */ - INT_RESERVED = 0xfffffff0, - INT_WATCHDOG = (1 << 3), /* watchdog timer */ - INT_Q_OVERFLOW = (1 << 2), /* cmd msg q overflow */ - INT_Q_AVAILABLE = (1 << 1), /* cmd msg q has free space */ - INT_RESPONSE = (1 << 0), /* response msg available */ - INT_ACK_MASK = INT_WATCHDOG | INT_Q_OVERFLOW, - INT_DEF_MASK = INT_RESERVED | INT_Q_OVERFLOW | - INT_RESPONSE, - - /* command messages, and related register bits */ - CARM_HAVE_RESP = 0x01, - CARM_MSG_READ = 1, - CARM_MSG_WRITE = 2, - CARM_MSG_VERIFY = 3, - CARM_MSG_GET_CAPACITY = 4, - CARM_MSG_FLUSH = 5, - CARM_MSG_IOCTL = 6, - CARM_MSG_ARRAY = 8, - CARM_MSG_MISC = 9, - CARM_CME = (1 << 2), - CARM_RME = (1 << 1), - CARM_WZBC = (1 << 0), - CARM_RMI = (1 << 0), - CARM_Q_FULL = (1 << 3), - CARM_MSG_SIZE = 288, - CARM_Q_LEN = 48, - - /* CARM_MSG_IOCTL messages */ - CARM_IOC_SCAN_CHAN = 5, /* scan channels for devices */ - CARM_IOC_GET_TCQ = 13, /* get tcq/ncq depth */ - CARM_IOC_SET_TCQ = 14, /* set tcq/ncq depth */ - - IOC_SCAN_CHAN_NODEV = 0x1f, - IOC_SCAN_CHAN_OFFSET = 0x40, - - /* CARM_MSG_ARRAY messages */ - CARM_ARRAY_INFO = 0, - - ARRAY_NO_EXIST = (1 << 31), - - /* response messages */ - RMSG_SZ = 8, /* sizeof(struct carm_response) */ - RMSG_Q_LEN = 48, /* resp. msg list length */ - RMSG_OK = 1, /* bit indicating msg was successful */ - /* length of entire resp. msg buffer */ - RBUF_LEN = RMSG_SZ * RMSG_Q_LEN, - - PDC_SHM_SIZE = (4096 << 7), /* length of entire h/w buffer */ - - /* CARM_MSG_MISC messages */ - MISC_GET_FW_VER = 2, - MISC_ALLOC_MEM = 3, - MISC_SET_TIME = 5, - - /* MISC_GET_FW_VER feature bits */ - FW_VER_4PORT = (1 << 2), /* 1=4 ports, 0=8 ports */ - FW_VER_NON_RAID = (1 << 1), /* 1=non-RAID firmware, 0=RAID */ - FW_VER_ZCR = (1 << 0), /* zero channel RAID (whatever that is) */ - - /* carm_host flags */ - FL_NON_RAID = FW_VER_NON_RAID, - FL_4PORT = FW_VER_4PORT, - FL_FW_VER_MASK = (FW_VER_NON_RAID | FW_VER_4PORT), - FL_DAC = (1 << 16), - FL_DYN_MAJOR = (1 << 17), -}; - -enum scatter_gather_types { - SGT_32BIT = 0, - SGT_64BIT = 1, -}; - -enum host_states { - HST_INVALID, /* invalid state; never used */ - HST_ALLOC_BUF, /* setting up master SHM area */ - HST_ERROR, /* we never leave here */ - HST_PORT_SCAN, /* start dev scan */ - HST_DEV_SCAN_START, /* start per-device probe */ - HST_DEV_SCAN, /* continue per-device probe */ - HST_DEV_ACTIVATE, /* activate devices we found */ - HST_PROBE_FINISHED, /* probe is complete */ - HST_PROBE_START, /* initiate probe */ - HST_SYNC_TIME, /* tell firmware what time it is */ - HST_GET_FW_VER, /* get firmware version, adapter port cnt */ -}; - -#ifdef CARM_DEBUG -static const char *state_name[] = { - "HST_INVALID", - "HST_ALLOC_BUF", - "HST_ERROR", - "HST_PORT_SCAN", - "HST_DEV_SCAN_START", - "HST_DEV_SCAN", - "HST_DEV_ACTIVATE", - "HST_PROBE_FINISHED", - "HST_PROBE_START", - "HST_SYNC_TIME", - "HST_GET_FW_VER", -}; -#endif - -struct carm_port { - unsigned int port_no; - unsigned int n_queued; - struct gendisk *disk; - struct carm_host *host; - - /* attached device characteristics */ - u64 capacity; - char name[41]; - u16 dev_geom_head; - u16 dev_geom_sect; - u16 dev_geom_cyl; -}; - -struct carm_request { - unsigned int tag; - int n_elem; - unsigned int msg_type; - unsigned int msg_subtype; - unsigned int msg_bucket; - struct request *rq; - struct carm_port *port; - struct scatterlist sg[CARM_MAX_REQ_SG]; -}; - -struct carm_host { - unsigned long flags; - void *mmio; - void *shm; - dma_addr_t shm_dma; - - int major; - int id; - char name[32]; - - spinlock_t lock; - struct pci_dev *pdev; - unsigned int state; - u32 fw_ver; - - request_queue_t *oob_q; - unsigned int n_oob; - - unsigned int hw_sg_used; - - unsigned int resp_idx; - - unsigned int wait_q_prod; - unsigned int wait_q_cons; - request_queue_t *wait_q[CARM_MAX_WAIT_Q]; - - unsigned int n_msgs; - u64 msg_alloc; - struct carm_request req[CARM_MAX_REQ]; - void *msg_base; - dma_addr_t msg_dma; - - int cur_scan_dev; - unsigned long dev_active; - unsigned long dev_present; - struct carm_port port[CARM_MAX_PORTS]; - - struct work_struct fsm_task; - - struct semaphore probe_sem; -}; - -struct carm_response { - u32 ret_handle; - u32 status; -} __attribute__((packed)); - -struct carm_msg_sg { - u32 start; - u32 len; -} __attribute__((packed)); - -struct carm_msg_rw { - u8 type; - u8 id; - u8 sg_count; - u8 sg_type; - u32 handle; - u32 lba; - u16 lba_count; - u16 lba_high; - struct carm_msg_sg sg[32]; -} __attribute__((packed)); - -struct carm_msg_allocbuf { - u8 type; - u8 subtype; - u8 n_sg; - u8 sg_type; - u32 handle; - u32 addr; - u32 len; - u32 evt_pool; - u32 n_evt; - u32 rbuf_pool; - u32 n_rbuf; - u32 msg_pool; - u32 n_msg; - struct carm_msg_sg sg[8]; -} __attribute__((packed)); - -struct carm_msg_ioctl { - u8 type; - u8 subtype; - u8 array_id; - u8 reserved1; - u32 handle; - u32 data_addr; - u32 reserved2; -} __attribute__((packed)); - -struct carm_msg_sync_time { - u8 type; - u8 subtype; - u16 reserved1; - u32 handle; - u32 reserved2; - u32 timestamp; -} __attribute__((packed)); - -struct carm_msg_get_fw_ver { - u8 type; - u8 subtype; - u16 reserved1; - u32 handle; - u32 data_addr; - u32 reserved2; -} __attribute__((packed)); - -struct carm_fw_ver { - u32 version; - u8 features; - u8 reserved1; - u16 reserved2; -} __attribute__((packed)); - -struct carm_array_info { - u32 size; - - u16 size_hi; - u16 stripe_size; - - u32 mode; - - u16 stripe_blk_sz; - u16 reserved1; - - u16 cyl; - u16 head; - - u16 sect; - u8 array_id; - u8 reserved2; - - char name[40]; - - u32 array_status; - - /* device list continues beyond this point? */ -} __attribute__((packed)); - -static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static void carm_remove_one (struct pci_dev *pdev); -static int carm_bdev_ioctl(struct inode *ino, struct file *fil, - unsigned int cmd, unsigned long arg); - -static struct pci_device_id carm_pci_tbl[] = { - { PCI_VENDOR_ID_PROMISE, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - { PCI_VENDOR_ID_PROMISE, 0x8002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - { } /* terminate list */ -}; -MODULE_DEVICE_TABLE(pci, carm_pci_tbl); - -static struct pci_driver carm_driver = { - .name = DRV_NAME, - .id_table = carm_pci_tbl, - .probe = carm_init_one, - .remove = carm_remove_one, -}; - -static struct block_device_operations carm_bd_ops = { - .owner = THIS_MODULE, - .ioctl = carm_bdev_ioctl, -}; - -static unsigned int carm_host_id; -static unsigned long carm_major_alloc; - - - -static int carm_bdev_ioctl(struct inode *ino, struct file *fil, - unsigned int cmd, unsigned long arg) -{ - void __user *usermem = (void __user *) arg; - struct carm_port *port = ino->i_bdev->bd_disk->private_data; - struct hd_geometry geom; - - switch (cmd) { - case HDIO_GETGEO: - if (!usermem) - return -EINVAL; - - geom.heads = (u8) port->dev_geom_head; - geom.sectors = (u8) port->dev_geom_sect; - geom.cylinders = port->dev_geom_cyl; - geom.start = get_start_sect(ino->i_bdev); - - if (copy_to_user(usermem, &geom, sizeof(geom))) - return -EFAULT; - return 0; - - default: - break; - } - - return -EOPNOTSUPP; -} - -static const u32 msg_sizes[] = { 32, 64, 128, CARM_MSG_SIZE }; - -static inline int carm_lookup_bucket(u32 msg_size) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(msg_sizes); i++) - if (msg_size <= msg_sizes[i]) - return i; - - return -ENOENT; -} - -static void carm_init_buckets(void *mmio) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(msg_sizes); i++) - writel(msg_sizes[i], mmio + CARM_CMS0 + (4 * i)); -} - -static inline void *carm_ref_msg(struct carm_host *host, - unsigned int msg_idx) -{ - return host->msg_base + (msg_idx * CARM_MSG_SIZE); -} - -static inline dma_addr_t carm_ref_msg_dma(struct carm_host *host, - unsigned int msg_idx) -{ - return host->msg_dma + (msg_idx * CARM_MSG_SIZE); -} - -static int carm_send_msg(struct carm_host *host, - struct carm_request *crq) -{ - void *mmio = host->mmio; - u32 msg = (u32) carm_ref_msg_dma(host, crq->tag); - u32 cm_bucket = crq->msg_bucket; - u32 tmp; - int rc = 0; - - VPRINTK("ENTER\n"); - - tmp = readl(mmio + CARM_HMUC); - if (tmp & CARM_Q_FULL) { -#if 0 - tmp = readl(mmio + CARM_INT_MASK); - tmp |= INT_Q_AVAILABLE; - writel(tmp, mmio + CARM_INT_MASK); - readl(mmio + CARM_INT_MASK); /* flush */ -#endif - DPRINTK("host msg queue full\n"); - rc = -EBUSY; - } else { - writel(msg | (cm_bucket << 1), mmio + CARM_IHQP); - readl(mmio + CARM_IHQP); /* flush */ - } - - return rc; -} - -static struct carm_request *carm_get_request(struct carm_host *host) -{ - unsigned int i; - - /* obey global hardware limit on S/G entries */ - if (host->hw_sg_used >= (CARM_MAX_HOST_SG - CARM_MAX_REQ_SG)) - return NULL; - - for (i = 0; i < CARM_MAX_Q; i++) - if ((host->msg_alloc & (1ULL << i)) == 0) { - struct carm_request *crq = &host->req[i]; - crq->port = NULL; - crq->n_elem = 0; - - host->msg_alloc |= (1ULL << i); - host->n_msgs++; - - assert(host->n_msgs <= CARM_MAX_REQ); - return crq; - } - - DPRINTK("no request available, returning NULL\n"); - return NULL; -} - -static int carm_put_request(struct carm_host *host, struct carm_request *crq) -{ - assert(crq->tag < CARM_MAX_Q); - - if (unlikely((host->msg_alloc & (1ULL << crq->tag)) == 0)) - return -EINVAL; /* tried to clear a tag that was not active */ - - assert(host->hw_sg_used >= crq->n_elem); - - host->msg_alloc &= ~(1ULL << crq->tag); - host->hw_sg_used -= crq->n_elem; - host->n_msgs--; - - return 0; -} - -static struct carm_request *carm_get_special(struct carm_host *host) -{ - unsigned long flags; - struct carm_request *crq = NULL; - struct request *rq; - int tries = 5000; - - while (tries-- > 0) { - spin_lock_irqsave(&host->lock, flags); - crq = carm_get_request(host); - spin_unlock_irqrestore(&host->lock, flags); - - if (crq) - break; - msleep(10); - } - - if (!crq) - return NULL; - - rq = blk_get_request(host->oob_q, WRITE /* bogus */, GFP_KERNEL); - if (!rq) { - spin_lock_irqsave(&host->lock, flags); - carm_put_request(host, crq); - spin_unlock_irqrestore(&host->lock, flags); - return NULL; - } - - crq->rq = rq; - return crq; -} - -static int carm_array_info (struct carm_host *host, unsigned int array_idx) -{ - struct carm_msg_ioctl *ioc; - unsigned int idx; - u32 msg_data; - dma_addr_t msg_dma; - struct carm_request *crq; - int rc; - - crq = carm_get_special(host); - if (!crq) { - rc = -ENOMEM; - goto err_out; - } - - idx = crq->tag; - - ioc = carm_ref_msg(host, idx); - msg_dma = carm_ref_msg_dma(host, idx); - msg_data = (u32) (msg_dma + sizeof(struct carm_array_info)); - - crq->msg_type = CARM_MSG_ARRAY; - crq->msg_subtype = CARM_ARRAY_INFO; - rc = carm_lookup_bucket(sizeof(struct carm_msg_ioctl) + - sizeof(struct carm_array_info)); - BUG_ON(rc < 0); - crq->msg_bucket = (u32) rc; - - memset(ioc, 0, sizeof(*ioc)); - ioc->type = CARM_MSG_ARRAY; - ioc->subtype = CARM_ARRAY_INFO; - ioc->array_id = (u8) array_idx; - ioc->handle = cpu_to_le32(TAG_ENCODE(idx)); - ioc->data_addr = cpu_to_le32(msg_data); - - spin_lock_irq(&host->lock); - assert(host->state == HST_DEV_SCAN_START || - host->state == HST_DEV_SCAN); - spin_unlock_irq(&host->lock); - - DPRINTK("blk_insert_request, tag == %u\n", idx); - blk_insert_request(host->oob_q, crq->rq, 1, crq, 0); - - return 0; - -err_out: - spin_lock_irq(&host->lock); - host->state = HST_ERROR; - spin_unlock_irq(&host->lock); - return rc; -} - -typedef unsigned int (*carm_sspc_t)(struct carm_host *, unsigned int, void *); - -static int carm_send_special (struct carm_host *host, carm_sspc_t func) -{ - struct carm_request *crq; - struct carm_msg_ioctl *ioc; - void *mem; - unsigned int idx, msg_size; - int rc; - - crq = carm_get_special(host); - if (!crq) - return -ENOMEM; - - idx = crq->tag; - - mem = carm_ref_msg(host, idx); - - msg_size = func(host, idx, mem); - - ioc = mem; - crq->msg_type = ioc->type; - crq->msg_subtype = ioc->subtype; - rc = carm_lookup_bucket(msg_size); - BUG_ON(rc < 0); - crq->msg_bucket = (u32) rc; - - DPRINTK("blk_insert_request, tag == %u\n", idx); - blk_insert_request(host->oob_q, crq->rq, 1, crq, 0); - - return 0; -} - -static unsigned int carm_fill_sync_time(struct carm_host *host, - unsigned int idx, void *mem) -{ - struct timeval tv; - struct carm_msg_sync_time *st = mem; - - do_gettimeofday(&tv); - - memset(st, 0, sizeof(*st)); - st->type = CARM_MSG_MISC; - st->subtype = MISC_SET_TIME; - st->handle = cpu_to_le32(TAG_ENCODE(idx)); - st->timestamp = cpu_to_le32(tv.tv_sec); - - return sizeof(struct carm_msg_sync_time); -} - -static unsigned int carm_fill_alloc_buf(struct carm_host *host, - unsigned int idx, void *mem) -{ - struct carm_msg_allocbuf *ab = mem; - - memset(ab, 0, sizeof(*ab)); - ab->type = CARM_MSG_MISC; - ab->subtype = MISC_ALLOC_MEM; - ab->handle = cpu_to_le32(TAG_ENCODE(idx)); - ab->n_sg = 1; - ab->sg_type = SGT_32BIT; - ab->addr = cpu_to_le32(host->shm_dma + (PDC_SHM_SIZE >> 1)); - ab->len = cpu_to_le32(PDC_SHM_SIZE >> 1); - ab->evt_pool = cpu_to_le32(host->shm_dma + (16 * 1024)); - ab->n_evt = cpu_to_le32(1024); - ab->rbuf_pool = cpu_to_le32(host->shm_dma); - ab->n_rbuf = cpu_to_le32(RMSG_Q_LEN); - ab->msg_pool = cpu_to_le32(host->shm_dma + RBUF_LEN); - ab->n_msg = cpu_to_le32(CARM_Q_LEN); - ab->sg[0].start = cpu_to_le32(host->shm_dma + (PDC_SHM_SIZE >> 1)); - ab->sg[0].len = cpu_to_le32(65536); - - return sizeof(struct carm_msg_allocbuf); -} - -static unsigned int carm_fill_scan_channels(struct carm_host *host, - unsigned int idx, void *mem) -{ - struct carm_msg_ioctl *ioc = mem; - u32 msg_data = (u32) (carm_ref_msg_dma(host, idx) + - IOC_SCAN_CHAN_OFFSET); - - memset(ioc, 0, sizeof(*ioc)); - ioc->type = CARM_MSG_IOCTL; - ioc->subtype = CARM_IOC_SCAN_CHAN; - ioc->handle = cpu_to_le32(TAG_ENCODE(idx)); - ioc->data_addr = cpu_to_le32(msg_data); - - /* fill output data area with "no device" default values */ - mem += IOC_SCAN_CHAN_OFFSET; - memset(mem, IOC_SCAN_CHAN_NODEV, CARM_MAX_PORTS); - - return IOC_SCAN_CHAN_OFFSET + CARM_MAX_PORTS; -} - -static unsigned int carm_fill_get_fw_ver(struct carm_host *host, - unsigned int idx, void *mem) -{ - struct carm_msg_get_fw_ver *ioc = mem; - u32 msg_data = (u32) (carm_ref_msg_dma(host, idx) + sizeof(*ioc)); - - memset(ioc, 0, sizeof(*ioc)); - ioc->type = CARM_MSG_MISC; - ioc->subtype = MISC_GET_FW_VER; - ioc->handle = cpu_to_le32(TAG_ENCODE(idx)); - ioc->data_addr = cpu_to_le32(msg_data); - - return sizeof(struct carm_msg_get_fw_ver) + - sizeof(struct carm_fw_ver); -} - -static inline void carm_end_request_queued(struct carm_host *host, - struct carm_request *crq, - int uptodate) -{ - struct request *req = crq->rq; - int rc; - - rc = end_that_request_first(req, uptodate, req->hard_nr_sectors); - assert(rc == 0); - - end_that_request_last(req); - - rc = carm_put_request(host, crq); - assert(rc == 0); -} - -static inline void carm_push_q (struct carm_host *host, request_queue_t *q) -{ - unsigned int idx = host->wait_q_prod % CARM_MAX_WAIT_Q; - - blk_stop_queue(q); - VPRINTK("STOPPED QUEUE %p\n", q); - - host->wait_q[idx] = q; - host->wait_q_prod++; - BUG_ON(host->wait_q_prod == host->wait_q_cons); /* overrun */ -} - -static inline request_queue_t *carm_pop_q(struct carm_host *host) -{ - unsigned int idx; - - if (host->wait_q_prod == host->wait_q_cons) - return NULL; - - idx = host->wait_q_cons % CARM_MAX_WAIT_Q; - host->wait_q_cons++; - - return host->wait_q[idx]; -} - -static inline void carm_round_robin(struct carm_host *host) -{ - request_queue_t *q = carm_pop_q(host); - if (q) { - blk_start_queue(q); - VPRINTK("STARTED QUEUE %p\n", q); - } -} - -static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq, - int is_ok) -{ - carm_end_request_queued(host, crq, is_ok); - if (CARM_MAX_Q == 1) - carm_round_robin(host); - else if ((host->n_msgs <= CARM_MSG_LOW_WATER) && - (host->hw_sg_used <= CARM_SG_LOW_WATER)) { - carm_round_robin(host); - } -} - -static void carm_oob_rq_fn(request_queue_t *q) -{ - struct carm_host *host = q->queuedata; - struct carm_request *crq; - struct request *rq; - int rc; - - while (1) { - DPRINTK("get req\n"); - rq = elv_next_request(q); - if (!rq) - break; - - blkdev_dequeue_request(rq); - - crq = rq->special; - assert(crq != NULL); - assert(crq->rq == rq); - - crq->n_elem = 0; - - DPRINTK("send req\n"); - rc = carm_send_msg(host, crq); - if (rc) { - blk_requeue_request(q, rq); - carm_push_q(host, q); - return; /* call us again later, eventually */ - } - } -} - -static void carm_rq_fn(request_queue_t *q) -{ - struct carm_port *port = q->queuedata; - struct carm_host *host = port->host; - struct carm_msg_rw *msg; - struct carm_request *crq; - struct request *rq; - struct scatterlist *sg; - int writing = 0, pci_dir, i, n_elem, rc; - u32 tmp; - unsigned int msg_size; - -queue_one_request: - VPRINTK("get req\n"); - rq = elv_next_request(q); - if (!rq) - return; - - crq = carm_get_request(host); - if (!crq) { - carm_push_q(host, q); - return; /* call us again later, eventually */ - } - crq->rq = rq; - - blkdev_dequeue_request(rq); - - if (rq_data_dir(rq) == WRITE) { - writing = 1; - pci_dir = PCI_DMA_TODEVICE; - } else { - pci_dir = PCI_DMA_FROMDEVICE; - } - - /* get scatterlist from block layer */ - sg = &crq->sg[0]; - n_elem = blk_rq_map_sg(q, rq, sg); - if (n_elem <= 0) { - carm_end_rq(host, crq, 0); - return; /* request with no s/g entries? */ - } - - /* map scatterlist to PCI bus addresses */ - n_elem = pci_map_sg(host->pdev, sg, n_elem, pci_dir); - if (n_elem <= 0) { - carm_end_rq(host, crq, 0); - return; /* request with no s/g entries? */ - } - crq->n_elem = n_elem; - crq->port = port; - host->hw_sg_used += n_elem; - - /* - * build read/write message - */ - - VPRINTK("build msg\n"); - msg = (struct carm_msg_rw *) carm_ref_msg(host, crq->tag); - - if (writing) { - msg->type = CARM_MSG_WRITE; - crq->msg_type = CARM_MSG_WRITE; - } else { - msg->type = CARM_MSG_READ; - crq->msg_type = CARM_MSG_READ; - } - - msg->id = port->port_no; - msg->sg_count = n_elem; - msg->sg_type = SGT_32BIT; - msg->handle = cpu_to_le32(TAG_ENCODE(crq->tag)); - msg->lba = cpu_to_le32(rq->sector & 0xffffffff); - tmp = (rq->sector >> 16) >> 16; - msg->lba_high = cpu_to_le16( (u16) tmp ); - msg->lba_count = cpu_to_le16(rq->nr_sectors); - - msg_size = sizeof(struct carm_msg_rw) - sizeof(msg->sg); - for (i = 0; i < n_elem; i++) { - struct carm_msg_sg *carm_sg = &msg->sg[i]; - carm_sg->start = cpu_to_le32(sg_dma_address(&crq->sg[i])); - carm_sg->len = cpu_to_le32(sg_dma_len(&crq->sg[i])); - msg_size += sizeof(struct carm_msg_sg); - } - - rc = carm_lookup_bucket(msg_size); - BUG_ON(rc < 0); - crq->msg_bucket = (u32) rc; - - /* - * queue read/write message to hardware - */ - - VPRINTK("send msg, tag == %u\n", crq->tag); - rc = carm_send_msg(host, crq); - if (rc) { - carm_put_request(host, crq); - blk_requeue_request(q, rq); - carm_push_q(host, q); - return; /* call us again later, eventually */ - } - - goto queue_one_request; -} - -static void carm_handle_array_info(struct carm_host *host, - struct carm_request *crq, u8 *mem, - int is_ok) -{ - struct carm_port *port; - u8 *msg_data = mem + sizeof(struct carm_array_info); - struct carm_array_info *desc = (struct carm_array_info *) msg_data; - u64 lo, hi; - int cur_port; - size_t slen; - - DPRINTK("ENTER\n"); - - carm_end_rq(host, crq, is_ok); - - if (!is_ok) - goto out; - if (le32_to_cpu(desc->array_status) & ARRAY_NO_EXIST) - goto out; - - cur_port = host->cur_scan_dev; - - /* should never occur */ - if ((cur_port < 0) || (cur_port >= CARM_MAX_PORTS)) { - printk(KERN_ERR PFX "BUG: cur_scan_dev==%d, array_id==%d\n", - cur_port, (int) desc->array_id); - goto out; - } - - port = &host->port[cur_port]; - - lo = (u64) le32_to_cpu(desc->size); - hi = (u64) le32_to_cpu(desc->size_hi); - - port->capacity = lo | (hi << 32); - port->dev_geom_head = le16_to_cpu(desc->head); - port->dev_geom_sect = le16_to_cpu(desc->sect); - port->dev_geom_cyl = le16_to_cpu(desc->cyl); - - host->dev_active |= (1 << cur_port); - - strncpy(port->name, desc->name, sizeof(port->name)); - port->name[sizeof(port->name) - 1] = 0; - slen = strlen(port->name); - while (slen && (port->name[slen - 1] == ' ')) { - port->name[slen - 1] = 0; - slen--; - } - - printk(KERN_INFO DRV_NAME "(%s): port %u device %Lu sectors\n", - pci_name(host->pdev), port->port_no, - (unsigned long long) port->capacity); - printk(KERN_INFO DRV_NAME "(%s): port %u device \"%s\"\n", - pci_name(host->pdev), port->port_no, port->name); - -out: - assert(host->state == HST_DEV_SCAN); - schedule_work(&host->fsm_task); -} - -static void carm_handle_scan_chan(struct carm_host *host, - struct carm_request *crq, u8 *mem, - int is_ok) -{ - u8 *msg_data = mem + IOC_SCAN_CHAN_OFFSET; - unsigned int i, dev_count = 0; - int new_state = HST_DEV_SCAN_START; - - DPRINTK("ENTER\n"); - - carm_end_rq(host, crq, is_ok); - - if (!is_ok) { - new_state = HST_ERROR; - goto out; - } - - /* TODO: scan and support non-disk devices */ - for (i = 0; i < 8; i++) - if (msg_data[i] == 0) { /* direct-access device (disk) */ - host->dev_present |= (1 << i); - dev_count++; - } - - printk(KERN_INFO DRV_NAME "(%s): found %u interesting devices\n", - pci_name(host->pdev), dev_count); - -out: - assert(host->state == HST_PORT_SCAN); - host->state = new_state; - schedule_work(&host->fsm_task); -} - -static void carm_handle_generic(struct carm_host *host, - struct carm_request *crq, int is_ok, - int cur_state, int next_state) -{ - DPRINTK("ENTER\n"); - - carm_end_rq(host, crq, is_ok); - - assert(host->state == cur_state); - if (is_ok) - host->state = next_state; - else - host->state = HST_ERROR; - schedule_work(&host->fsm_task); -} - -static inline void carm_handle_rw(struct carm_host *host, - struct carm_request *crq, int is_ok) -{ - int pci_dir; - - VPRINTK("ENTER\n"); - - if (rq_data_dir(crq->rq) == WRITE) - pci_dir = PCI_DMA_TODEVICE; - else - pci_dir = PCI_DMA_FROMDEVICE; - - pci_unmap_sg(host->pdev, &crq->sg[0], crq->n_elem, pci_dir); - - carm_end_rq(host, crq, is_ok); -} - -static inline void carm_handle_resp(struct carm_host *host, - u32 ret_handle_le, u32 status) -{ - u32 handle = le32_to_cpu(ret_handle_le); - unsigned int msg_idx; - struct carm_request *crq; - int is_ok = (status == RMSG_OK); - u8 *mem; - - VPRINTK("ENTER, handle == 0x%x\n", handle); - - if (unlikely(!TAG_VALID(handle))) { - printk(KERN_ERR DRV_NAME "(%s): BUG: invalid tag 0x%x\n", - pci_name(host->pdev), handle); - return; - } - - msg_idx = TAG_DECODE(handle); - VPRINTK("tag == %u\n", msg_idx); - - crq = &host->req[msg_idx]; - - /* fast path */ - if (likely(crq->msg_type == CARM_MSG_READ || - crq->msg_type == CARM_MSG_WRITE)) { - carm_handle_rw(host, crq, is_ok); - return; - } - - mem = carm_ref_msg(host, msg_idx); - - switch (crq->msg_type) { - case CARM_MSG_IOCTL: { - switch (crq->msg_subtype) { - case CARM_IOC_SCAN_CHAN: - carm_handle_scan_chan(host, crq, mem, is_ok); - break; - default: - /* unknown / invalid response */ - goto err_out; - } - break; - } - - case CARM_MSG_MISC: { - switch (crq->msg_subtype) { - case MISC_ALLOC_MEM: - carm_handle_generic(host, crq, is_ok, - HST_ALLOC_BUF, HST_SYNC_TIME); - break; - case MISC_SET_TIME: - carm_handle_generic(host, crq, is_ok, - HST_SYNC_TIME, HST_GET_FW_VER); - break; - case MISC_GET_FW_VER: { - struct carm_fw_ver *ver = (struct carm_fw_ver *) - mem + sizeof(struct carm_msg_get_fw_ver); - if (is_ok) { - host->fw_ver = le32_to_cpu(ver->version); - host->flags |= (ver->features & FL_FW_VER_MASK); - } - carm_handle_generic(host, crq, is_ok, - HST_GET_FW_VER, HST_PORT_SCAN); - break; - } - default: - /* unknown / invalid response */ - goto err_out; - } - break; - } - - case CARM_MSG_ARRAY: { - switch (crq->msg_subtype) { - case CARM_ARRAY_INFO: - carm_handle_array_info(host, crq, mem, is_ok); - break; - default: - /* unknown / invalid response */ - goto err_out; - } - break; - } - - default: - /* unknown / invalid response */ - goto err_out; - } - - return; - -err_out: - printk(KERN_WARNING DRV_NAME "(%s): BUG: unhandled message type %d/%d\n", - pci_name(host->pdev), crq->msg_type, crq->msg_subtype); - carm_end_rq(host, crq, 0); -} - -static inline void carm_handle_responses(struct carm_host *host) -{ - void *mmio = host->mmio; - struct carm_response *resp = (struct carm_response *) host->shm; - unsigned int work = 0; - unsigned int idx = host->resp_idx % RMSG_Q_LEN; - - while (1) { - u32 status = le32_to_cpu(resp[idx].status); - - if (status == 0xffffffff) { - VPRINTK("ending response on index %u\n", idx); - writel(idx << 3, mmio + CARM_RESP_IDX); - break; - } - - /* response to a message we sent */ - else if ((status & (1 << 31)) == 0) { - VPRINTK("handling msg response on index %u\n", idx); - carm_handle_resp(host, resp[idx].ret_handle, status); - resp[idx].status = 0xffffffff; - } - - /* asynchronous events the hardware throws our way */ - else if ((status & 0xff000000) == (1 << 31)) { - u8 *evt_type_ptr = (u8 *) &resp[idx]; - u8 evt_type = *evt_type_ptr; - printk(KERN_WARNING DRV_NAME "(%s): unhandled event type %d\n", - pci_name(host->pdev), (int) evt_type); - resp[idx].status = 0xffffffff; - } - - idx = NEXT_RESP(idx); - work++; - } - - VPRINTK("EXIT, work==%u\n", work); - host->resp_idx += work; -} - -static irqreturn_t carm_interrupt(int irq, void *__host, struct pt_regs *regs) -{ - struct carm_host *host = __host; - void *mmio; - u32 mask; - int handled = 0; - unsigned long flags; - - if (!host) { - VPRINTK("no host\n"); - return IRQ_NONE; - } - - spin_lock_irqsave(&host->lock, flags); - - mmio = host->mmio; - - /* reading should also clear interrupts */ - mask = readl(mmio + CARM_INT_STAT); - - if (mask == 0 || mask == 0xffffffff) { - VPRINTK("no work, mask == 0x%x\n", mask); - goto out; - } - - if (mask & INT_ACK_MASK) - writel(mask, mmio + CARM_INT_STAT); - - if (unlikely(host->state == HST_INVALID)) { - VPRINTK("not initialized yet, mask = 0x%x\n", mask); - goto out; - } - - if (mask & CARM_HAVE_RESP) { - handled = 1; - carm_handle_responses(host); - } - -out: - spin_unlock_irqrestore(&host->lock, flags); - VPRINTK("EXIT\n"); - return IRQ_RETVAL(handled); -} - -static void carm_fsm_task (void *_data) -{ - struct carm_host *host = _data; - unsigned long flags; - unsigned int state; - int rc, i, next_dev; - int reschedule = 0; - int new_state = HST_INVALID; - - spin_lock_irqsave(&host->lock, flags); - state = host->state; - spin_unlock_irqrestore(&host->lock, flags); - - DPRINTK("ENTER, state == %s\n", state_name[state]); - - switch (state) { - case HST_PROBE_START: - new_state = HST_ALLOC_BUF; - reschedule = 1; - break; - - case HST_ALLOC_BUF: - rc = carm_send_special(host, carm_fill_alloc_buf); - if (rc) { - new_state = HST_ERROR; - reschedule = 1; - } - break; - - case HST_SYNC_TIME: - rc = carm_send_special(host, carm_fill_sync_time); - if (rc) { - new_state = HST_ERROR; - reschedule = 1; - } - break; - - case HST_GET_FW_VER: - rc = carm_send_special(host, carm_fill_get_fw_ver); - if (rc) { - new_state = HST_ERROR; - reschedule = 1; - } - break; - - case HST_PORT_SCAN: - rc = carm_send_special(host, carm_fill_scan_channels); - if (rc) { - new_state = HST_ERROR; - reschedule = 1; - } - break; - - case HST_DEV_SCAN_START: - host->cur_scan_dev = -1; - new_state = HST_DEV_SCAN; - reschedule = 1; - break; - - case HST_DEV_SCAN: - next_dev = -1; - for (i = host->cur_scan_dev + 1; i < CARM_MAX_PORTS; i++) - if (host->dev_present & (1 << i)) { - next_dev = i; - break; - } - - if (next_dev >= 0) { - host->cur_scan_dev = next_dev; - rc = carm_array_info(host, next_dev); - if (rc) { - new_state = HST_ERROR; - reschedule = 1; - } - } else { - new_state = HST_DEV_ACTIVATE; - reschedule = 1; - } - break; - - case HST_DEV_ACTIVATE: { - int activated = 0; - for (i = 0; i < CARM_MAX_PORTS; i++) - if (host->dev_active & (1 << i)) { - struct carm_port *port = &host->port[i]; - struct gendisk *disk = port->disk; - - set_capacity(disk, port->capacity); - add_disk(disk); - activated++; - } - - printk(KERN_INFO DRV_NAME "(%s): %d ports activated\n", - pci_name(host->pdev), activated); - - new_state = HST_PROBE_FINISHED; - reschedule = 1; - break; - } - - case HST_PROBE_FINISHED: - up(&host->probe_sem); - break; - - case HST_ERROR: - /* FIXME: TODO */ - break; - - default: - /* should never occur */ - printk(KERN_ERR PFX "BUG: unknown state %d\n", state); - assert(0); - break; - } - - if (new_state != HST_INVALID) { - spin_lock_irqsave(&host->lock, flags); - host->state = new_state; - spin_unlock_irqrestore(&host->lock, flags); - } - if (reschedule) - schedule_work(&host->fsm_task); -} - -static int carm_init_wait(void *mmio, u32 bits, unsigned int test_bit) -{ - unsigned int i; - - for (i = 0; i < 50000; i++) { - u32 tmp = readl(mmio + CARM_LMUC); - udelay(100); - - if (test_bit) { - if ((tmp & bits) == bits) - return 0; - } else { - if ((tmp & bits) == 0) - return 0; - } - - cond_resched(); - } - - printk(KERN_ERR PFX "carm_init_wait timeout, bits == 0x%x, test_bit == %s\n", - bits, test_bit ? "yes" : "no"); - return -EBUSY; -} - -static void carm_init_responses(struct carm_host *host) -{ - void *mmio = host->mmio; - unsigned int i; - struct carm_response *resp = (struct carm_response *) host->shm; - - for (i = 0; i < RMSG_Q_LEN; i++) - resp[i].status = 0xffffffff; - - writel(0, mmio + CARM_RESP_IDX); -} - -static int carm_init_host(struct carm_host *host) -{ - void *mmio = host->mmio; - u32 tmp; - u8 tmp8; - int rc; - - DPRINTK("ENTER\n"); - - writel(0, mmio + CARM_INT_MASK); - - tmp8 = readb(mmio + CARM_INITC); - if (tmp8 & 0x01) { - tmp8 &= ~0x01; - writeb(tmp8, CARM_INITC); - readb(mmio + CARM_INITC); /* flush */ - - DPRINTK("snooze...\n"); - msleep(5000); - } - - tmp = readl(mmio + CARM_HMUC); - if (tmp & CARM_CME) { - DPRINTK("CME bit present, waiting\n"); - rc = carm_init_wait(mmio, CARM_CME, 1); - if (rc) { - DPRINTK("EXIT, carm_init_wait 1 failed\n"); - return rc; - } - } - if (tmp & CARM_RME) { - DPRINTK("RME bit present, waiting\n"); - rc = carm_init_wait(mmio, CARM_RME, 1); - if (rc) { - DPRINTK("EXIT, carm_init_wait 2 failed\n"); - return rc; - } - } - - tmp &= ~(CARM_RME | CARM_CME); - writel(tmp, mmio + CARM_HMUC); - readl(mmio + CARM_HMUC); /* flush */ - - rc = carm_init_wait(mmio, CARM_RME | CARM_CME, 0); - if (rc) { - DPRINTK("EXIT, carm_init_wait 3 failed\n"); - return rc; - } - - carm_init_buckets(mmio); - - writel(host->shm_dma & 0xffffffff, mmio + RBUF_ADDR_LO); - writel((host->shm_dma >> 16) >> 16, mmio + RBUF_ADDR_HI); - writel(RBUF_LEN, mmio + RBUF_BYTE_SZ); - - tmp = readl(mmio + CARM_HMUC); - tmp |= (CARM_RME | CARM_CME | CARM_WZBC); - writel(tmp, mmio + CARM_HMUC); - readl(mmio + CARM_HMUC); /* flush */ - - rc = carm_init_wait(mmio, CARM_RME | CARM_CME, 1); - if (rc) { - DPRINTK("EXIT, carm_init_wait 4 failed\n"); - return rc; - } - - writel(0, mmio + CARM_HMPHA); - writel(INT_DEF_MASK, mmio + CARM_INT_MASK); - - carm_init_responses(host); - - /* start initialization, probing state machine */ - spin_lock_irq(&host->lock); - assert(host->state == HST_INVALID); - host->state = HST_PROBE_START; - spin_unlock_irq(&host->lock); - schedule_work(&host->fsm_task); - - DPRINTK("EXIT\n"); - return 0; -} - -static int carm_init_disks(struct carm_host *host) -{ - unsigned int i; - int rc = 0; - - for (i = 0; i < CARM_MAX_PORTS; i++) { - struct gendisk *disk; - request_queue_t *q; - struct carm_port *port; - - port = &host->port[i]; - port->host = host; - port->port_no = i; - - disk = alloc_disk(CARM_MINORS_PER_MAJOR); - if (!disk) { - rc = -ENOMEM; - break; - } - - port->disk = disk; - sprintf(disk->disk_name, DRV_NAME "%u_%u", host->id, i); - sprintf(disk->devfs_name, DRV_NAME "/%u_%u", host->id, i); - disk->major = host->major; - disk->first_minor = i * CARM_MINORS_PER_MAJOR; - disk->fops = &carm_bd_ops; - disk->private_data = port; - - q = blk_init_queue(carm_rq_fn, &host->lock); - if (!q) { - rc = -ENOMEM; - break; - } - disk->queue = q; - blk_queue_max_hw_segments(q, CARM_MAX_REQ_SG); - blk_queue_max_phys_segments(q, CARM_MAX_REQ_SG); - blk_queue_segment_boundary(q, CARM_SG_BOUNDARY); - - q->queuedata = port; - } - - return rc; -} - -static void carm_free_disks(struct carm_host *host) -{ - unsigned int i; - - for (i = 0; i < CARM_MAX_PORTS; i++) { - struct gendisk *disk = host->port[i].disk; - if (disk) { - request_queue_t *q = disk->queue; - - if (disk->flags & GENHD_FL_UP) - del_gendisk(disk); - if (q) - blk_cleanup_queue(q); - put_disk(disk); - } - } -} - -static int carm_init_shm(struct carm_host *host) -{ - host->shm = pci_alloc_consistent(host->pdev, CARM_SHM_SIZE, - &host->shm_dma); - if (!host->shm) - return -ENOMEM; - - host->msg_base = host->shm + RBUF_LEN; - host->msg_dma = host->shm_dma + RBUF_LEN; - - memset(host->shm, 0xff, RBUF_LEN); - memset(host->msg_base, 0, PDC_SHM_SIZE - RBUF_LEN); - - return 0; -} - -static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) -{ - static unsigned int printed_version; - struct carm_host *host; - unsigned int pci_dac; - int rc; - request_queue_t *q; - unsigned int i; - - if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); - - rc = pci_enable_device(pdev); - if (rc) - return rc; - - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) - goto err_out; - -#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */ - rc = pci_set_dma_mask(pdev, 0xffffffffffffffffULL); - if (!rc) { - rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL); - if (rc) { - printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n", - pci_name(pdev)); - goto err_out_regions; - } - pci_dac = 1; - } else { -#endif - rc = pci_set_dma_mask(pdev, 0xffffffffULL); - if (rc) { - printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n", - pci_name(pdev)); - goto err_out_regions; - } - pci_dac = 0; -#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */ - } -#endif - - host = kmalloc(sizeof(*host), GFP_KERNEL); - if (!host) { - printk(KERN_ERR DRV_NAME "(%s): memory alloc failure\n", - pci_name(pdev)); - rc = -ENOMEM; - goto err_out_regions; - } - - memset(host, 0, sizeof(*host)); - host->pdev = pdev; - host->flags = pci_dac ? FL_DAC : 0; - spin_lock_init(&host->lock); - INIT_WORK(&host->fsm_task, carm_fsm_task, host); - init_MUTEX_LOCKED(&host->probe_sem); - - for (i = 0; i < ARRAY_SIZE(host->req); i++) - host->req[i].tag = i; - - host->mmio = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - if (!host->mmio) { - printk(KERN_ERR DRV_NAME "(%s): MMIO alloc failure\n", - pci_name(pdev)); - rc = -ENOMEM; - goto err_out_kfree; - } - - rc = carm_init_shm(host); - if (rc) { - printk(KERN_ERR DRV_NAME "(%s): DMA SHM alloc failure\n", - pci_name(pdev)); - goto err_out_iounmap; - } - - q = blk_init_queue(carm_oob_rq_fn, &host->lock); - if (!q) { - printk(KERN_ERR DRV_NAME "(%s): OOB queue alloc failure\n", - pci_name(pdev)); - rc = -ENOMEM; - goto err_out_pci_free; - } - host->oob_q = q; - q->queuedata = host; - - /* - * Figure out which major to use: 160, 161, or dynamic - */ - if (!test_and_set_bit(0, &carm_major_alloc)) - host->major = 160; - else if (!test_and_set_bit(1, &carm_major_alloc)) - host->major = 161; - else - host->flags |= FL_DYN_MAJOR; - - host->id = carm_host_id; - sprintf(host->name, DRV_NAME "%d", carm_host_id); - - rc = register_blkdev(host->major, host->name); - if (rc < 0) - goto err_out_free_majors; - if (host->flags & FL_DYN_MAJOR) - host->major = rc; - - devfs_mk_dir(DRV_NAME); - - rc = carm_init_disks(host); - if (rc) - goto err_out_blkdev_disks; - - pci_set_master(pdev); - - rc = request_irq(pdev->irq, carm_interrupt, SA_SHIRQ, DRV_NAME, host); - if (rc) { - printk(KERN_ERR DRV_NAME "(%s): irq alloc failure\n", - pci_name(pdev)); - goto err_out_blkdev_disks; - } - - rc = carm_init_host(host); - if (rc) - goto err_out_free_irq; - - DPRINTK("waiting for probe_sem\n"); - down(&host->probe_sem); - - printk(KERN_INFO "%s: pci %s, ports %d, io %lx, irq %u, major %d\n", - host->name, pci_name(pdev), (int) CARM_MAX_PORTS, - pci_resource_start(pdev, 0), pdev->irq, host->major); - - carm_host_id++; - pci_set_drvdata(pdev, host); - return 0; - -err_out_free_irq: - free_irq(pdev->irq, host); -err_out_blkdev_disks: - carm_free_disks(host); - unregister_blkdev(host->major, host->name); -err_out_free_majors: - if (host->major == 160) - clear_bit(0, &carm_major_alloc); - else if (host->major == 161) - clear_bit(1, &carm_major_alloc); - blk_cleanup_queue(host->oob_q); -err_out_pci_free: - pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma); -err_out_iounmap: - iounmap(host->mmio); -err_out_kfree: - kfree(host); -err_out_regions: - pci_release_regions(pdev); -err_out: - pci_disable_device(pdev); - return rc; -} - -static void carm_remove_one (struct pci_dev *pdev) -{ - struct carm_host *host = pci_get_drvdata(pdev); - - if (!host) { - printk(KERN_ERR PFX "BUG: no host data for PCI(%s)\n", - pci_name(pdev)); - return; - } - - free_irq(pdev->irq, host); - carm_free_disks(host); - devfs_remove(DRV_NAME); - unregister_blkdev(host->major, host->name); - if (host->major == 160) - clear_bit(0, &carm_major_alloc); - else if (host->major == 161) - clear_bit(1, &carm_major_alloc); - blk_cleanup_queue(host->oob_q); - pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma); - iounmap(host->mmio); - kfree(host); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); -} - -static int __init carm_init(void) -{ - return pci_module_init(&carm_driver); -} - -static void __exit carm_exit(void) -{ - pci_unregister_driver(&carm_driver); -} - -module_init(carm_init); -module_exit(carm_exit); - - diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c new file mode 100644 index 000000000000..38fd6fe42d07 --- /dev/null +++ b/drivers/block/sx8.c @@ -0,0 +1,1763 @@ +/* + * carmel.c: Driver for Promise SATA SX8 looks-like-I2O hardware + * + * Copyright 2004 Red Hat, Inc. + * + * Author/maintainer: Jeff Garzik + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jeff Garzik"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Promise SATA SX8 (carmel) block driver"); + +#if 0 +#define CARM_DEBUG +#define CARM_VERBOSE_DEBUG +#else +#undef CARM_DEBUG +#undef CARM_VERBOSE_DEBUG +#endif +#undef CARM_NDEBUG + +#define DRV_NAME "carmel" +#define DRV_VERSION "0.8" +#define PFX DRV_NAME ": " + +#define NEXT_RESP(idx) ((idx + 1) % RMSG_Q_LEN) + +/* 0xf is just arbitrary, non-zero noise; this is sorta like poisoning */ +#define TAG_ENCODE(tag) (((tag) << 16) | 0xf) +#define TAG_DECODE(tag) (((tag) >> 16) & 0x1f) +#define TAG_VALID(tag) ((((tag) & 0xf) == 0xf) && (TAG_DECODE(tag) < 32)) + +/* note: prints function name for you */ +#ifdef CARM_DEBUG +#define DPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) +#ifdef CARM_VERBOSE_DEBUG +#define VPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) +#else +#define VPRINTK(fmt, args...) +#endif /* CARM_VERBOSE_DEBUG */ +#else +#define DPRINTK(fmt, args...) +#define VPRINTK(fmt, args...) +#endif /* CARM_DEBUG */ + +#ifdef CARM_NDEBUG +#define assert(expr) +#else +#define assert(expr) \ + if(unlikely(!(expr))) { \ + printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + } +#endif + +/* defines only for the constants which don't work well as enums */ +struct carm_host; + +enum { + /* adapter-wide limits */ + CARM_MAX_PORTS = 8, + CARM_SHM_SIZE = (4096 << 7), + CARM_MINORS_PER_MAJOR = 256 / CARM_MAX_PORTS, + CARM_MAX_WAIT_Q = CARM_MAX_PORTS + 1, + + /* command message queue limits */ + CARM_MAX_REQ = 64, /* max command msgs per host */ + CARM_MAX_Q = 1, /* one command at a time */ + CARM_MSG_LOW_WATER = (CARM_MAX_REQ / 4), /* refill mark */ + + /* S/G limits, host-wide and per-request */ + CARM_MAX_REQ_SG = 32, /* max s/g entries per request */ + CARM_SG_BOUNDARY = 0xffffUL, /* s/g segment boundary */ + CARM_MAX_HOST_SG = 600, /* max s/g entries per host */ + CARM_SG_LOW_WATER = (CARM_MAX_HOST_SG / 4), /* re-fill mark */ + + /* hardware registers */ + CARM_IHQP = 0x1c, + CARM_INT_STAT = 0x10, /* interrupt status */ + CARM_INT_MASK = 0x14, /* interrupt mask */ + CARM_HMUC = 0x18, /* host message unit control */ + RBUF_ADDR_LO = 0x20, /* response msg DMA buf low 32 bits */ + RBUF_ADDR_HI = 0x24, /* response msg DMA buf high 32 bits */ + RBUF_BYTE_SZ = 0x28, + CARM_RESP_IDX = 0x2c, + CARM_CMS0 = 0x30, /* command message size reg 0 */ + CARM_LMUC = 0x48, + CARM_HMPHA = 0x6c, + CARM_INITC = 0xb5, + + /* bits in CARM_INT_{STAT,MASK} */ + INT_RESERVED = 0xfffffff0, + INT_WATCHDOG = (1 << 3), /* watchdog timer */ + INT_Q_OVERFLOW = (1 << 2), /* cmd msg q overflow */ + INT_Q_AVAILABLE = (1 << 1), /* cmd msg q has free space */ + INT_RESPONSE = (1 << 0), /* response msg available */ + INT_ACK_MASK = INT_WATCHDOG | INT_Q_OVERFLOW, + INT_DEF_MASK = INT_RESERVED | INT_Q_OVERFLOW | + INT_RESPONSE, + + /* command messages, and related register bits */ + CARM_HAVE_RESP = 0x01, + CARM_MSG_READ = 1, + CARM_MSG_WRITE = 2, + CARM_MSG_VERIFY = 3, + CARM_MSG_GET_CAPACITY = 4, + CARM_MSG_FLUSH = 5, + CARM_MSG_IOCTL = 6, + CARM_MSG_ARRAY = 8, + CARM_MSG_MISC = 9, + CARM_CME = (1 << 2), + CARM_RME = (1 << 1), + CARM_WZBC = (1 << 0), + CARM_RMI = (1 << 0), + CARM_Q_FULL = (1 << 3), + CARM_MSG_SIZE = 288, + CARM_Q_LEN = 48, + + /* CARM_MSG_IOCTL messages */ + CARM_IOC_SCAN_CHAN = 5, /* scan channels for devices */ + CARM_IOC_GET_TCQ = 13, /* get tcq/ncq depth */ + CARM_IOC_SET_TCQ = 14, /* set tcq/ncq depth */ + + IOC_SCAN_CHAN_NODEV = 0x1f, + IOC_SCAN_CHAN_OFFSET = 0x40, + + /* CARM_MSG_ARRAY messages */ + CARM_ARRAY_INFO = 0, + + ARRAY_NO_EXIST = (1 << 31), + + /* response messages */ + RMSG_SZ = 8, /* sizeof(struct carm_response) */ + RMSG_Q_LEN = 48, /* resp. msg list length */ + RMSG_OK = 1, /* bit indicating msg was successful */ + /* length of entire resp. msg buffer */ + RBUF_LEN = RMSG_SZ * RMSG_Q_LEN, + + PDC_SHM_SIZE = (4096 << 7), /* length of entire h/w buffer */ + + /* CARM_MSG_MISC messages */ + MISC_GET_FW_VER = 2, + MISC_ALLOC_MEM = 3, + MISC_SET_TIME = 5, + + /* MISC_GET_FW_VER feature bits */ + FW_VER_4PORT = (1 << 2), /* 1=4 ports, 0=8 ports */ + FW_VER_NON_RAID = (1 << 1), /* 1=non-RAID firmware, 0=RAID */ + FW_VER_ZCR = (1 << 0), /* zero channel RAID (whatever that is) */ + + /* carm_host flags */ + FL_NON_RAID = FW_VER_NON_RAID, + FL_4PORT = FW_VER_4PORT, + FL_FW_VER_MASK = (FW_VER_NON_RAID | FW_VER_4PORT), + FL_DAC = (1 << 16), + FL_DYN_MAJOR = (1 << 17), +}; + +enum scatter_gather_types { + SGT_32BIT = 0, + SGT_64BIT = 1, +}; + +enum host_states { + HST_INVALID, /* invalid state; never used */ + HST_ALLOC_BUF, /* setting up master SHM area */ + HST_ERROR, /* we never leave here */ + HST_PORT_SCAN, /* start dev scan */ + HST_DEV_SCAN_START, /* start per-device probe */ + HST_DEV_SCAN, /* continue per-device probe */ + HST_DEV_ACTIVATE, /* activate devices we found */ + HST_PROBE_FINISHED, /* probe is complete */ + HST_PROBE_START, /* initiate probe */ + HST_SYNC_TIME, /* tell firmware what time it is */ + HST_GET_FW_VER, /* get firmware version, adapter port cnt */ +}; + +#ifdef CARM_DEBUG +static const char *state_name[] = { + "HST_INVALID", + "HST_ALLOC_BUF", + "HST_ERROR", + "HST_PORT_SCAN", + "HST_DEV_SCAN_START", + "HST_DEV_SCAN", + "HST_DEV_ACTIVATE", + "HST_PROBE_FINISHED", + "HST_PROBE_START", + "HST_SYNC_TIME", + "HST_GET_FW_VER", +}; +#endif + +struct carm_port { + unsigned int port_no; + unsigned int n_queued; + struct gendisk *disk; + struct carm_host *host; + + /* attached device characteristics */ + u64 capacity; + char name[41]; + u16 dev_geom_head; + u16 dev_geom_sect; + u16 dev_geom_cyl; +}; + +struct carm_request { + unsigned int tag; + int n_elem; + unsigned int msg_type; + unsigned int msg_subtype; + unsigned int msg_bucket; + struct request *rq; + struct carm_port *port; + struct scatterlist sg[CARM_MAX_REQ_SG]; +}; + +struct carm_host { + unsigned long flags; + void *mmio; + void *shm; + dma_addr_t shm_dma; + + int major; + int id; + char name[32]; + + spinlock_t lock; + struct pci_dev *pdev; + unsigned int state; + u32 fw_ver; + + request_queue_t *oob_q; + unsigned int n_oob; + + unsigned int hw_sg_used; + + unsigned int resp_idx; + + unsigned int wait_q_prod; + unsigned int wait_q_cons; + request_queue_t *wait_q[CARM_MAX_WAIT_Q]; + + unsigned int n_msgs; + u64 msg_alloc; + struct carm_request req[CARM_MAX_REQ]; + void *msg_base; + dma_addr_t msg_dma; + + int cur_scan_dev; + unsigned long dev_active; + unsigned long dev_present; + struct carm_port port[CARM_MAX_PORTS]; + + struct work_struct fsm_task; + + struct semaphore probe_sem; +}; + +struct carm_response { + u32 ret_handle; + u32 status; +} __attribute__((packed)); + +struct carm_msg_sg { + u32 start; + u32 len; +} __attribute__((packed)); + +struct carm_msg_rw { + u8 type; + u8 id; + u8 sg_count; + u8 sg_type; + u32 handle; + u32 lba; + u16 lba_count; + u16 lba_high; + struct carm_msg_sg sg[32]; +} __attribute__((packed)); + +struct carm_msg_allocbuf { + u8 type; + u8 subtype; + u8 n_sg; + u8 sg_type; + u32 handle; + u32 addr; + u32 len; + u32 evt_pool; + u32 n_evt; + u32 rbuf_pool; + u32 n_rbuf; + u32 msg_pool; + u32 n_msg; + struct carm_msg_sg sg[8]; +} __attribute__((packed)); + +struct carm_msg_ioctl { + u8 type; + u8 subtype; + u8 array_id; + u8 reserved1; + u32 handle; + u32 data_addr; + u32 reserved2; +} __attribute__((packed)); + +struct carm_msg_sync_time { + u8 type; + u8 subtype; + u16 reserved1; + u32 handle; + u32 reserved2; + u32 timestamp; +} __attribute__((packed)); + +struct carm_msg_get_fw_ver { + u8 type; + u8 subtype; + u16 reserved1; + u32 handle; + u32 data_addr; + u32 reserved2; +} __attribute__((packed)); + +struct carm_fw_ver { + u32 version; + u8 features; + u8 reserved1; + u16 reserved2; +} __attribute__((packed)); + +struct carm_array_info { + u32 size; + + u16 size_hi; + u16 stripe_size; + + u32 mode; + + u16 stripe_blk_sz; + u16 reserved1; + + u16 cyl; + u16 head; + + u16 sect; + u8 array_id; + u8 reserved2; + + char name[40]; + + u32 array_status; + + /* device list continues beyond this point? */ +} __attribute__((packed)); + +static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +static void carm_remove_one (struct pci_dev *pdev); +static int carm_bdev_ioctl(struct inode *ino, struct file *fil, + unsigned int cmd, unsigned long arg); + +static struct pci_device_id carm_pci_tbl[] = { + { PCI_VENDOR_ID_PROMISE, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { PCI_VENDOR_ID_PROMISE, 0x8002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { } /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, carm_pci_tbl); + +static struct pci_driver carm_driver = { + .name = DRV_NAME, + .id_table = carm_pci_tbl, + .probe = carm_init_one, + .remove = carm_remove_one, +}; + +static struct block_device_operations carm_bd_ops = { + .owner = THIS_MODULE, + .ioctl = carm_bdev_ioctl, +}; + +static unsigned int carm_host_id; +static unsigned long carm_major_alloc; + + + +static int carm_bdev_ioctl(struct inode *ino, struct file *fil, + unsigned int cmd, unsigned long arg) +{ + void __user *usermem = (void __user *) arg; + struct carm_port *port = ino->i_bdev->bd_disk->private_data; + struct hd_geometry geom; + + switch (cmd) { + case HDIO_GETGEO: + if (!usermem) + return -EINVAL; + + geom.heads = (u8) port->dev_geom_head; + geom.sectors = (u8) port->dev_geom_sect; + geom.cylinders = port->dev_geom_cyl; + geom.start = get_start_sect(ino->i_bdev); + + if (copy_to_user(usermem, &geom, sizeof(geom))) + return -EFAULT; + return 0; + + default: + break; + } + + return -EOPNOTSUPP; +} + +static const u32 msg_sizes[] = { 32, 64, 128, CARM_MSG_SIZE }; + +static inline int carm_lookup_bucket(u32 msg_size) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(msg_sizes); i++) + if (msg_size <= msg_sizes[i]) + return i; + + return -ENOENT; +} + +static void carm_init_buckets(void *mmio) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(msg_sizes); i++) + writel(msg_sizes[i], mmio + CARM_CMS0 + (4 * i)); +} + +static inline void *carm_ref_msg(struct carm_host *host, + unsigned int msg_idx) +{ + return host->msg_base + (msg_idx * CARM_MSG_SIZE); +} + +static inline dma_addr_t carm_ref_msg_dma(struct carm_host *host, + unsigned int msg_idx) +{ + return host->msg_dma + (msg_idx * CARM_MSG_SIZE); +} + +static int carm_send_msg(struct carm_host *host, + struct carm_request *crq) +{ + void *mmio = host->mmio; + u32 msg = (u32) carm_ref_msg_dma(host, crq->tag); + u32 cm_bucket = crq->msg_bucket; + u32 tmp; + int rc = 0; + + VPRINTK("ENTER\n"); + + tmp = readl(mmio + CARM_HMUC); + if (tmp & CARM_Q_FULL) { +#if 0 + tmp = readl(mmio + CARM_INT_MASK); + tmp |= INT_Q_AVAILABLE; + writel(tmp, mmio + CARM_INT_MASK); + readl(mmio + CARM_INT_MASK); /* flush */ +#endif + DPRINTK("host msg queue full\n"); + rc = -EBUSY; + } else { + writel(msg | (cm_bucket << 1), mmio + CARM_IHQP); + readl(mmio + CARM_IHQP); /* flush */ + } + + return rc; +} + +static struct carm_request *carm_get_request(struct carm_host *host) +{ + unsigned int i; + + /* obey global hardware limit on S/G entries */ + if (host->hw_sg_used >= (CARM_MAX_HOST_SG - CARM_MAX_REQ_SG)) + return NULL; + + for (i = 0; i < CARM_MAX_Q; i++) + if ((host->msg_alloc & (1ULL << i)) == 0) { + struct carm_request *crq = &host->req[i]; + crq->port = NULL; + crq->n_elem = 0; + + host->msg_alloc |= (1ULL << i); + host->n_msgs++; + + assert(host->n_msgs <= CARM_MAX_REQ); + return crq; + } + + DPRINTK("no request available, returning NULL\n"); + return NULL; +} + +static int carm_put_request(struct carm_host *host, struct carm_request *crq) +{ + assert(crq->tag < CARM_MAX_Q); + + if (unlikely((host->msg_alloc & (1ULL << crq->tag)) == 0)) + return -EINVAL; /* tried to clear a tag that was not active */ + + assert(host->hw_sg_used >= crq->n_elem); + + host->msg_alloc &= ~(1ULL << crq->tag); + host->hw_sg_used -= crq->n_elem; + host->n_msgs--; + + return 0; +} + +static struct carm_request *carm_get_special(struct carm_host *host) +{ + unsigned long flags; + struct carm_request *crq = NULL; + struct request *rq; + int tries = 5000; + + while (tries-- > 0) { + spin_lock_irqsave(&host->lock, flags); + crq = carm_get_request(host); + spin_unlock_irqrestore(&host->lock, flags); + + if (crq) + break; + msleep(10); + } + + if (!crq) + return NULL; + + rq = blk_get_request(host->oob_q, WRITE /* bogus */, GFP_KERNEL); + if (!rq) { + spin_lock_irqsave(&host->lock, flags); + carm_put_request(host, crq); + spin_unlock_irqrestore(&host->lock, flags); + return NULL; + } + + crq->rq = rq; + return crq; +} + +static int carm_array_info (struct carm_host *host, unsigned int array_idx) +{ + struct carm_msg_ioctl *ioc; + unsigned int idx; + u32 msg_data; + dma_addr_t msg_dma; + struct carm_request *crq; + int rc; + + crq = carm_get_special(host); + if (!crq) { + rc = -ENOMEM; + goto err_out; + } + + idx = crq->tag; + + ioc = carm_ref_msg(host, idx); + msg_dma = carm_ref_msg_dma(host, idx); + msg_data = (u32) (msg_dma + sizeof(struct carm_array_info)); + + crq->msg_type = CARM_MSG_ARRAY; + crq->msg_subtype = CARM_ARRAY_INFO; + rc = carm_lookup_bucket(sizeof(struct carm_msg_ioctl) + + sizeof(struct carm_array_info)); + BUG_ON(rc < 0); + crq->msg_bucket = (u32) rc; + + memset(ioc, 0, sizeof(*ioc)); + ioc->type = CARM_MSG_ARRAY; + ioc->subtype = CARM_ARRAY_INFO; + ioc->array_id = (u8) array_idx; + ioc->handle = cpu_to_le32(TAG_ENCODE(idx)); + ioc->data_addr = cpu_to_le32(msg_data); + + spin_lock_irq(&host->lock); + assert(host->state == HST_DEV_SCAN_START || + host->state == HST_DEV_SCAN); + spin_unlock_irq(&host->lock); + + DPRINTK("blk_insert_request, tag == %u\n", idx); + blk_insert_request(host->oob_q, crq->rq, 1, crq, 0); + + return 0; + +err_out: + spin_lock_irq(&host->lock); + host->state = HST_ERROR; + spin_unlock_irq(&host->lock); + return rc; +} + +typedef unsigned int (*carm_sspc_t)(struct carm_host *, unsigned int, void *); + +static int carm_send_special (struct carm_host *host, carm_sspc_t func) +{ + struct carm_request *crq; + struct carm_msg_ioctl *ioc; + void *mem; + unsigned int idx, msg_size; + int rc; + + crq = carm_get_special(host); + if (!crq) + return -ENOMEM; + + idx = crq->tag; + + mem = carm_ref_msg(host, idx); + + msg_size = func(host, idx, mem); + + ioc = mem; + crq->msg_type = ioc->type; + crq->msg_subtype = ioc->subtype; + rc = carm_lookup_bucket(msg_size); + BUG_ON(rc < 0); + crq->msg_bucket = (u32) rc; + + DPRINTK("blk_insert_request, tag == %u\n", idx); + blk_insert_request(host->oob_q, crq->rq, 1, crq, 0); + + return 0; +} + +static unsigned int carm_fill_sync_time(struct carm_host *host, + unsigned int idx, void *mem) +{ + struct timeval tv; + struct carm_msg_sync_time *st = mem; + + do_gettimeofday(&tv); + + memset(st, 0, sizeof(*st)); + st->type = CARM_MSG_MISC; + st->subtype = MISC_SET_TIME; + st->handle = cpu_to_le32(TAG_ENCODE(idx)); + st->timestamp = cpu_to_le32(tv.tv_sec); + + return sizeof(struct carm_msg_sync_time); +} + +static unsigned int carm_fill_alloc_buf(struct carm_host *host, + unsigned int idx, void *mem) +{ + struct carm_msg_allocbuf *ab = mem; + + memset(ab, 0, sizeof(*ab)); + ab->type = CARM_MSG_MISC; + ab->subtype = MISC_ALLOC_MEM; + ab->handle = cpu_to_le32(TAG_ENCODE(idx)); + ab->n_sg = 1; + ab->sg_type = SGT_32BIT; + ab->addr = cpu_to_le32(host->shm_dma + (PDC_SHM_SIZE >> 1)); + ab->len = cpu_to_le32(PDC_SHM_SIZE >> 1); + ab->evt_pool = cpu_to_le32(host->shm_dma + (16 * 1024)); + ab->n_evt = cpu_to_le32(1024); + ab->rbuf_pool = cpu_to_le32(host->shm_dma); + ab->n_rbuf = cpu_to_le32(RMSG_Q_LEN); + ab->msg_pool = cpu_to_le32(host->shm_dma + RBUF_LEN); + ab->n_msg = cpu_to_le32(CARM_Q_LEN); + ab->sg[0].start = cpu_to_le32(host->shm_dma + (PDC_SHM_SIZE >> 1)); + ab->sg[0].len = cpu_to_le32(65536); + + return sizeof(struct carm_msg_allocbuf); +} + +static unsigned int carm_fill_scan_channels(struct carm_host *host, + unsigned int idx, void *mem) +{ + struct carm_msg_ioctl *ioc = mem; + u32 msg_data = (u32) (carm_ref_msg_dma(host, idx) + + IOC_SCAN_CHAN_OFFSET); + + memset(ioc, 0, sizeof(*ioc)); + ioc->type = CARM_MSG_IOCTL; + ioc->subtype = CARM_IOC_SCAN_CHAN; + ioc->handle = cpu_to_le32(TAG_ENCODE(idx)); + ioc->data_addr = cpu_to_le32(msg_data); + + /* fill output data area with "no device" default values */ + mem += IOC_SCAN_CHAN_OFFSET; + memset(mem, IOC_SCAN_CHAN_NODEV, CARM_MAX_PORTS); + + return IOC_SCAN_CHAN_OFFSET + CARM_MAX_PORTS; +} + +static unsigned int carm_fill_get_fw_ver(struct carm_host *host, + unsigned int idx, void *mem) +{ + struct carm_msg_get_fw_ver *ioc = mem; + u32 msg_data = (u32) (carm_ref_msg_dma(host, idx) + sizeof(*ioc)); + + memset(ioc, 0, sizeof(*ioc)); + ioc->type = CARM_MSG_MISC; + ioc->subtype = MISC_GET_FW_VER; + ioc->handle = cpu_to_le32(TAG_ENCODE(idx)); + ioc->data_addr = cpu_to_le32(msg_data); + + return sizeof(struct carm_msg_get_fw_ver) + + sizeof(struct carm_fw_ver); +} + +static inline void carm_end_request_queued(struct carm_host *host, + struct carm_request *crq, + int uptodate) +{ + struct request *req = crq->rq; + int rc; + + rc = end_that_request_first(req, uptodate, req->hard_nr_sectors); + assert(rc == 0); + + end_that_request_last(req); + + rc = carm_put_request(host, crq); + assert(rc == 0); +} + +static inline void carm_push_q (struct carm_host *host, request_queue_t *q) +{ + unsigned int idx = host->wait_q_prod % CARM_MAX_WAIT_Q; + + blk_stop_queue(q); + VPRINTK("STOPPED QUEUE %p\n", q); + + host->wait_q[idx] = q; + host->wait_q_prod++; + BUG_ON(host->wait_q_prod == host->wait_q_cons); /* overrun */ +} + +static inline request_queue_t *carm_pop_q(struct carm_host *host) +{ + unsigned int idx; + + if (host->wait_q_prod == host->wait_q_cons) + return NULL; + + idx = host->wait_q_cons % CARM_MAX_WAIT_Q; + host->wait_q_cons++; + + return host->wait_q[idx]; +} + +static inline void carm_round_robin(struct carm_host *host) +{ + request_queue_t *q = carm_pop_q(host); + if (q) { + blk_start_queue(q); + VPRINTK("STARTED QUEUE %p\n", q); + } +} + +static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq, + int is_ok) +{ + carm_end_request_queued(host, crq, is_ok); + if (CARM_MAX_Q == 1) + carm_round_robin(host); + else if ((host->n_msgs <= CARM_MSG_LOW_WATER) && + (host->hw_sg_used <= CARM_SG_LOW_WATER)) { + carm_round_robin(host); + } +} + +static void carm_oob_rq_fn(request_queue_t *q) +{ + struct carm_host *host = q->queuedata; + struct carm_request *crq; + struct request *rq; + int rc; + + while (1) { + DPRINTK("get req\n"); + rq = elv_next_request(q); + if (!rq) + break; + + blkdev_dequeue_request(rq); + + crq = rq->special; + assert(crq != NULL); + assert(crq->rq == rq); + + crq->n_elem = 0; + + DPRINTK("send req\n"); + rc = carm_send_msg(host, crq); + if (rc) { + blk_requeue_request(q, rq); + carm_push_q(host, q); + return; /* call us again later, eventually */ + } + } +} + +static void carm_rq_fn(request_queue_t *q) +{ + struct carm_port *port = q->queuedata; + struct carm_host *host = port->host; + struct carm_msg_rw *msg; + struct carm_request *crq; + struct request *rq; + struct scatterlist *sg; + int writing = 0, pci_dir, i, n_elem, rc; + u32 tmp; + unsigned int msg_size; + +queue_one_request: + VPRINTK("get req\n"); + rq = elv_next_request(q); + if (!rq) + return; + + crq = carm_get_request(host); + if (!crq) { + carm_push_q(host, q); + return; /* call us again later, eventually */ + } + crq->rq = rq; + + blkdev_dequeue_request(rq); + + if (rq_data_dir(rq) == WRITE) { + writing = 1; + pci_dir = PCI_DMA_TODEVICE; + } else { + pci_dir = PCI_DMA_FROMDEVICE; + } + + /* get scatterlist from block layer */ + sg = &crq->sg[0]; + n_elem = blk_rq_map_sg(q, rq, sg); + if (n_elem <= 0) { + carm_end_rq(host, crq, 0); + return; /* request with no s/g entries? */ + } + + /* map scatterlist to PCI bus addresses */ + n_elem = pci_map_sg(host->pdev, sg, n_elem, pci_dir); + if (n_elem <= 0) { + carm_end_rq(host, crq, 0); + return; /* request with no s/g entries? */ + } + crq->n_elem = n_elem; + crq->port = port; + host->hw_sg_used += n_elem; + + /* + * build read/write message + */ + + VPRINTK("build msg\n"); + msg = (struct carm_msg_rw *) carm_ref_msg(host, crq->tag); + + if (writing) { + msg->type = CARM_MSG_WRITE; + crq->msg_type = CARM_MSG_WRITE; + } else { + msg->type = CARM_MSG_READ; + crq->msg_type = CARM_MSG_READ; + } + + msg->id = port->port_no; + msg->sg_count = n_elem; + msg->sg_type = SGT_32BIT; + msg->handle = cpu_to_le32(TAG_ENCODE(crq->tag)); + msg->lba = cpu_to_le32(rq->sector & 0xffffffff); + tmp = (rq->sector >> 16) >> 16; + msg->lba_high = cpu_to_le16( (u16) tmp ); + msg->lba_count = cpu_to_le16(rq->nr_sectors); + + msg_size = sizeof(struct carm_msg_rw) - sizeof(msg->sg); + for (i = 0; i < n_elem; i++) { + struct carm_msg_sg *carm_sg = &msg->sg[i]; + carm_sg->start = cpu_to_le32(sg_dma_address(&crq->sg[i])); + carm_sg->len = cpu_to_le32(sg_dma_len(&crq->sg[i])); + msg_size += sizeof(struct carm_msg_sg); + } + + rc = carm_lookup_bucket(msg_size); + BUG_ON(rc < 0); + crq->msg_bucket = (u32) rc; + + /* + * queue read/write message to hardware + */ + + VPRINTK("send msg, tag == %u\n", crq->tag); + rc = carm_send_msg(host, crq); + if (rc) { + carm_put_request(host, crq); + blk_requeue_request(q, rq); + carm_push_q(host, q); + return; /* call us again later, eventually */ + } + + goto queue_one_request; +} + +static void carm_handle_array_info(struct carm_host *host, + struct carm_request *crq, u8 *mem, + int is_ok) +{ + struct carm_port *port; + u8 *msg_data = mem + sizeof(struct carm_array_info); + struct carm_array_info *desc = (struct carm_array_info *) msg_data; + u64 lo, hi; + int cur_port; + size_t slen; + + DPRINTK("ENTER\n"); + + carm_end_rq(host, crq, is_ok); + + if (!is_ok) + goto out; + if (le32_to_cpu(desc->array_status) & ARRAY_NO_EXIST) + goto out; + + cur_port = host->cur_scan_dev; + + /* should never occur */ + if ((cur_port < 0) || (cur_port >= CARM_MAX_PORTS)) { + printk(KERN_ERR PFX "BUG: cur_scan_dev==%d, array_id==%d\n", + cur_port, (int) desc->array_id); + goto out; + } + + port = &host->port[cur_port]; + + lo = (u64) le32_to_cpu(desc->size); + hi = (u64) le32_to_cpu(desc->size_hi); + + port->capacity = lo | (hi << 32); + port->dev_geom_head = le16_to_cpu(desc->head); + port->dev_geom_sect = le16_to_cpu(desc->sect); + port->dev_geom_cyl = le16_to_cpu(desc->cyl); + + host->dev_active |= (1 << cur_port); + + strncpy(port->name, desc->name, sizeof(port->name)); + port->name[sizeof(port->name) - 1] = 0; + slen = strlen(port->name); + while (slen && (port->name[slen - 1] == ' ')) { + port->name[slen - 1] = 0; + slen--; + } + + printk(KERN_INFO DRV_NAME "(%s): port %u device %Lu sectors\n", + pci_name(host->pdev), port->port_no, + (unsigned long long) port->capacity); + printk(KERN_INFO DRV_NAME "(%s): port %u device \"%s\"\n", + pci_name(host->pdev), port->port_no, port->name); + +out: + assert(host->state == HST_DEV_SCAN); + schedule_work(&host->fsm_task); +} + +static void carm_handle_scan_chan(struct carm_host *host, + struct carm_request *crq, u8 *mem, + int is_ok) +{ + u8 *msg_data = mem + IOC_SCAN_CHAN_OFFSET; + unsigned int i, dev_count = 0; + int new_state = HST_DEV_SCAN_START; + + DPRINTK("ENTER\n"); + + carm_end_rq(host, crq, is_ok); + + if (!is_ok) { + new_state = HST_ERROR; + goto out; + } + + /* TODO: scan and support non-disk devices */ + for (i = 0; i < 8; i++) + if (msg_data[i] == 0) { /* direct-access device (disk) */ + host->dev_present |= (1 << i); + dev_count++; + } + + printk(KERN_INFO DRV_NAME "(%s): found %u interesting devices\n", + pci_name(host->pdev), dev_count); + +out: + assert(host->state == HST_PORT_SCAN); + host->state = new_state; + schedule_work(&host->fsm_task); +} + +static void carm_handle_generic(struct carm_host *host, + struct carm_request *crq, int is_ok, + int cur_state, int next_state) +{ + DPRINTK("ENTER\n"); + + carm_end_rq(host, crq, is_ok); + + assert(host->state == cur_state); + if (is_ok) + host->state = next_state; + else + host->state = HST_ERROR; + schedule_work(&host->fsm_task); +} + +static inline void carm_handle_rw(struct carm_host *host, + struct carm_request *crq, int is_ok) +{ + int pci_dir; + + VPRINTK("ENTER\n"); + + if (rq_data_dir(crq->rq) == WRITE) + pci_dir = PCI_DMA_TODEVICE; + else + pci_dir = PCI_DMA_FROMDEVICE; + + pci_unmap_sg(host->pdev, &crq->sg[0], crq->n_elem, pci_dir); + + carm_end_rq(host, crq, is_ok); +} + +static inline void carm_handle_resp(struct carm_host *host, + u32 ret_handle_le, u32 status) +{ + u32 handle = le32_to_cpu(ret_handle_le); + unsigned int msg_idx; + struct carm_request *crq; + int is_ok = (status == RMSG_OK); + u8 *mem; + + VPRINTK("ENTER, handle == 0x%x\n", handle); + + if (unlikely(!TAG_VALID(handle))) { + printk(KERN_ERR DRV_NAME "(%s): BUG: invalid tag 0x%x\n", + pci_name(host->pdev), handle); + return; + } + + msg_idx = TAG_DECODE(handle); + VPRINTK("tag == %u\n", msg_idx); + + crq = &host->req[msg_idx]; + + /* fast path */ + if (likely(crq->msg_type == CARM_MSG_READ || + crq->msg_type == CARM_MSG_WRITE)) { + carm_handle_rw(host, crq, is_ok); + return; + } + + mem = carm_ref_msg(host, msg_idx); + + switch (crq->msg_type) { + case CARM_MSG_IOCTL: { + switch (crq->msg_subtype) { + case CARM_IOC_SCAN_CHAN: + carm_handle_scan_chan(host, crq, mem, is_ok); + break; + default: + /* unknown / invalid response */ + goto err_out; + } + break; + } + + case CARM_MSG_MISC: { + switch (crq->msg_subtype) { + case MISC_ALLOC_MEM: + carm_handle_generic(host, crq, is_ok, + HST_ALLOC_BUF, HST_SYNC_TIME); + break; + case MISC_SET_TIME: + carm_handle_generic(host, crq, is_ok, + HST_SYNC_TIME, HST_GET_FW_VER); + break; + case MISC_GET_FW_VER: { + struct carm_fw_ver *ver = (struct carm_fw_ver *) + mem + sizeof(struct carm_msg_get_fw_ver); + if (is_ok) { + host->fw_ver = le32_to_cpu(ver->version); + host->flags |= (ver->features & FL_FW_VER_MASK); + } + carm_handle_generic(host, crq, is_ok, + HST_GET_FW_VER, HST_PORT_SCAN); + break; + } + default: + /* unknown / invalid response */ + goto err_out; + } + break; + } + + case CARM_MSG_ARRAY: { + switch (crq->msg_subtype) { + case CARM_ARRAY_INFO: + carm_handle_array_info(host, crq, mem, is_ok); + break; + default: + /* unknown / invalid response */ + goto err_out; + } + break; + } + + default: + /* unknown / invalid response */ + goto err_out; + } + + return; + +err_out: + printk(KERN_WARNING DRV_NAME "(%s): BUG: unhandled message type %d/%d\n", + pci_name(host->pdev), crq->msg_type, crq->msg_subtype); + carm_end_rq(host, crq, 0); +} + +static inline void carm_handle_responses(struct carm_host *host) +{ + void *mmio = host->mmio; + struct carm_response *resp = (struct carm_response *) host->shm; + unsigned int work = 0; + unsigned int idx = host->resp_idx % RMSG_Q_LEN; + + while (1) { + u32 status = le32_to_cpu(resp[idx].status); + + if (status == 0xffffffff) { + VPRINTK("ending response on index %u\n", idx); + writel(idx << 3, mmio + CARM_RESP_IDX); + break; + } + + /* response to a message we sent */ + else if ((status & (1 << 31)) == 0) { + VPRINTK("handling msg response on index %u\n", idx); + carm_handle_resp(host, resp[idx].ret_handle, status); + resp[idx].status = 0xffffffff; + } + + /* asynchronous events the hardware throws our way */ + else if ((status & 0xff000000) == (1 << 31)) { + u8 *evt_type_ptr = (u8 *) &resp[idx]; + u8 evt_type = *evt_type_ptr; + printk(KERN_WARNING DRV_NAME "(%s): unhandled event type %d\n", + pci_name(host->pdev), (int) evt_type); + resp[idx].status = 0xffffffff; + } + + idx = NEXT_RESP(idx); + work++; + } + + VPRINTK("EXIT, work==%u\n", work); + host->resp_idx += work; +} + +static irqreturn_t carm_interrupt(int irq, void *__host, struct pt_regs *regs) +{ + struct carm_host *host = __host; + void *mmio; + u32 mask; + int handled = 0; + unsigned long flags; + + if (!host) { + VPRINTK("no host\n"); + return IRQ_NONE; + } + + spin_lock_irqsave(&host->lock, flags); + + mmio = host->mmio; + + /* reading should also clear interrupts */ + mask = readl(mmio + CARM_INT_STAT); + + if (mask == 0 || mask == 0xffffffff) { + VPRINTK("no work, mask == 0x%x\n", mask); + goto out; + } + + if (mask & INT_ACK_MASK) + writel(mask, mmio + CARM_INT_STAT); + + if (unlikely(host->state == HST_INVALID)) { + VPRINTK("not initialized yet, mask = 0x%x\n", mask); + goto out; + } + + if (mask & CARM_HAVE_RESP) { + handled = 1; + carm_handle_responses(host); + } + +out: + spin_unlock_irqrestore(&host->lock, flags); + VPRINTK("EXIT\n"); + return IRQ_RETVAL(handled); +} + +static void carm_fsm_task (void *_data) +{ + struct carm_host *host = _data; + unsigned long flags; + unsigned int state; + int rc, i, next_dev; + int reschedule = 0; + int new_state = HST_INVALID; + + spin_lock_irqsave(&host->lock, flags); + state = host->state; + spin_unlock_irqrestore(&host->lock, flags); + + DPRINTK("ENTER, state == %s\n", state_name[state]); + + switch (state) { + case HST_PROBE_START: + new_state = HST_ALLOC_BUF; + reschedule = 1; + break; + + case HST_ALLOC_BUF: + rc = carm_send_special(host, carm_fill_alloc_buf); + if (rc) { + new_state = HST_ERROR; + reschedule = 1; + } + break; + + case HST_SYNC_TIME: + rc = carm_send_special(host, carm_fill_sync_time); + if (rc) { + new_state = HST_ERROR; + reschedule = 1; + } + break; + + case HST_GET_FW_VER: + rc = carm_send_special(host, carm_fill_get_fw_ver); + if (rc) { + new_state = HST_ERROR; + reschedule = 1; + } + break; + + case HST_PORT_SCAN: + rc = carm_send_special(host, carm_fill_scan_channels); + if (rc) { + new_state = HST_ERROR; + reschedule = 1; + } + break; + + case HST_DEV_SCAN_START: + host->cur_scan_dev = -1; + new_state = HST_DEV_SCAN; + reschedule = 1; + break; + + case HST_DEV_SCAN: + next_dev = -1; + for (i = host->cur_scan_dev + 1; i < CARM_MAX_PORTS; i++) + if (host->dev_present & (1 << i)) { + next_dev = i; + break; + } + + if (next_dev >= 0) { + host->cur_scan_dev = next_dev; + rc = carm_array_info(host, next_dev); + if (rc) { + new_state = HST_ERROR; + reschedule = 1; + } + } else { + new_state = HST_DEV_ACTIVATE; + reschedule = 1; + } + break; + + case HST_DEV_ACTIVATE: { + int activated = 0; + for (i = 0; i < CARM_MAX_PORTS; i++) + if (host->dev_active & (1 << i)) { + struct carm_port *port = &host->port[i]; + struct gendisk *disk = port->disk; + + set_capacity(disk, port->capacity); + add_disk(disk); + activated++; + } + + printk(KERN_INFO DRV_NAME "(%s): %d ports activated\n", + pci_name(host->pdev), activated); + + new_state = HST_PROBE_FINISHED; + reschedule = 1; + break; + } + + case HST_PROBE_FINISHED: + up(&host->probe_sem); + break; + + case HST_ERROR: + /* FIXME: TODO */ + break; + + default: + /* should never occur */ + printk(KERN_ERR PFX "BUG: unknown state %d\n", state); + assert(0); + break; + } + + if (new_state != HST_INVALID) { + spin_lock_irqsave(&host->lock, flags); + host->state = new_state; + spin_unlock_irqrestore(&host->lock, flags); + } + if (reschedule) + schedule_work(&host->fsm_task); +} + +static int carm_init_wait(void *mmio, u32 bits, unsigned int test_bit) +{ + unsigned int i; + + for (i = 0; i < 50000; i++) { + u32 tmp = readl(mmio + CARM_LMUC); + udelay(100); + + if (test_bit) { + if ((tmp & bits) == bits) + return 0; + } else { + if ((tmp & bits) == 0) + return 0; + } + + cond_resched(); + } + + printk(KERN_ERR PFX "carm_init_wait timeout, bits == 0x%x, test_bit == %s\n", + bits, test_bit ? "yes" : "no"); + return -EBUSY; +} + +static void carm_init_responses(struct carm_host *host) +{ + void *mmio = host->mmio; + unsigned int i; + struct carm_response *resp = (struct carm_response *) host->shm; + + for (i = 0; i < RMSG_Q_LEN; i++) + resp[i].status = 0xffffffff; + + writel(0, mmio + CARM_RESP_IDX); +} + +static int carm_init_host(struct carm_host *host) +{ + void *mmio = host->mmio; + u32 tmp; + u8 tmp8; + int rc; + + DPRINTK("ENTER\n"); + + writel(0, mmio + CARM_INT_MASK); + + tmp8 = readb(mmio + CARM_INITC); + if (tmp8 & 0x01) { + tmp8 &= ~0x01; + writeb(tmp8, CARM_INITC); + readb(mmio + CARM_INITC); /* flush */ + + DPRINTK("snooze...\n"); + msleep(5000); + } + + tmp = readl(mmio + CARM_HMUC); + if (tmp & CARM_CME) { + DPRINTK("CME bit present, waiting\n"); + rc = carm_init_wait(mmio, CARM_CME, 1); + if (rc) { + DPRINTK("EXIT, carm_init_wait 1 failed\n"); + return rc; + } + } + if (tmp & CARM_RME) { + DPRINTK("RME bit present, waiting\n"); + rc = carm_init_wait(mmio, CARM_RME, 1); + if (rc) { + DPRINTK("EXIT, carm_init_wait 2 failed\n"); + return rc; + } + } + + tmp &= ~(CARM_RME | CARM_CME); + writel(tmp, mmio + CARM_HMUC); + readl(mmio + CARM_HMUC); /* flush */ + + rc = carm_init_wait(mmio, CARM_RME | CARM_CME, 0); + if (rc) { + DPRINTK("EXIT, carm_init_wait 3 failed\n"); + return rc; + } + + carm_init_buckets(mmio); + + writel(host->shm_dma & 0xffffffff, mmio + RBUF_ADDR_LO); + writel((host->shm_dma >> 16) >> 16, mmio + RBUF_ADDR_HI); + writel(RBUF_LEN, mmio + RBUF_BYTE_SZ); + + tmp = readl(mmio + CARM_HMUC); + tmp |= (CARM_RME | CARM_CME | CARM_WZBC); + writel(tmp, mmio + CARM_HMUC); + readl(mmio + CARM_HMUC); /* flush */ + + rc = carm_init_wait(mmio, CARM_RME | CARM_CME, 1); + if (rc) { + DPRINTK("EXIT, carm_init_wait 4 failed\n"); + return rc; + } + + writel(0, mmio + CARM_HMPHA); + writel(INT_DEF_MASK, mmio + CARM_INT_MASK); + + carm_init_responses(host); + + /* start initialization, probing state machine */ + spin_lock_irq(&host->lock); + assert(host->state == HST_INVALID); + host->state = HST_PROBE_START; + spin_unlock_irq(&host->lock); + schedule_work(&host->fsm_task); + + DPRINTK("EXIT\n"); + return 0; +} + +static int carm_init_disks(struct carm_host *host) +{ + unsigned int i; + int rc = 0; + + for (i = 0; i < CARM_MAX_PORTS; i++) { + struct gendisk *disk; + request_queue_t *q; + struct carm_port *port; + + port = &host->port[i]; + port->host = host; + port->port_no = i; + + disk = alloc_disk(CARM_MINORS_PER_MAJOR); + if (!disk) { + rc = -ENOMEM; + break; + } + + port->disk = disk; + sprintf(disk->disk_name, DRV_NAME "%u_%u", host->id, i); + sprintf(disk->devfs_name, DRV_NAME "/%u_%u", host->id, i); + disk->major = host->major; + disk->first_minor = i * CARM_MINORS_PER_MAJOR; + disk->fops = &carm_bd_ops; + disk->private_data = port; + + q = blk_init_queue(carm_rq_fn, &host->lock); + if (!q) { + rc = -ENOMEM; + break; + } + disk->queue = q; + blk_queue_max_hw_segments(q, CARM_MAX_REQ_SG); + blk_queue_max_phys_segments(q, CARM_MAX_REQ_SG); + blk_queue_segment_boundary(q, CARM_SG_BOUNDARY); + + q->queuedata = port; + } + + return rc; +} + +static void carm_free_disks(struct carm_host *host) +{ + unsigned int i; + + for (i = 0; i < CARM_MAX_PORTS; i++) { + struct gendisk *disk = host->port[i].disk; + if (disk) { + request_queue_t *q = disk->queue; + + if (disk->flags & GENHD_FL_UP) + del_gendisk(disk); + if (q) + blk_cleanup_queue(q); + put_disk(disk); + } + } +} + +static int carm_init_shm(struct carm_host *host) +{ + host->shm = pci_alloc_consistent(host->pdev, CARM_SHM_SIZE, + &host->shm_dma); + if (!host->shm) + return -ENOMEM; + + host->msg_base = host->shm + RBUF_LEN; + host->msg_dma = host->shm_dma + RBUF_LEN; + + memset(host->shm, 0xff, RBUF_LEN); + memset(host->msg_base, 0, PDC_SHM_SIZE - RBUF_LEN); + + return 0; +} + +static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static unsigned int printed_version; + struct carm_host *host; + unsigned int pci_dac; + int rc; + request_queue_t *q; + unsigned int i; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + +#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */ + rc = pci_set_dma_mask(pdev, 0xffffffffffffffffULL); + if (!rc) { + rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n", + pci_name(pdev)); + goto err_out_regions; + } + pci_dac = 1; + } else { +#endif + rc = pci_set_dma_mask(pdev, 0xffffffffULL); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n", + pci_name(pdev)); + goto err_out_regions; + } + pci_dac = 0; +#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */ + } +#endif + + host = kmalloc(sizeof(*host), GFP_KERNEL); + if (!host) { + printk(KERN_ERR DRV_NAME "(%s): memory alloc failure\n", + pci_name(pdev)); + rc = -ENOMEM; + goto err_out_regions; + } + + memset(host, 0, sizeof(*host)); + host->pdev = pdev; + host->flags = pci_dac ? FL_DAC : 0; + spin_lock_init(&host->lock); + INIT_WORK(&host->fsm_task, carm_fsm_task, host); + init_MUTEX_LOCKED(&host->probe_sem); + + for (i = 0; i < ARRAY_SIZE(host->req); i++) + host->req[i].tag = i; + + host->mmio = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!host->mmio) { + printk(KERN_ERR DRV_NAME "(%s): MMIO alloc failure\n", + pci_name(pdev)); + rc = -ENOMEM; + goto err_out_kfree; + } + + rc = carm_init_shm(host); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): DMA SHM alloc failure\n", + pci_name(pdev)); + goto err_out_iounmap; + } + + q = blk_init_queue(carm_oob_rq_fn, &host->lock); + if (!q) { + printk(KERN_ERR DRV_NAME "(%s): OOB queue alloc failure\n", + pci_name(pdev)); + rc = -ENOMEM; + goto err_out_pci_free; + } + host->oob_q = q; + q->queuedata = host; + + /* + * Figure out which major to use: 160, 161, or dynamic + */ + if (!test_and_set_bit(0, &carm_major_alloc)) + host->major = 160; + else if (!test_and_set_bit(1, &carm_major_alloc)) + host->major = 161; + else + host->flags |= FL_DYN_MAJOR; + + host->id = carm_host_id; + sprintf(host->name, DRV_NAME "%d", carm_host_id); + + rc = register_blkdev(host->major, host->name); + if (rc < 0) + goto err_out_free_majors; + if (host->flags & FL_DYN_MAJOR) + host->major = rc; + + devfs_mk_dir(DRV_NAME); + + rc = carm_init_disks(host); + if (rc) + goto err_out_blkdev_disks; + + pci_set_master(pdev); + + rc = request_irq(pdev->irq, carm_interrupt, SA_SHIRQ, DRV_NAME, host); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): irq alloc failure\n", + pci_name(pdev)); + goto err_out_blkdev_disks; + } + + rc = carm_init_host(host); + if (rc) + goto err_out_free_irq; + + DPRINTK("waiting for probe_sem\n"); + down(&host->probe_sem); + + printk(KERN_INFO "%s: pci %s, ports %d, io %lx, irq %u, major %d\n", + host->name, pci_name(pdev), (int) CARM_MAX_PORTS, + pci_resource_start(pdev, 0), pdev->irq, host->major); + + carm_host_id++; + pci_set_drvdata(pdev, host); + return 0; + +err_out_free_irq: + free_irq(pdev->irq, host); +err_out_blkdev_disks: + carm_free_disks(host); + unregister_blkdev(host->major, host->name); +err_out_free_majors: + if (host->major == 160) + clear_bit(0, &carm_major_alloc); + else if (host->major == 161) + clear_bit(1, &carm_major_alloc); + blk_cleanup_queue(host->oob_q); +err_out_pci_free: + pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma); +err_out_iounmap: + iounmap(host->mmio); +err_out_kfree: + kfree(host); +err_out_regions: + pci_release_regions(pdev); +err_out: + pci_disable_device(pdev); + return rc; +} + +static void carm_remove_one (struct pci_dev *pdev) +{ + struct carm_host *host = pci_get_drvdata(pdev); + + if (!host) { + printk(KERN_ERR PFX "BUG: no host data for PCI(%s)\n", + pci_name(pdev)); + return; + } + + free_irq(pdev->irq, host); + carm_free_disks(host); + devfs_remove(DRV_NAME); + unregister_blkdev(host->major, host->name); + if (host->major == 160) + clear_bit(0, &carm_major_alloc); + else if (host->major == 161) + clear_bit(1, &carm_major_alloc); + blk_cleanup_queue(host->oob_q); + pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma); + iounmap(host->mmio); + kfree(host); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +static int __init carm_init(void) +{ + return pci_module_init(&carm_driver); +} + +static void __exit carm_exit(void) +{ + pci_unregister_driver(&carm_driver); +} + +module_init(carm_init); +module_exit(carm_exit); + + -- cgit v1.2.3 -- cgit v1.2.3 From 1becc720dca95f370fc163d14b445001964ff751 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 21 Jun 2004 15:47:16 -0400 Subject: [PATCH] 2.6.7-mm1: drivers/scsi/hosts.h -> scsi/scsi_host.h On Sun, Jun 20, 2004 at 05:46:32PM -0700, Andrew Morton wrote: >... > All 226 patches: >... > bk-libata.patch >... drivers/scsi/hosts.h is obsolete, use scsi/scsi_host.h. Please apply Adrian --- drivers/scsi/sata_nv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index e6a7bb0c444f..f90821e67cac 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -31,7 +31,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #include #define DRV_NAME "sata_nv" -- cgit v1.2.3 From 217a7b206acd141ad300694d5719ea12258d725d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 21 Jun 2004 17:01:24 -0300 Subject: [NET] generalise tcp_error, renaming it to sk_stream_error Signed-off-by: Arnaldo Carvalho de Melo --- include/net/sock.h | 1 + net/core/stream.c | 11 +++++++++++ net/ipv4/tcp.c | 13 ++----------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 60f8c869b5bd..c87a90d7ca25 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -473,6 +473,7 @@ do { if (!(__sk)->sk_backlog.tail) { \ extern int sk_stream_wait_connect(struct sock *sk, long *timeo_p); extern int sk_stream_wait_memory(struct sock *sk, long *timeo_p); extern void sk_stream_wait_close(struct sock *sk, long timeo_p); +extern int sk_stream_error(struct sock *sk, int flags, int err); extern int sk_wait_data(struct sock *sk, long *timeo); diff --git a/net/core/stream.c b/net/core/stream.c index d5357897830a..d00c8d90565f 100644 --- a/net/core/stream.c +++ b/net/core/stream.c @@ -177,3 +177,14 @@ void sk_stream_rfree(struct sk_buff *skb) } EXPORT_SYMBOL(sk_stream_rfree); + +int sk_stream_error(struct sock *sk, int flags, int err) +{ + if (err == -EPIPE) + err = sock_error(sk) ? : -EPIPE; + if (err == -EPIPE && !(flags & MSG_NOSIGNAL)) + send_sig(SIGPIPE, current, 0); + return err; +} + +EXPORT_SYMBOL(sk_stream_error); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 77525aa5274e..00743ca43f4d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -688,15 +688,6 @@ static inline void tcp_push(struct sock *sk, struct tcp_opt *tp, int flags, } } -static int tcp_error(struct sock *sk, int flags, int err) -{ - if (err == -EPIPE) - err = sock_error(sk) ? : -EPIPE; - if (err == -EPIPE && !(flags & MSG_NOSIGNAL)) - send_sig(SIGPIPE, current, 0); - return err; -} - static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags) { @@ -800,7 +791,7 @@ do_error: if (copied) goto out; out_err: - return tcp_error(sk, flags, err); + return sk_stream_error(sk, flags, err); } ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset, @@ -1054,7 +1045,7 @@ do_error: if (copied) goto out; out_err: - err = tcp_error(sk, flags, err); + err = sk_stream_error(sk, flags, err); TCP_CHECK_TIMER(sk); release_sock(sk); return err; -- cgit v1.2.3 From 3cc46e229ede119567d731f27df6dbdfea931c41 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 21 Jun 2004 16:36:09 -0400 Subject: [libata] move some code around Split ata_eng_timeout into the main part (ata_qc_timeout) and the part called by the SCSI layer (ata_eng_timeout). Zero behavior changes. --- drivers/scsi/libata-core.c | 54 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index e0f59b47cc71..96f239bf22fb 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2123,8 +2123,8 @@ static void ata_pio_task(void *_data) } /** - * ata_eng_timeout - Handle timeout of queued command - * @ap: Port on which timed-out command is active + * ata_qc_timeout - Handle timeout of queued command + * @qc: Command that timed out * * Some part of the kernel (currently, only the SCSI layer) * has noticed that the active command on port @ap has not @@ -2138,23 +2138,14 @@ static void ata_pio_task(void *_data) * transaction completed successfully. * * LOCKING: - * Inherited from SCSI layer (none, can sleep) */ -void ata_eng_timeout(struct ata_port *ap) +static void ata_qc_timeout(struct ata_queued_cmd *qc) { u8 host_stat = 0, drv_stat; - struct ata_queued_cmd *qc; DPRINTK("ENTER\n"); - qc = ata_qc_from_tag(ap, ap->active_tag); - if (!qc) { - printk(KERN_ERR "ata%u: BUG: timeout without command\n", - ap->id); - goto out; - } - /* hack alert! We cannot use the supplied completion * function from inside the ->eh_strategy_handler() thread. * libata is the only user of ->eh_strategy_handler() in @@ -2194,6 +2185,45 @@ out: DPRINTK("EXIT\n"); } +/** + * ata_eng_timeout - Handle timeout of queued command + * @ap: Port on which timed-out command is active + * + * Some part of the kernel (currently, only the SCSI layer) + * has noticed that the active command on port @ap has not + * completed after a specified length of time. Handle this + * condition by disabling DMA (if necessary) and completing + * transactions, with error if necessary. + * + * This also handles the case of the "lost interrupt", where + * for some reason (possibly hardware bug, possibly driver bug) + * an interrupt was not delivered to the driver, even though the + * transaction completed successfully. + * + * LOCKING: + * Inherited from SCSI layer (none, can sleep) + */ + +void ata_eng_timeout(struct ata_port *ap) +{ + u8 host_stat = 0, drv_stat; + struct ata_queued_cmd *qc; + + DPRINTK("ENTER\n"); + + qc = ata_qc_from_tag(ap, ap->active_tag); + if (!qc) { + printk(KERN_ERR "ata%u: BUG: timeout without command\n", + ap->id); + goto out; + } + + ata_qc_timeout(qc); + +out: + DPRINTK("EXIT\n"); +} + /** * ata_qc_new - Request an available ATA command, for queueing * @ap: Port associated with device @dev -- cgit v1.2.3 From ec8a1e9ac422cfed05a2647804cf90f497f1033e Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 21 Jun 2004 16:54:50 -0400 Subject: [libata] fix build error, minor cleanups --- drivers/scsi/libata-core.c | 5 ++--- include/linux/libata.h | 5 ----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 96f239bf22fb..d1fadbc4ba78 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2142,6 +2142,7 @@ static void ata_pio_task(void *_data) static void ata_qc_timeout(struct ata_queued_cmd *qc) { + struct ata_port *ap = qc->ap; u8 host_stat = 0, drv_stat; DPRINTK("ENTER\n"); @@ -2181,7 +2182,6 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) break; } -out: DPRINTK("EXIT\n"); } @@ -2206,7 +2206,6 @@ out: void ata_eng_timeout(struct ata_port *ap) { - u8 host_stat = 0, drv_stat; struct ata_queued_cmd *qc; DPRINTK("ENTER\n"); @@ -2317,7 +2316,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) qc->scsidone(cmd); } - qc->flags &= ~ATA_QCFLAG_ACTIVE; + qc->flags = 0; tag = qc->tag; if (likely(ata_tag_valid(tag))) { if (tag == ap->active_tag) diff --git a/include/linux/libata.h b/include/linux/libata.h index a5cbca376a92..787f3583729a 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -137,11 +137,6 @@ enum { PORT_UNKNOWN = 0, PORT_ENABLED = 1, PORT_DISABLED = 2, - - /* ata_qc_cb_t flags - note uses above ATA_QCFLAG_xxx namespace, - * but not numberspace - */ - ATA_QCFLAG_TIMEOUT = (1 << 0), }; enum pio_task_states { -- cgit v1.2.3 From dd87b025bb0e23ca603b5603f9b93c74ac8ceb65 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 21 Jun 2004 18:46:47 -0300 Subject: [NET] generalise tcp_free_skb, renaming it to sk_stream_free_skb Will be used by the poor cousins Signed-of-by: Arnaldo Carvalho de Melo --- include/linux/tcp.h | 2 +- include/net/sock.h | 11 +++++++++++ include/net/tcp.h | 10 +--------- net/ipv4/tcp.c | 2 +- net/ipv4/tcp_input.c | 10 ++++------ net/ipv4/tcp_output.c | 4 ++-- 6 files changed, 20 insertions(+), 19 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index f807f0507815..17b7902ff760 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -262,8 +262,8 @@ struct tcp_opt { __u32 frto_highmark; /* snd_nxt when RTO occurred */ __u8 unused_pad; - __u8 queue_shrunk; /* Write queue has been shrunk recently.*/ __u8 defer_accept; /* User waits for some data after accept() */ + /* one byte hole, try to pack */ /* RTT measurement */ __u8 backoff; /* backoff */ diff --git a/include/net/sock.h b/include/net/sock.h index c87a90d7ca25..16011c87f20b 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -168,6 +168,7 @@ struct sock_common { * @sk_user_data - RPC layer private data * @sk_owner - module that owns this socket * @sk_write_pending - a write to stream socket waits to start + * @sk_queue_shrunk - write queue has been shrunk recently * @sk_state_change - callback to indicate change in the state of the sock * @sk_data_ready - callback to indicate there is data to be processed * @sk_write_space - callback to indicate there is bf sending space available @@ -250,6 +251,8 @@ struct sock { struct module *sk_owner; int sk_write_pending; void *sk_security; + __u8 sk_queue_shrunk; + /* three bytes hole, try to pack */ void (*sk_state_change)(struct sock *sk); void (*sk_data_ready)(struct sock *sk, int bytes); void (*sk_write_space)(struct sock *sk); @@ -446,6 +449,14 @@ static inline void sk_stream_set_owner_r(struct sk_buff *skb, struct sock *sk) sk->sk_forward_alloc -= skb->truesize; } +static inline void sk_stream_free_skb(struct sock *sk, struct sk_buff *skb) +{ + sk->sk_queue_shrunk = 1; + sk->sk_wmem_queued -= skb->truesize; + sk->sk_forward_alloc += skb->truesize; + __kfree_skb(skb); +} + /* The per-socket spinlock must be held here. */ #define sk_add_backlog(__sk, __skb) \ do { if (!(__sk)->sk_backlog.tail) { \ diff --git a/include/net/tcp.h b/include/net/tcp.h index aaef4bf548be..5ce69af04dd4 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1876,14 +1876,6 @@ static __inline__ void tcp_openreq_init(struct open_request *req, #define TCP_MEM_QUANTUM ((int)PAGE_SIZE) -static inline void tcp_free_skb(struct sock *sk, struct sk_buff *skb) -{ - tcp_sk(sk)->queue_shrunk = 1; - sk->sk_wmem_queued -= skb->truesize; - sk->sk_forward_alloc += skb->truesize; - __kfree_skb(skb); -} - extern void __tcp_mem_reclaim(struct sock *sk); extern int tcp_mem_schedule(struct sock *sk, int size, int kind); @@ -1951,7 +1943,7 @@ static inline void tcp_writequeue_purge(struct sock *sk) struct sk_buff *skb; while ((skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) - tcp_free_skb(sk, skb); + sk_stream_free_skb(sk, skb); tcp_mem_reclaim(sk); } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 00743ca43f4d..71404e1a9e63 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1038,7 +1038,7 @@ do_fault: if (tp->send_head == skb) tp->send_head = NULL; __skb_unlink(skb, skb->list); - tcp_free_skb(sk, skb); + sk_stream_free_skb(sk, skb); } do_error: diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index d0ad5def4629..40f31f3b569c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2368,7 +2368,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) tp->fackets_out--; tp->packets_out--; __skb_unlink(skb, skb->list); - tcp_free_skb(sk, skb); + sk_stream_free_skb(sk, skb); } if (acked&FLAG_ACKED) { @@ -3829,7 +3829,7 @@ void tcp_cwnd_application_limited(struct sock *sk) /* When incoming ACK allowed to free some skb from write_queue, - * we remember this event in flag tp->queue_shrunk and wake up socket + * we remember this event in flag sk->sk_queue_shrunk and wake up socket * on the exit from tcp input handler. * * PROBLEM: sndbuf expansion does not work well with largesend. @@ -3857,10 +3857,8 @@ static void tcp_new_space(struct sock *sk) static inline void tcp_check_space(struct sock *sk) { - struct tcp_opt *tp = tcp_sk(sk); - - if (tp->queue_shrunk) { - tp->queue_shrunk = 0; + if (sk->sk_queue_shrunk) { + sk->sk_queue_shrunk = 0; if (sk->sk_socket && test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) tcp_new_space(sk); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index ad0c2ac89a1a..20dd3b7e3ec5 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -763,7 +763,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m */ if (tp->fackets_out) tp->fackets_out--; - tcp_free_skb(sk, next_skb); + sk_stream_free_skb(sk, next_skb); tp->packets_out--; } } @@ -1104,7 +1104,7 @@ int tcp_send_synack(struct sock *sk) return -ENOMEM; __skb_unlink(skb, &sk->sk_write_queue); __skb_queue_head(&sk->sk_write_queue, nskb); - tcp_free_skb(sk, skb); + sk_stream_free_skb(sk, skb); sk_charge_skb(sk, nskb); skb = nskb; } -- cgit v1.2.3 From 82c687e48d73b7a13aaccc22924f6466245721da Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 21 Jun 2004 18:12:28 -0400 Subject: [libata ata_piix] combined mode bug fix; improved ICH6 support --- drivers/scsi/ata_piix.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index e02e33c17404..ff2e7385f59a 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -57,6 +57,7 @@ enum { ich5_pata = 0, ich5_sata = 1, piix4_pata = 2, + ich6_sata = 3, }; static int piix_init_one (struct pci_dev *pdev, @@ -91,10 +92,8 @@ static struct pci_device_id piix_pci_tbl[] = { * and enhanced mode, with queueing and other fancy stuff. * This is distinguished by PCI class code. */ - { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_STORAGE_IDE << 8, 0xffff00, ich5_sata }, - { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_STORAGE_IDE << 8, 0xffff00, ich5_sata }, + { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, + { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, { } /* terminate list */ }; @@ -199,6 +198,17 @@ static struct ata_port_info piix_port_info[] = { .udma_mask = ATA_UDMA_MASK_40C, /* FIXME: cbl det */ .port_ops = &piix_pata_ops, }, + + /* ich6_sata */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | + PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR | + ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x03, /* pio3-4 */ + .udma_mask = 0x7f, /* udma0-6 ; FIXME */ + .port_ops = &piix_sata_ops, + }, }; static struct pci_bits piix_enable_bits[] = { @@ -327,13 +337,6 @@ static int piix_sata_probe (struct ata_port *ap) static void piix_sata_phy_reset(struct ata_port *ap) { - if (!pci_test_config_bits(ap->host_set->pdev, - &piix_enable_bits[ap->port_no])) { - ata_port_disable(ap); - printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); - return; - } - if (!piix_sata_probe(ap)) { ata_port_disable(ap); printk(KERN_INFO "ata%u: SATA port has no device.\n", ap->id); -- cgit v1.2.3 From 6511d74e8502c38b02bbbdaa38004fa53d2745e8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 21 Jun 2004 19:20:08 -0300 Subject: [NET] generalise tcp_moderate_sndbuf Renaming it to sk_stream_moderate_sndbuf, further patches will move all the tcp memory pressure handling support into net/core/stream.c to make them usable by the poor cousins, starting with LLC. Signed-off-by: Arnaldo Carvalho de Melo --- include/net/sock.h | 8 ++++++++ include/net/tcp.h | 12 ++---------- net/ipv4/tcp.c | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 16011c87f20b..f34406db9442 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1095,6 +1095,14 @@ static inline void sk_wake_async(struct sock *sk, int how, int band) #define SOCK_MIN_SNDBUF 2048 #define SOCK_MIN_RCVBUF 256 +static inline void sk_stream_moderate_sndbuf(struct sock *sk) +{ + if (!(sk->sk_userlocks & SOCK_SNDBUF_LOCK)) { + sk->sk_sndbuf = min(sk->sk_sndbuf, sk->sk_wmem_queued / 2); + sk->sk_sndbuf = max(sk->sk_sndbuf, SOCK_MIN_SNDBUF); + } +} + /* * Default write policy as shown to user space via poll/select/SIGIO */ diff --git a/include/net/tcp.h b/include/net/tcp.h index 5ce69af04dd4..904f0cd12da9 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1893,14 +1893,6 @@ static inline void tcp_enter_memory_pressure(void) } } -static inline void tcp_moderate_sndbuf(struct sock *sk) -{ - if (!(sk->sk_userlocks & SOCK_SNDBUF_LOCK)) { - sk->sk_sndbuf = min(sk->sk_sndbuf, sk->sk_wmem_queued / 2); - sk->sk_sndbuf = max(sk->sk_sndbuf, SOCK_MIN_SNDBUF); - } -} - static inline struct sk_buff *tcp_alloc_pskb(struct sock *sk, int size, int mem, int gfp) { struct sk_buff *skb = alloc_skb(size+MAX_TCP_HEADER, gfp); @@ -1915,7 +1907,7 @@ static inline struct sk_buff *tcp_alloc_pskb(struct sock *sk, int size, int mem, __kfree_skb(skb); } else { tcp_enter_memory_pressure(); - tcp_moderate_sndbuf(sk); + sk_stream_moderate_sndbuf(sk); } return NULL; } @@ -1934,7 +1926,7 @@ static inline struct page * tcp_alloc_page(struct sock *sk) return page; } tcp_enter_memory_pressure(); - tcp_moderate_sndbuf(sk); + sk_stream_moderate_sndbuf(sk); return NULL; } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 71404e1a9e63..201713493659 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -333,7 +333,7 @@ int tcp_mem_schedule(struct sock *sk, int size, int kind) suppress_allocation: if (!kind) { - tcp_moderate_sndbuf(sk); + sk_stream_moderate_sndbuf(sk); /* Fail only if socket is _under_ its sndbuf. * In this case we cannot block, so that we have to fail. -- cgit v1.2.3 From a09a83869eeaed66b44bb8e82944efacd9533310 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 21 Jun 2004 21:52:32 -0300 Subject: [NET] move send_head from tcp private area to struct sock The poor cousins also need this, LLC will be the first to use it. Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/tcp.h | 1 - include/net/sock.h | 8 ++++++++ include/net/tcp.h | 17 +++++------------ net/core/sock.c | 2 ++ net/ipv4/tcp.c | 20 ++++++++++---------- net/ipv4/tcp_input.c | 25 ++++++++++++------------- net/ipv4/tcp_minisocks.c | 2 +- net/ipv4/tcp_output.c | 36 +++++++++++++++++++----------------- net/ipv4/tcp_timer.c | 4 ++-- 9 files changed, 59 insertions(+), 56 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 17b7902ff760..d95f58a553b0 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -297,7 +297,6 @@ struct tcp_opt { struct sk_buff_head out_of_order_queue; /* Out of order segments go here */ struct tcp_func *af_specific; /* Operations which are AF_INET{4,6} specific */ - struct sk_buff *send_head; /* Front of stuff to transmit */ __u32 rcv_wnd; /* Current receiver window */ __u32 rcv_wup; /* rcv_nxt on last window update sent */ diff --git a/include/net/sock.h b/include/net/sock.h index f34406db9442..0398823e18ed 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -167,6 +167,7 @@ struct sock_common { * @sk_socket - Identd and reporting IO signals * @sk_user_data - RPC layer private data * @sk_owner - module that owns this socket + * @sk_send_head - front of stuff to transmit * @sk_write_pending - a write to stream socket waits to start * @sk_queue_shrunk - write queue has been shrunk recently * @sk_state_change - callback to indicate change in the state of the sock @@ -248,6 +249,7 @@ struct sock { struct timeval sk_stamp; struct socket *sk_socket; void *sk_user_data; + struct sk_buff *sk_send_head; struct module *sk_owner; int sk_write_pending; void *sk_security; @@ -1103,6 +1105,12 @@ static inline void sk_stream_moderate_sndbuf(struct sock *sk) } } +#define sk_stream_for_retrans_queue(skb, sk) \ + for (skb = (sk)->sk_write_queue.next; \ + (skb != (sk)->sk_send_head) && \ + (skb != (struct sk_buff *)&(sk)->sk_write_queue); \ + skb = skb->next) + /* * Default write policy as shown to user space via poll/select/SIGIO */ diff --git a/include/net/tcp.h b/include/net/tcp.h index 904f0cd12da9..22a62d58c24d 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1186,13 +1186,6 @@ struct tcp_skb_cb { #define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0])) -#define for_retrans_queue(skb, sk, tp) \ - for (skb = (sk)->sk_write_queue.next; \ - (skb != (tp)->send_head) && \ - (skb != (struct sk_buff *)&(sk)->sk_write_queue); \ - skb=skb->next) - - #include /* This determines how many packets are "in the network" to the best @@ -1400,7 +1393,7 @@ tcp_nagle_check(struct tcp_opt *tp, struct sk_buff *skb, unsigned mss_now, int n tcp_minshall_check(tp)))); } -/* This checks if the data bearing packet SKB (usually tp->send_head) +/* This checks if the data bearing packet SKB (usually sk->sk_send_head) * should be put on the wire right now. */ static __inline__ int tcp_snd_test(struct tcp_opt *tp, struct sk_buff *skb, @@ -1457,7 +1450,7 @@ static __inline__ void __tcp_push_pending_frames(struct sock *sk, unsigned cur_mss, int nonagle) { - struct sk_buff *skb = tp->send_head; + struct sk_buff *skb = sk->sk_send_head; if (skb) { if (!tcp_skb_is_last(sk, skb)) @@ -1477,7 +1470,7 @@ static __inline__ void tcp_push_pending_frames(struct sock *sk, static __inline__ int tcp_may_send_now(struct sock *sk, struct tcp_opt *tp) { - struct sk_buff *skb = tp->send_head; + struct sk_buff *skb = sk->sk_send_head; return (skb && tcp_snd_test(tp, skb, tcp_current_mss(sk, 1), @@ -2023,8 +2016,8 @@ static inline int tcp_use_frto(const struct sock *sk) * unsent new data, and the advertised window should allow * sending it. */ - return (sysctl_tcp_frto && tp->send_head && - !after(TCP_SKB_CB(tp->send_head)->end_seq, + return (sysctl_tcp_frto && sk->sk_send_head && + !after(TCP_SKB_CB(sk->sk_send_head)->end_seq, tp->snd_una + tp->snd_wnd)); } diff --git a/net/core/sock.c b/net/core/sock.c index cc84b85f5b0f..992c2ab34c7a 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1147,6 +1147,8 @@ void sock_init_data(struct socket *sock, struct sock *sk) skb_queue_head_init(&sk->sk_write_queue); skb_queue_head_init(&sk->sk_error_queue); + sk->sk_send_head = NULL; + init_timer(&sk->sk_timer); sk->sk_allocation = GFP_KERNEL; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 201713493659..bc1394f67919 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -659,8 +659,8 @@ static inline void skb_entail(struct sock *sk, struct tcp_opt *tp, TCP_SKB_CB(skb)->sacked = 0; __skb_queue_tail(&sk->sk_write_queue, skb); sk_charge_skb(sk, skb); - if (!tp->send_head) - tp->send_head = skb; + if (!sk->sk_send_head) + sk->sk_send_head = skb; else if (tp->nonagle&TCP_NAGLE_PUSH) tp->nonagle &= ~TCP_NAGLE_PUSH; } @@ -678,7 +678,7 @@ static inline void tcp_mark_urg(struct tcp_opt *tp, int flags, static inline void tcp_push(struct sock *sk, struct tcp_opt *tp, int flags, int mss_now, int nonagle) { - if (tp->send_head) { + if (sk->sk_send_head) { struct sk_buff *skb = sk->sk_write_queue.prev; if (!(flags & MSG_MORE) || forced_push(tp)) tcp_mark_push(tp, skb); @@ -718,7 +718,7 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffse int offset = poffset % PAGE_SIZE; int size = min_t(size_t, psize, PAGE_SIZE - offset); - if (!tp->send_head || (copy = mss_now - skb->len) <= 0) { + if (!sk->sk_send_head || (copy = mss_now - skb->len) <= 0) { new_segment: if (!sk_stream_memory_free(sk)) goto wait_for_sndbuf; @@ -766,7 +766,7 @@ new_segment: if (forced_push(tp)) { tcp_mark_push(tp, skb); __tcp_push_pending_frames(sk, tp, mss_now, TCP_NAGLE_PUSH); - } else if (skb == tp->send_head) + } else if (skb == sk->sk_send_head) tcp_push_one(sk, mss_now); continue; @@ -880,7 +880,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, skb = sk->sk_write_queue.prev; - if (!tp->send_head || + if (!sk->sk_send_head || (copy = mss_now - skb->len) <= 0) { new_segment: @@ -1009,7 +1009,7 @@ new_segment: if (forced_push(tp)) { tcp_mark_push(tp, skb); __tcp_push_pending_frames(sk, tp, mss_now, TCP_NAGLE_PUSH); - } else if (skb == tp->send_head) + } else if (skb == sk->sk_send_head) tcp_push_one(sk, mss_now); continue; @@ -1035,8 +1035,8 @@ out: do_fault: if (!skb->len) { - if (tp->send_head == skb) - tp->send_head = NULL; + if (sk->sk_send_head == skb) + sk->sk_send_head = NULL; __skb_unlink(skb, skb->list); sk_stream_free_skb(sk, skb); } @@ -1907,7 +1907,7 @@ int tcp_disconnect(struct sock *sk, int flags) tcp_set_ca_state(tp, TCP_CA_Open); tcp_clear_retrans(tp); tcp_delack_init(tp); - tp->send_head = NULL; + sk->sk_send_head = NULL; tp->saw_tstamp = 0; tcp_sack_reset(tp); __sk_dst_reset(sk); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 40f31f3b569c..5ac9ec2ad579 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1001,7 +1001,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ if (after(end_seq, tp->high_seq)) flag |= FLAG_DATA_LOST; - for_retrans_queue(skb, sk, tp) { + sk_stream_for_retrans_queue(skb, sk) { u8 sacked = TCP_SKB_CB(skb)->sacked; int in_sack; @@ -1105,7 +1105,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ if (lost_retrans && tp->ca_state == TCP_CA_Recovery) { struct sk_buff *skb; - for_retrans_queue(skb, sk, tp) { + sk_stream_for_retrans_queue(skb, sk) { if (after(TCP_SKB_CB(skb)->seq, lost_retrans)) break; if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) @@ -1171,7 +1171,7 @@ void tcp_enter_frto(struct sock *sk) tp->undo_marker = tp->snd_una; tp->undo_retrans = 0; - for_retrans_queue(skb, sk, tp) { + sk_stream_for_retrans_queue(skb, sk) { TCP_SKB_CB(skb)->sacked &= ~TCPCB_RETRANS; } tcp_sync_left_out(tp); @@ -1194,7 +1194,7 @@ static void tcp_enter_frto_loss(struct sock *sk) tp->lost_out = 0; tp->fackets_out = 0; - for_retrans_queue(skb, sk, tp) { + sk_stream_for_retrans_queue(skb, sk) { cnt++; TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST; if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED)) { @@ -1267,7 +1267,7 @@ void tcp_enter_loss(struct sock *sk, int how) if (!how) tp->undo_marker = tp->snd_una; - for_retrans_queue(skb, sk, tp) { + sk_stream_for_retrans_queue(skb, sk) { cnt++; if (TCP_SKB_CB(skb)->sacked&TCPCB_RETRANS) tp->undo_marker = 0; @@ -1510,7 +1510,7 @@ tcp_mark_head_lost(struct sock *sk, struct tcp_opt *tp, int packets, u32 high_se BUG_TRAP(cnt <= tp->packets_out); - for_retrans_queue(skb, sk, tp) { + sk_stream_for_retrans_queue(skb, sk) { if (--cnt < 0 || after(TCP_SKB_CB(skb)->end_seq, high_seq)) break; if (!(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) { @@ -1542,7 +1542,7 @@ static void tcp_update_scoreboard(struct sock *sk, struct tcp_opt *tp) if (tcp_head_timedout(sk, tp)) { struct sk_buff *skb; - for_retrans_queue(skb, sk, tp) { + sk_stream_for_retrans_queue(skb, sk) { if (tcp_skb_timedout(tp, skb) && !(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) { TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; @@ -1711,7 +1711,7 @@ static int tcp_try_undo_loss(struct sock *sk, struct tcp_opt *tp) { if (tcp_may_undo(tp)) { struct sk_buff *skb; - for_retrans_queue(skb, sk, tp) { + sk_stream_for_retrans_queue(skb, sk) { TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST; } DBGUNDO(sk, tp, "partial loss"); @@ -2320,7 +2320,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) int acked = 0; __s32 seq_rtt = -1; - while ((skb = skb_peek(&sk->sk_write_queue)) && skb != tp->send_head) { + while ((skb = skb_peek(&sk->sk_write_queue)) && skb != sk->sk_send_head) { struct tcp_skb_cb *scb = TCP_SKB_CB(skb); __u8 sacked = scb->sacked; @@ -2408,7 +2408,7 @@ static void tcp_ack_probe(struct sock *sk) /* Was it a usable window open? */ - if (!after(TCP_SKB_CB(tp->send_head)->end_seq, + if (!after(TCP_SKB_CB(sk->sk_send_head)->end_seq, tp->snd_una + tp->snd_wnd)) { tp->backoff = 0; tcp_clear_xmit_timer(sk, TCP_TIME_PROBE0); @@ -2849,7 +2849,7 @@ no_queue: * being used to time the probes, and is probably far higher than * it needs to be for normal retransmission. */ - if (tp->send_head) + if (sk->sk_send_head) tcp_ack_probe(sk); return 1; @@ -3877,8 +3877,7 @@ static void __tcp_data_snd_check(struct sock *sk, struct sk_buff *skb) static __inline__ void tcp_data_snd_check(struct sock *sk) { - struct tcp_opt *tp = tcp_sk(sk); - struct sk_buff *skb = tp->send_head; + struct sk_buff *skb = sk->sk_send_head; if (skb != NULL) __tcp_data_snd_check(sk, skb); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 3af98bd3ff3e..dacd76e33133 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -718,6 +718,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, sock_reset_flag(newsk, SOCK_DONE); newsk->sk_userlocks = sk->sk_userlocks & ~SOCK_BINDPORT_LOCK; newsk->sk_backlog.head = newsk->sk_backlog.tail = NULL; + newsk->sk_send_head = NULL; newsk->sk_callback_lock = RW_LOCK_UNLOCKED; skb_queue_head_init(&newsk->sk_error_queue); newsk->sk_write_space = sk_stream_write_space; @@ -775,7 +776,6 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, tcp_set_ca_state(newtp, TCP_CA_Open); tcp_init_xmit_timers(newsk); skb_queue_head_init(&newtp->out_of_order_queue); - newtp->send_head = NULL; newtp->rcv_wup = req->rcv_isn + 1; newtp->write_seq = req->snt_isn + 1; newtp->pushed_seq = newtp->write_seq; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 20dd3b7e3ec5..7d6eca0cd01e 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -48,9 +48,9 @@ int sysctl_tcp_retrans_collapse = 1; static __inline__ void update_send_head(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb) { - tp->send_head = skb->next; - if (tp->send_head == (struct sk_buff *)&sk->sk_write_queue) - tp->send_head = NULL; + sk->sk_send_head = skb->next; + if (sk->sk_send_head == (struct sk_buff *)&sk->sk_write_queue) + sk->sk_send_head = NULL; tp->snd_nxt = TCP_SKB_CB(skb)->end_seq; if (tp->packets_out++ == 0) tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); @@ -329,8 +329,8 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) sk_charge_skb(sk, skb); /* Queue it, remembering where we must start sending. */ - if (tp->send_head == NULL) - tp->send_head = skb; + if (sk->sk_send_head == NULL) + sk->sk_send_head = skb; } /* Send _single_ skb sitting at the send head. This function requires @@ -339,13 +339,13 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) void tcp_push_one(struct sock *sk, unsigned cur_mss) { struct tcp_opt *tp = tcp_sk(sk); - struct sk_buff *skb = tp->send_head; + struct sk_buff *skb = sk->sk_send_head; if (tcp_snd_test(tp, skb, cur_mss, TCP_NAGLE_PUSH)) { /* Send it out now. */ TCP_SKB_CB(skb)->when = tcp_time_stamp; if (!tcp_transmit_skb(sk, skb_clone(skb, sk->sk_allocation))) { - tp->send_head = NULL; + sk->sk_send_head = NULL; tp->snd_nxt = TCP_SKB_CB(skb)->end_seq; if (tp->packets_out++ == 0) tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); @@ -572,8 +572,10 @@ int tcp_write_xmit(struct sock *sk, int nonagle) */ mss_now = tcp_current_mss(sk, 1); - while((skb = tp->send_head) && - tcp_snd_test(tp, skb, mss_now, tcp_skb_is_last(sk, skb) ? nonagle : TCP_NAGLE_PUSH)) { + while ((skb = sk->sk_send_head) && + tcp_snd_test(tp, skb, mss_now, + tcp_skb_is_last(sk, skb) ? nonagle : + TCP_NAGLE_PUSH)) { if (skb->len > mss_now) { if (tcp_fragment(sk, skb, mss_now)) break; @@ -593,7 +595,7 @@ int tcp_write_xmit(struct sock *sk, int nonagle) return 0; } - return !tp->packets_out && tp->send_head; + return !tp->packets_out && sk->sk_send_head; } return 0; } @@ -779,7 +781,7 @@ void tcp_simple_retransmit(struct sock *sk) unsigned int mss = tcp_current_mss(sk, 0); int lost = 0; - for_retrans_queue(skb, sk, tp) { + sk_stream_for_retrans_queue(skb, sk) { if (skb->len > mss && !(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED)) { if (TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_RETRANS) { @@ -865,7 +867,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) /* Collapse two adjacent packets if worthwhile and we can. */ if(!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN) && (skb->len < (cur_mss >> 1)) && - (skb->next != tp->send_head) && + (skb->next != sk->sk_send_head) && (skb->next != (struct sk_buff *)&sk->sk_write_queue) && (skb_shinfo(skb)->nr_frags == 0 && skb_shinfo(skb->next)->nr_frags == 0) && (sysctl_tcp_retrans_collapse != 0)) @@ -940,7 +942,7 @@ void tcp_xmit_retransmit_queue(struct sock *sk) /* First pass: retransmit lost packets. */ if (packet_cnt) { - for_retrans_queue(skb, sk, tp) { + sk_stream_for_retrans_queue(skb, sk) { __u8 sacked = TCP_SKB_CB(skb)->sacked; if (tcp_packets_in_flight(tp) >= tp->snd_cwnd) @@ -988,7 +990,7 @@ void tcp_xmit_retransmit_queue(struct sock *sk) packet_cnt = 0; - for_retrans_queue(skb, sk, tp) { + sk_stream_for_retrans_queue(skb, sk) { if(++packet_cnt > tp->fackets_out) break; @@ -1025,7 +1027,7 @@ void tcp_send_fin(struct sock *sk) */ mss_now = tcp_current_mss(sk, 1); - if(tp->send_head != NULL) { + if (sk->sk_send_head != NULL) { TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_FIN; TCP_SKB_CB(skb)->end_seq++; tp->write_seq++; @@ -1404,7 +1406,7 @@ int tcp_write_wakeup(struct sock *sk) struct tcp_opt *tp = tcp_sk(sk); struct sk_buff *skb; - if ((skb = tp->send_head) != NULL && + if ((skb = sk->sk_send_head) != NULL && before(TCP_SKB_CB(skb)->seq, tp->snd_una+tp->snd_wnd)) { int err; int mss = tcp_current_mss(sk, 0); @@ -1458,7 +1460,7 @@ void tcp_send_probe0(struct sock *sk) err = tcp_write_wakeup(sk); - if (tp->packets_out || !tp->send_head) { + if (tp->packets_out || !sk->sk_send_head) { /* Cancel probe timer, if it is not required. */ tp->probes_out = 0; tp->backoff = 0; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index cab2678b1958..44615198e6a1 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -269,7 +269,7 @@ static void tcp_probe_timer(struct sock *sk) struct tcp_opt *tp = tcp_sk(sk); int max_probes; - if (tp->packets_out || !tp->send_head) { + if (tp->packets_out || !sk->sk_send_head) { tp->probes_out = 0; return; } @@ -606,7 +606,7 @@ static void tcp_keepalive_timer (unsigned long data) elapsed = keepalive_time_when(tp); /* It is alive without keepalive 8) */ - if (tp->packets_out || tp->send_head) + if (tp->packets_out || sk->sk_send_head) goto resched; elapsed = tcp_time_stamp - tp->rcv_tstamp; -- cgit v1.2.3 From 55449851ae1081fbe3acc8377a2e3935bc87514c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 21 Jun 2004 18:27:10 -0700 Subject: [PATCH] Fix sparse warning in fs/devfs/base.c From: Mika Kukkonen Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- fs/devfs/base.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/devfs/base.c b/fs/devfs/base.c index 5e66bc917c28..deab8f23ffa1 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -2490,7 +2490,8 @@ static int devfs_mknod(struct inode *dir, struct dentry *dentry, int mode, return 0; } /* End Function devfs_mknod */ -static int devfs_readlink(struct dentry *dentry, char *buffer, int buflen) +static int devfs_readlink(struct dentry *dentry, char __user *buffer, + int buflen) { int err; struct devfs_entry *de; -- cgit v1.2.3 From 321bb47212d8d213f1c70c84154ca291a2323189 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 21 Jun 2004 18:27:21 -0700 Subject: [PATCH] Fix sparse warning in fs/proc/base.c From: Mika Kukkonen Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- fs/proc/base.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 5d62232721e6..9e3a70ea23f9 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1463,7 +1463,8 @@ static struct inode_operations proc_tid_attr_inode_operations = { /* * /proc/self: */ -static int proc_self_readlink(struct dentry *dentry, char *buffer, int buflen) +static int proc_self_readlink(struct dentry *dentry, char __user *buffer, + int buflen) { char tmp[30]; sprintf(tmp, "%d", current->tgid); @@ -1747,7 +1748,9 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) ino_t ino = fake_ino(tgid,PROC_TGID_INO); unsigned long j = PROC_NUMBUF; - do buf[--j] = '0' + (tgid % 10); while (tgid/=10); + do + buf[--j] = '0' + (tgid % 10); + while ((tgid /= 10) != 0); if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino, DT_DIR) < 0) { filp->f_version = tgid; @@ -1799,7 +1802,7 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi do buf[--j] = '0' + (tid % 10); - while (tid /= 10); + while ((tid /= 10) != 0); if (filldir(dirent, buf+j, PROC_NUMBUF-j, pos, ino, DT_DIR) < 0) break; -- cgit v1.2.3 From 1f3a6f5f8ac0d1a02936f249a11869a25a0926f4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 21 Jun 2004 18:27:32 -0700 Subject: [PATCH] Fix sparse warning in drivers/block/ll_rw_blk.c From: Mika Kukkonen Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- drivers/block/ll_rw_blk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 6203e02ad5c2..1ee5ab64f11f 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -2667,7 +2667,7 @@ static int __end_that_request_first(struct request *req, int uptodate, } total_bytes = bio_nbytes = 0; - while ((bio = req->bio)) { + while ((bio = req->bio) != NULL) { int nbytes; if (nr_bytes >= bio->bi_size) { -- cgit v1.2.3 From be62805e16ca01f418ff940e3f886d441a0da9fe Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 21 Jun 2004 18:27:43 -0700 Subject: [PATCH] sparse: make sys_quotactl() prototype match function Al missed this one in his sparse fixes Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- include/linux/syscalls.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index ef193874f81a..fadfc6d7a87e 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -382,7 +382,7 @@ asmlinkage long sys_fchdir(unsigned int fd); asmlinkage long sys_rmdir(const char __user *pathname); asmlinkage long sys_lookup_dcookie(u64 cookie64, char __user *buf, size_t len); asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, - qid_t id, caddr_t addr); + qid_t id, void __user *addr); asmlinkage long sys_getdents(unsigned int fd, struct linux_dirent __user *dirent, unsigned int count); -- cgit v1.2.3 From 6b6f1ba5ddf894956b874bbcfe96ff1bb2742840 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 21 Jun 2004 19:20:30 -0700 Subject: [PATCH] USB: sparse fixups for devio.c --- drivers/usb/core/devio.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 3b7f089002e9..6f61c8fb58a2 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -290,8 +290,11 @@ static void destroy_async (struct dev_state *ps, struct list_head *list) spin_lock_irqsave(&ps->lock, flags); } spin_unlock_irqrestore(&ps->lock, flags); - while ((as = async_getcompleted(ps))) + as = async_getcompleted(ps); + while (as) { free_async(as); + as = async_getcompleted(ps); + } } static void destroy_async_on_interface (struct dev_state *ps, unsigned int ifnum) @@ -968,29 +971,27 @@ static int proc_unlinkurb(struct dev_state *ps, void __user *arg) static int processcompl(struct async *as) { struct urb *urb = as->urb; + struct usbdevfs_urb __user *userurb = as->userurb; unsigned int i; if (as->userbuffer) if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) return -EFAULT; - if (put_user(urb->status, - &((struct usbdevfs_urb *)as->userurb)->status)) + if (put_user(urb->status, &userurb->status)) return -EFAULT; - if (put_user(urb->actual_length, - &((struct usbdevfs_urb *)as->userurb)->actual_length)) + if (put_user(urb->actual_length, &userurb->actual_length)) return -EFAULT; - if (put_user(urb->error_count, - &((struct usbdevfs_urb *)as->userurb)->error_count)) + if (put_user(urb->error_count, &userurb->error_count)) return -EFAULT; if (!(usb_pipeisoc(urb->pipe))) return 0; for (i = 0; i < urb->number_of_packets; i++) { if (put_user(urb->iso_frame_desc[i].actual_length, - &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length)) + &userurb->iso_frame_desc[i].actual_length)) return -EFAULT; if (put_user(urb->iso_frame_desc[i].status, - &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status)) + &userurb->iso_frame_desc[i].status)) return -EFAULT; } return 0; -- cgit v1.2.3 From 6214d5daf7aea9e66598e3c1861dc791590a393c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 21 Jun 2004 19:25:34 -0700 Subject: [PATCH] I2C: Drop out-of-date code in w83781d and w83627hf Here is a simple patch which drops some out-of-date code in the w83781d and w83627hf i2c chip drivers. These bits are left over from the times when chip drivers were setting default limits at init. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/w83627hf.c | 5 +---- drivers/i2c/chips/w83781d.c | 11 ++--------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c index 649bf80203bd..5d1a31bcb222 100644 --- a/drivers/i2c/chips/w83627hf.c +++ b/drivers/i2c/chips/w83627hf.c @@ -1240,7 +1240,7 @@ static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value) static void w83627hf_init_client(struct i2c_client *client) { struct w83627hf_data *data = i2c_get_clientdata(client); - int vid = 0, i; + int i; int type = data->type; u8 tmp; @@ -1284,9 +1284,6 @@ static void w83627hf_init_client(struct i2c_client *client) data->vrm = DEFAULT_VRM; } - if (type != w83697hf) - vid = vid_from_reg(vid, data->vrm); - tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); for (i = 1; i <= 3; i++) { if (!(tmp & BIT_SCFG1[i - 1])) { diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c index df30ca18602a..785203d39d68 100644 --- a/drivers/i2c/chips/w83781d.c +++ b/drivers/i2c/chips/w83781d.c @@ -1491,7 +1491,7 @@ static void w83781d_init_client(struct i2c_client *client) { struct w83781d_data *data = i2c_get_clientdata(client); - int vid = 0, i, p; + int i, p; int type = data->type; u8 tmp; @@ -1513,14 +1513,7 @@ w83781d_init_client(struct i2c_client *client) w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0); } - if (type != w83697hf) { - vid = w83781d_read_value(client, W83781D_REG_VID_FANDIV) & 0x0f; - vid |= - (w83781d_read_value(client, W83781D_REG_CHIPID) & 0x01) << - 4; - data->vrm = DEFAULT_VRM; - vid = vid_from_reg(vid, data->vrm); - } + data->vrm = 82; if ((type != w83781d) && (type != as99127f)) { tmp = w83781d_read_value(client, W83781D_REG_SCFG1); -- cgit v1.2.3 From 9c8a1f3c1051e4fd21223acbd4f4143aa0f7b568 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 21 Jun 2004 19:28:50 -0700 Subject: Fix C99'ism that breaks older gcc's. Also clean it all up - use get_cpu()/put_cpu() instead of playing games by hand with preemption. --- net/core/dev.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 9729210ca4cb..95a2b344e949 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1406,13 +1406,12 @@ int dev_queue_xmit(struct sk_buff *skb) Either shot noqueue qdisc, it is even simpler 8) */ if (dev->flags & IFF_UP) { - preempt_disable(); - int cpu = smp_processor_id(); + int cpu = get_cpu(); if (dev->xmit_lock_owner != cpu) { HARD_TX_LOCK_BH(dev, cpu); - preempt_enable(); + put_cpu(); if (!netif_queue_stopped(dev)) { if (netdev_nit) @@ -1430,7 +1429,7 @@ int dev_queue_xmit(struct sk_buff *skb) "queue packet!\n", dev->name); goto out_enetdown; } else { - preempt_enable(); + put_cpu(); /* Recursion is detected! It is possible, * unfortunately */ if (net_ratelimit()) -- cgit v1.2.3 From 7e5302e77c29b0dcf4d9188a1d4bf682d73de8b4 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 21 Jun 2004 20:18:32 -0700 Subject: sparse: clean up warning in swapfile.c --- mm/swapfile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/swapfile.c b/mm/swapfile.c index 154d05795678..6422f1b8d810 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -652,7 +652,7 @@ static int try_to_unuse(unsigned int type) * open() method called) - so swap entries may be invisible * to swapoff for a while, then reappear - but that is rare. */ - while ((i = find_next_to_unuse(si, i))) { + while ((i = find_next_to_unuse(si, i)) != 0) { if (signal_pending(current)) { retval = -EINTR; break; -- cgit v1.2.3 From 5eef782fc251a4936c8aedca4879387aad58dae2 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 22 Jun 2004 05:02:35 -0400 Subject: [blk carmel] s/carmel/sx8/ in the driver itself --- drivers/block/sx8.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index 38fd6fe42d07..0a0234129030 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -1,5 +1,5 @@ /* - * carmel.c: Driver for Promise SATA SX8 looks-like-I2O hardware + * sx8.c: Driver for Promise SATA SX8 looks-like-I2O hardware * * Copyright 2004 Red Hat, Inc. * @@ -32,7 +32,7 @@ MODULE_AUTHOR("Jeff Garzik"); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Promise SATA SX8 (carmel) block driver"); +MODULE_DESCRIPTION("Promise SATA SX8 block driver"); #if 0 #define CARM_DEBUG @@ -43,7 +43,7 @@ MODULE_DESCRIPTION("Promise SATA SX8 (carmel) block driver"); #endif #undef CARM_NDEBUG -#define DRV_NAME "carmel" +#define DRV_NAME "sx8" #define DRV_VERSION "0.8" #define PFX DRV_NAME ": " -- cgit v1.2.3 From 61266d5f8b5b08ff99b767a50cb24d72f96b5a64 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 21 Jun 2004 23:54:22 -0700 Subject: [IPSEC]: In ESP, do not put scatterlist array on stack. Put it in per-esp data instead. Noticed by Linus. Signed-off-by: David S. Miller --- include/net/esp.h | 5 +++++ net/ipv4/esp4.c | 16 ++++++---------- net/ipv6/esp6.c | 16 ++++++---------- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/include/net/esp.h b/include/net/esp.h index a513d14522ee..90cd94fad7d9 100644 --- a/include/net/esp.h +++ b/include/net/esp.h @@ -2,9 +2,14 @@ #define _NET_ESP_H #include +#include + +#define ESP_NUM_FAST_SG 4 struct esp_data { + struct scatterlist sgbuf[ESP_NUM_FAST_SG]; + /* Confidentiality */ struct { u8 *key; /* Key */ diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index acecd602a2c8..2cd91612ed63 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -11,8 +11,6 @@ #include #include -#define MAX_SG_ONSTACK 4 - /* decapsulation data for use when post-processing */ struct esp_decap_data { xfrm_address_t saddr; @@ -185,17 +183,16 @@ int esp_output(struct sk_buff **pskb) crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); do { - struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; - struct scatterlist *sg = sgbuf; + struct scatterlist *sg = &esp->sgbuf[0]; - if (unlikely(nfrags > MAX_SG_ONSTACK)) { + if (unlikely(nfrags > ESP_NUM_FAST_SG)) { sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); if (!sg) goto error; } skb_to_sgvec(*pskb, sg, esph->enc_data+esp->conf.ivlen-(*pskb)->data, clen); crypto_cipher_encrypt(tfm, sg, sg, clen); - if (unlikely(sg != sgbuf)) + if (unlikely(sg != &esp->sgbuf[0])) kfree(sg); } while (0); @@ -283,19 +280,18 @@ int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_bu { u8 nexthdr[2]; - struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; - struct scatterlist *sg = sgbuf; + struct scatterlist *sg = &esp->sgbuf[0]; u8 workbuf[60]; int padlen; - if (unlikely(nfrags > MAX_SG_ONSTACK)) { + if (unlikely(nfrags > ESP_NUM_FAST_SG)) { sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); if (!sg) goto out; } skb_to_sgvec(skb, sg, sizeof(struct ip_esp_hdr) + esp->conf.ivlen, elen); crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen); - if (unlikely(sg != sgbuf)) + if (unlikely(sg != &esp->sgbuf[0])) kfree(sg); if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index fb2720697d96..8682cf13402a 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -38,8 +38,6 @@ #include #include -#define MAX_SG_ONSTACK 4 - int esp6_output(struct sk_buff **pskb) { int err; @@ -151,17 +149,16 @@ int esp6_output(struct sk_buff **pskb) crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); do { - struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; - struct scatterlist *sg = sgbuf; + struct scatterlist *sg = &esp->sgbuf[0]; - if (unlikely(nfrags > MAX_SG_ONSTACK)) { + if (unlikely(nfrags > ESP_NUM_FAST_SG)) { sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); if (!sg) goto error; } skb_to_sgvec(*pskb, sg, esph->enc_data+esp->conf.ivlen-(*pskb)->data, clen); crypto_cipher_encrypt(tfm, sg, sg, clen); - if (unlikely(sg != sgbuf)) + if (unlikely(sg != &esp->sgbuf[0])) kfree(sg); } while (0); @@ -259,12 +256,11 @@ int esp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_b { u8 nexthdr[2]; - struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; - struct scatterlist *sg = sgbuf; + struct scatterlist *sg = &esp->sgbuf[0]; u8 padlen; u8 *prevhdr; - if (unlikely(nfrags > MAX_SG_ONSTACK)) { + if (unlikely(nfrags > ESP_NUM_FAST_SG)) { sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); if (!sg) { ret = -ENOMEM; @@ -273,7 +269,7 @@ int esp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_b } skb_to_sgvec(skb, sg, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen, elen); crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen); - if (unlikely(sg != sgbuf)) + if (unlikely(sg != &esp->sgbuf[0])) kfree(sg); if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) -- cgit v1.2.3 From 26e9ff172791e73e8ff61bffe4777c59bf89d0de Mon Sep 17 00:00:00 2001 From: Arthur Kepner Date: Tue, 22 Jun 2004 00:07:48 -0700 Subject: [NET]: In loopback, make get_stats() get correct per-cpu stats. Signed-off-by: Arthur Kepner Signed-off-by: David S. Miller --- drivers/net/loopback.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 318b1d60350c..8ffa894c3017 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -173,12 +173,11 @@ static struct net_device_stats *get_stats(struct net_device *dev) if (!cpu_possible(i)) continue; - lb_stats = &per_cpu(loopback_stats, get_cpu()); + lb_stats = &per_cpu(loopback_stats, i); stats->rx_bytes += lb_stats->rx_bytes; stats->tx_bytes += lb_stats->tx_bytes; stats->rx_packets += lb_stats->rx_packets; stats->tx_packets += lb_stats->tx_packets; - put_cpu(); } return stats; -- cgit v1.2.3 From 694b677ff8b68d1a5b6692795615f6d118e96873 Mon Sep 17 00:00:00 2001 From: Marc Singer Date: Wed, 23 Jun 2004 02:44:18 +0100 Subject: [ARM PATCH] 1913/1: lh7a40x #3 (1/2) serial Patch from Marc Singer Serial console and port driver for the LH7a40x CPUs. The only change made since the last patch was to change the PORT_ID (again). This patch superceeds two serial driver patches. --- drivers/serial/Kconfig | 23 ++ drivers/serial/Makefile | 1 + drivers/serial/serial_lh7a40x.c | 708 ++++++++++++++++++++++++++++++++++++++++ include/linux/serial_core.h | 3 + 4 files changed, 735 insertions(+) create mode 100644 drivers/serial/serial_lh7a40x.c diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index e5ce98eb0378..cb005e5a5bca 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -603,5 +603,28 @@ config SERIAL_PMACZILOG_CONSOLE on your PowerMac as the console, you can do so by answering Y to this option. +config SERIAL_LH7A40X + tristate "Sharp LH7A40X embedded UART support" + depends on ARM && ARCH_LH7A40X + select SERIAL_CORE + help + This enables support for the three on-board UARTs of the + Sharp LH7A40X series CPUs. Choose Y or M. + +config SERIAL_LH7A40X_CONSOLE + bool "Support for connsole on Sharp LH7A40X serial port" + depends on SERIAL_LH7A40X=y + select SERIAL_CORE_CONSOLE + help + Say Y here if you wish to use one of the serial ports as the + system console--the system console is the device which + receives all kernel messages and warnings and which allows + logins in single user mode. + + Even if you say Y here, the currently visible framebuffer console + (/dev/tty0) will still be used as the default system console, but + you can alter that using a kernel command line, for example + "console=ttyAM1". + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index c2eb159d8b43..ceacc99d8cd1 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_SERIAL_68360) += 68360serial.o obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o obj-$(CONFIG_V850E_UART) += v850e_uart.o obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o +obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o obj-$(CONFIG_SERIAL_AU1X00) += au1x00_uart.o obj-$(CONFIG_SERIAL_DZ) += dz.o obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c new file mode 100644 index 000000000000..d863368e45e2 --- /dev/null +++ b/drivers/serial/serial_lh7a40x.c @@ -0,0 +1,708 @@ +/* drivers/serial/serial_lh7a40x.c + * + * Copyright (C) 2004 Coastal Environmental Systems + * + * This program 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. + * + */ + +/* Driver for Sharp LH7A40X embedded serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd. + * + * --- + * + * This driver supports the embedded UARTs of the Sharp LH7A40X series + * CPUs. While similar to the 16550 and other UART chips, there is + * nothing close to register compatibility. Moreover, some of the + * modem control lines are not available, either in the chip or they + * are lacking in the board-level implementation. + * + * - Use of SIRDIS + * For simplicity, we disable the IR functions of any UART whenever + * we enable it. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include + +#include + +#define DEV_MAJOR 204 +#define DEV_MINOR 16 +#define DEV_NR 3 + +#define ISR_LOOP_LIMIT 256 + +#define UR(p,o) _UR ((p)->membase, o) +#define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o)))) +#define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m) +#define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m) + +#define UART_REG_SIZE 32 + +#define UARTEN (0x01) /* UART enable */ +#define SIRDIS (0x02) /* Serial IR disable (UART1 only) */ + +#define RxEmpty (0x10) +#define TxEmpty (0x80) +#define TxFull (0x20) +#define nRxRdy RxEmpty +#define nTxRdy TxFull +#define TxBusy (0x08) + +#define RxBreak (0x0800) +#define RxOverrunError (0x0400) +#define RxParityError (0x0200) +#define RxFramingError (0x0100) +#define RxError (RxBreak | RxOverrunError | RxParityError | RxFramingError) + +#define DCD (0x04) +#define DSR (0x02) +#define CTS (0x01) + +#define RxInt (0x01) +#define TxInt (0x02) +#define ModemInt (0x04) +#define RxTimeoutInt (0x08) + +#define MSEOI (0x10) + +#define WLEN_8 (0x60) +#define WLEN_7 (0x40) +#define WLEN_6 (0x20) +#define WLEN_5 (0x00) +#define WLEN (0x60) /* Mask for all word-length bits */ +#define STP2 (0x08) +#define PEN (0x02) /* Parity Enable */ +#define EPS (0x04) /* Even Parity Set */ +#define FEN (0x10) /* FIFO Enable */ +#define BRK (0x01) /* Send Break */ + + +struct uart_port_lh7a40x { + struct uart_port port; + unsigned int statusPrev; /* Most recently read modem status */ +}; + +static void lh7a40xuart_stop_tx (struct uart_port* port, unsigned int tty_stop) +{ + BIT_CLR (port, UART_R_INTEN, TxInt); +} + +static void lh7a40xuart_start_tx (struct uart_port* port, + unsigned int tty_start) +{ + BIT_SET (port, UART_R_INTEN, TxInt); + + /* *** FIXME: do I need to check for startup of the + transmitter? The old driver did, but AMBA + doesn't . */ +} + +static void lh7a40xuart_stop_rx (struct uart_port* port) +{ + BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt); +} + +static void lh7a40xuart_enable_ms (struct uart_port* port) +{ + BIT_SET (port, UART_R_INTEN, ModemInt); +} + +static void +#ifdef SUPPORT_SYSRQ +lh7a40xuart_rx_chars (struct uart_port* port, struct pt_regs* regs) +#else +lh7a40xuart_rx_chars (struct uart_port* port) +#endif +{ + struct tty_struct* tty = port->info->tty; + int cbRxMax = 256; /* (Gross) limit on receive */ + unsigned int data; /* Received data and status */ + + while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty->flip.work.func((void*)tty); + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + printk(KERN_WARNING "TTY_DONT_FLIP set\n"); + return; + } + } + + data = UR (port, UART_R_DATA); + + *tty->flip.char_buf_ptr = (unsigned char) data; + *tty->flip.flag_buf_ptr = TTY_NORMAL; + ++port->icount.rx; + + if (data & RxError) { /* Quick check, short-circuit */ + if (data & RxBreak) { + data &= ~(RxFramingError | RxParityError); + ++port->icount.brk; + if (uart_handle_break (port)) + continue; + } + else if (data & RxParityError) + ++port->icount.parity; + else if (data & RxFramingError) + ++port->icount.frame; + if (data & RxOverrunError) + ++port->icount.overrun; + + /* Mask by termios, leave Rx'd byte */ + data &= port->read_status_mask | 0xff; + + if (data & RxBreak) + *tty->flip.flag_buf_ptr = TTY_BREAK; + else if (data & RxParityError) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (data & RxFramingError) + *tty->flip.flag_buf_ptr = TTY_FRAME; + } + + if (uart_handle_sysrq_char (port, (unsigned char) data, regs)) + continue; + + if ((data & port->ignore_status_mask) == 0) { + ++tty->flip.flag_buf_ptr; + ++tty->flip.char_buf_ptr; + ++tty->flip.count; + } + if ((data & RxOverrunError) + && tty->flip.count < TTY_FLIPBUF_SIZE) { + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character + */ + *tty->flip.char_buf_ptr++ = 0; + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + ++tty->flip.count; + } + } + tty_flip_buffer_push (tty); + return; +} + +static void lh7a40xuart_tx_chars (struct uart_port* port) +{ + struct circ_buf* xmit = &port->info->xmit; + int cbTxMax = port->fifosize; + + if (port->x_char) { + UR (port, UART_R_DATA) = port->x_char; + ++port->icount.tx; + port->x_char = 0; + return; + } + if (uart_circ_empty (xmit) || uart_tx_stopped (port)) { + lh7a40xuart_stop_tx (port, 0); + return; + } + + /* Unlike the AMBA UART, the lh7a40x UART does not guarantee + that at least half of the FIFO is empty. Instead, we check + status for every character. Using the AMBA method causes + the transmitter to drop characters. */ + + do { + UR (port, UART_R_DATA) = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + ++port->icount.tx; + if (uart_circ_empty(xmit)) + break; + } while (!(UR (port, UART_R_STATUS) & nTxRdy) + && cbTxMax--); + + if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS) + uart_write_wakeup (port); + + if (uart_circ_empty (xmit)) + lh7a40xuart_stop_tx (port, 0); +} + +static void lh7a40xuart_modem_status (struct uart_port* port) +{ + unsigned int status = UR (port, UART_R_STATUS); + unsigned int delta + = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev; + + BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */ + + if (!delta) /* Only happens if we missed 2 transitions */ + return; + + ((struct uart_port_lh7a40x*) port)->statusPrev = status; + + if (delta & DCD) + uart_handle_dcd_change (port, status & DCD); + + if (delta & DSR) + ++port->icount.dsr; + + if (delta & CTS) + uart_handle_cts_change (port, status & CTS); + + wake_up_interruptible (&port->info->delta_msr_wait); +} + +static irqreturn_t lh7a40xuart_int (int irq, void* dev_id, + struct pt_regs* regs) +{ + struct uart_port* port = dev_id; + unsigned int cLoopLimit = ISR_LOOP_LIMIT; + unsigned int isr = UR (port, UART_R_ISR); + + + do { + if (isr & (RxInt | RxTimeoutInt)) +#ifdef SUPPORT_SYSRQ + lh7a40xuart_rx_chars(port, regs); +#else + lh7a40xuart_rx_chars(port); +#endif + if (isr & ModemInt) + lh7a40xuart_modem_status (port); + if (isr & TxInt) + lh7a40xuart_tx_chars (port); + + if (--cLoopLimit == 0) + break; + + isr = UR (port, UART_R_ISR); + } while (isr & (RxInt | TxInt | RxTimeoutInt)); + + return IRQ_HANDLED; +} + +static unsigned int lh7a40xuart_tx_empty (struct uart_port* port) +{ + return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0; +} + +static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port) +{ + unsigned int result = 0; + unsigned int status = UR (port, UART_R_STATUS); + + if (status & DCD) + result |= TIOCM_CAR; + if (status & DSR) + result |= TIOCM_DSR; + if (status & CTS) + result |= TIOCM_CTS; + + return result; +} + +static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl) +{ + /* None of the ports supports DTR. UART1 supports RTS through GPIO. */ + /* Note, kernel appears to be setting DTR and RTS on console. */ + + /* *** FIXME: this deserves more work. There's some work in + tracing all of the IO pins. */ +#if 0 + if( port->mapbase == UART1_PHYS) { + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + + if (mctrl & TIOCM_RTS) + gpio->pbdr &= ~GPIOB_UART1_RTS; + else + gpio->pbdr |= GPIOB_UART1_RTS; + } +#endif +} + +static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (break_state == -1) + BIT_SET (port, UART_R_FCON, BRK); /* Assert break */ + else + BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */ + spin_unlock_irqrestore(&port->lock, flags); +} + +static int lh7a40xuart_startup (struct uart_port* port) +{ + int retval; + + retval = request_irq (port->irq, lh7a40xuart_int, 0, + "serial_lh7a40x", port); + if (retval) + return retval; + + /* Initial modem control-line settings */ + ((struct uart_port_lh7a40x*) port)->statusPrev + = UR (port, UART_R_STATUS); + + /* There is presently no configuration option to enable IR. + Thus, we always disable it. */ + + BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); + BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt); + + return 0; +} + +static void lh7a40xuart_shutdown (struct uart_port* port) +{ + free_irq (port->irq, port); + BIT_CLR (port, UART_R_FCON, BRK | FEN); + BIT_CLR (port, UART_R_CON, UARTEN); +} + +static void lh7a40xuart_set_termios (struct uart_port* port, + struct termios* termios, + struct termios* old) +{ + unsigned int con; + unsigned int inten; + unsigned int fcon; + unsigned long flags; + unsigned int baud; + unsigned int quot; + + baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16); + quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */ + + switch (termios->c_cflag & CSIZE) { + case CS5: + fcon = WLEN_5; + break; + case CS6: + fcon = WLEN_6; + break; + case CS7: + fcon = WLEN_7; + break; + case CS8: + default: + fcon = WLEN_8; + break; + } + if (termios->c_cflag & CSTOPB) + fcon |= STP2; + if (termios->c_cflag & PARENB) { + fcon |= PEN; + if (!(termios->c_cflag & PARODD)) + fcon |= EPS; + } + if (port->fifosize > 1) + fcon |= FEN; + + spin_lock_irqsave (&port->lock, flags); + + uart_update_timeout (port, termios->c_cflag, baud); + + port->read_status_mask = RxOverrunError; + if (termios->c_iflag & INPCK) + port->read_status_mask |= RxFramingError | RxParityError; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= RxBreak; + + /* Figure mask for status we ignore */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= RxFramingError | RxParityError; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= RxBreak; + /* Ignore overrun when ignorning parity */ + /* *** FIXME: is this in the right place? */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= RxOverrunError; + } + + /* Ignore all receive errors when receive disabled */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= RxError; + + con = UR (port, UART_R_CON); + inten = (UR (port, UART_R_INTEN) & ~ModemInt); + + if (UART_ENABLE_MS (port, termios->c_cflag)) + inten |= ModemInt; + + BIT_CLR (port, UART_R_CON, UARTEN); /* Disable UART */ + UR (port, UART_R_INTEN) = 0; /* Disable interrupts */ + UR (port, UART_R_BRCON) = quot - 1; /* Set baud rate divisor */ + UR (port, UART_R_FCON) = fcon; /* Set FIFO and frame ctrl */ + UR (port, UART_R_INTEN) = inten; /* Enable interrupts */ + UR (port, UART_R_CON) = con; /* Restore UART mode */ + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char* lh7a40xuart_type (struct uart_port* port) +{ + return port->type == PORT_LH7A40X ? "LH7A40X" : NULL; +} + +static void lh7a40xuart_release_port (struct uart_port* port) +{ + release_mem_region (port->mapbase, UART_REG_SIZE); +} + +static int lh7a40xuart_request_port (struct uart_port* port) +{ + return request_mem_region (port->mapbase, UART_REG_SIZE, + "serial_lh7a40x") != NULL + ? 0 : -EBUSY; +} + +static void lh7a40xuart_config_port (struct uart_port* port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_LH7A40X; + lh7a40xuart_request_port (port); + } +} + +static int lh7a40xuart_verify_port (struct uart_port* port, + struct serial_struct* ser) +{ + int ret = 0; + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X) + ret = -EINVAL; + if (ser->irq < 0 || ser->irq >= NR_IRQS) + ret = -EINVAL; + if (ser->baud_base < 9600) /* *** FIXME: is this true? */ + ret = -EINVAL; + return ret; +} + +static struct uart_ops lh7a40x_uart_ops = { + .tx_empty = lh7a40xuart_tx_empty, + .set_mctrl = lh7a40xuart_set_mctrl, + .get_mctrl = lh7a40xuart_get_mctrl, + .stop_tx = lh7a40xuart_stop_tx, + .start_tx = lh7a40xuart_start_tx, + .stop_rx = lh7a40xuart_stop_rx, + .enable_ms = lh7a40xuart_enable_ms, + .break_ctl = lh7a40xuart_break_ctl, + .startup = lh7a40xuart_startup, + .shutdown = lh7a40xuart_shutdown, + .set_termios = lh7a40xuart_set_termios, + .type = lh7a40xuart_type, + .release_port = lh7a40xuart_release_port, + .request_port = lh7a40xuart_request_port, + .config_port = lh7a40xuart_config_port, + .verify_port = lh7a40xuart_verify_port, +}; + +static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = { + { + .port = { + .membase = (void*) io_p2v (UART1_PHYS), + .mapbase = UART1_PHYS, + .iotype = SERIAL_IO_MEM, + .irq = IRQ_UART1INTR, + .uartclk = 14745600/2, + .fifosize = 16, + .ops = &lh7a40x_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + }, + }, + { + .port = { + .membase = (void*) io_p2v (UART2_PHYS), + .mapbase = UART2_PHYS, + .iotype = SERIAL_IO_MEM, + .irq = IRQ_UART2INTR, + .uartclk = 14745600/2, + .fifosize = 16, + .ops = &lh7a40x_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 1, + }, + }, + { + .port = { + .membase = (void*) io_p2v (UART3_PHYS), + .mapbase = UART3_PHYS, + .iotype = SERIAL_IO_MEM, + .irq = IRQ_UART3INTR, + .uartclk = 14745600/2, + .fifosize = 16, + .ops = &lh7a40x_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 2, + }, + }, +}; + +#ifndef CONFIG_SERIAL_LH7A40X_CONSOLE +# define LH7A40X_CONSOLE NULL +#else +# define LH7A40X_CONSOLE &lh7a40x_console + + +static void lh7a40xuart_console_write (struct console* co, + const char* s, + unsigned int count) +{ + struct uart_port* port = &lh7a40x_ports[co->index].port; + unsigned int con = UR (port, UART_R_CON); + unsigned int inten = UR (port, UART_R_INTEN); + + + UR (port, UART_R_INTEN) = 0; /* Disable all interrupts */ + BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */ + + for (; count-- > 0; ++s) { + while (UR (port, UART_R_STATUS) & nTxRdy) + ; + UR (port, UART_R_DATA) = *s; + if (*s == '\n') { + while ((UR (port, UART_R_STATUS) & TxBusy)) + ; + UR (port, UART_R_DATA) = '\r'; + } + } + + /* Wait until all characters are sent */ + while (UR (port, UART_R_STATUS) & TxBusy) + ; + + /* Restore control and interrupt mask */ + UR (port, UART_R_CON) = con; + UR (port, UART_R_INTEN) = inten; +} + +static void __init lh7a40xuart_console_get_options (struct uart_port* port, + int* baud, + int* parity, + int* bits) +{ + if (UR (port, UART_R_CON) & UARTEN) { + unsigned int fcon = UR (port, UART_R_FCON); + unsigned int quot = UR (port, UART_R_BRCON) + 1; + + switch (fcon & (PEN | EPS)) { + default: *parity = 'n'; break; + case PEN: *parity = 'o'; break; + case PEN | EPS: *parity = 'e'; break; + } + + switch (fcon & WLEN) { + default: + case WLEN_8: *bits = 8; break; + case WLEN_7: *bits = 7; break; + case WLEN_6: *bits = 6; break; + case WLEN_5: *bits = 5; break; + } + + *baud = port->uartclk/(16*quot); + } +} + +static int __init lh7a40xuart_console_setup (struct console* co, char* options) +{ + struct uart_port* port; + int baud = 38400; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index >= DEV_NR) /* Bounds check on device number */ + co->index = 0; + port = &lh7a40x_ports[co->index].port; + + if (options) + uart_parse_options (options, &baud, &parity, &bits, &flow); + else + lh7a40xuart_console_get_options (port, &baud, &parity, &bits); + + return uart_set_options (port, co, baud, parity, bits, flow); +} + +extern struct uart_driver lh7a40x_reg; +static struct console lh7a40x_console = { + .name = "ttyAM", + .write = lh7a40xuart_console_write, + .device = uart_console_device, + .setup = lh7a40xuart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &lh7a40x_reg, +}; + +static int __init lh7a40xuart_console_init(void) +{ + register_console (&lh7a40x_console); + return 0; +} + +console_initcall (lh7a40xuart_console_init); + +#endif + +static struct uart_driver lh7a40x_reg = { + .owner = THIS_MODULE, + .driver_name = "ttyAM", + .dev_name = "ttyAM", + .major = DEV_MAJOR, + .minor = DEV_MINOR, + .nr = DEV_NR, + .cons = LH7A40X_CONSOLE, +}; + +static int __init lh7a40xuart_init(void) +{ + int ret; + + printk (KERN_INFO "serial: LH7A40X serial driver\n"); + + ret = uart_register_driver (&lh7a40x_reg); + + if (ret == 0) { + int i; + + for (i = 0; i < DEV_NR; i++) + uart_add_one_port (&lh7a40x_reg, + &lh7a40x_ports[i].port); + } + return ret; +} + +static void __exit lh7a40xuart_exit(void) +{ + int i; + + for (i = 0; i < DEV_NR; i++) + uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port); + + uart_unregister_driver (&lh7a40x_reg); +} + +module_init (lh7a40xuart_init); +module_exit (lh7a40xuart_exit); + +MODULE_AUTHOR ("Marc Singer"); +MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver"); +MODULE_LICENSE ("GPL"); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index f79c67d6f281..c653647073f1 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -80,6 +80,9 @@ /* SGI IP22 aka Indy / Challenge S / Indigo 2 */ #define PORT_IP22ZILOG 56 +/* Sharp LH7a40x -- an ARM9 SoC series */ +#define PORT_LH7A40X 57 + #ifdef __KERNEL__ #include -- cgit v1.2.3 From 33e8a4f82a0deb5b6384c4611a5f9db41ef82e5f Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 23 Jun 2004 02:48:22 +0100 Subject: [ARM PATCH] 1933/1: Convert PXA serial driver to device model and implement suspend and resume Patch from Ian Campbell Patch 1848/1 removed the hack for preserving FFUART over sleep. This patch adds back that support in the correct place by converting the PXA serial driver to use the driver model and hooking up the suspend and resume methods. --- arch/arm/mach-pxa/generic.c | 16 ++++++++++ drivers/serial/pxa.c | 73 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 78 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 20b776ff92d2..981f7b9750f1 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -198,10 +198,26 @@ static struct platform_device pxafb_device = { .resource = pxafb_resources, }; +static struct platform_device ffuart_device = { + .name = "pxa2xx-uart", + .id = 0, +}; +static struct platform_device btuart_device = { + .name = "pxa2xx-uart", + .id = 1, +}; +static struct platform_device stuart_device = { + .name = "pxa2xx-uart", + .id = 2, +}; + static struct platform_device *devices[] __initdata = { &pxamci_device, &udc_device, &pxafb_device, + &ffuart_device, + &btuart_device, + &stuart_device, }; static int __init pxa_init(void) diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index e83bb0728a37..cb6b4f3ec5c9 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -804,26 +805,76 @@ static struct uart_driver serial_pxa_reg = { .cons = PXA_CONSOLE, }; -static int __init serial_pxa_init(void) +static int serial_pxa_suspend(struct device *_dev, u32 state, u32 level) { - int i, ret; + struct uart_pxa_port *sport = dev_get_drvdata(_dev); - ret = uart_register_driver(&serial_pxa_reg); - if (ret) - return ret; + if (sport && level == SUSPEND_DISABLE) + uart_suspend_port(&serial_pxa_reg, &sport->port); + + return 0; +} - for (i = 0; i < ARRAY_SIZE(serial_pxa_ports); i++) - uart_add_one_port(&serial_pxa_reg, &serial_pxa_ports[i].port); +static int serial_pxa_resume(struct device *_dev, u32 level) +{ + struct uart_pxa_port *sport = dev_get_drvdata(_dev); + + if (sport && level == RESUME_ENABLE) + uart_resume_port(&serial_pxa_reg, &sport->port); + + return 0; +} +static int serial_pxa_probe(struct device *_dev) +{ + struct platform_device *dev = to_platform_device(_dev); + + serial_pxa_ports[dev->id].port.dev = _dev; + uart_add_one_port(&serial_pxa_reg, &serial_pxa_ports[dev->id].port); + dev_set_drvdata(_dev, &serial_pxa_ports[dev->id]); return 0; } -static void __exit serial_pxa_exit(void) +static int serial_pxa_remove(struct device *_dev) { - int i; + struct uart_pxa_port *sport = dev_get_drvdata(_dev); + + dev_set_drvdata(_dev, NULL); - for (i = 0; i < ARRAY_SIZE(serial_pxa_ports); i++) - uart_remove_one_port(&serial_pxa_reg, &serial_pxa_ports[i].port); + if (sport) + uart_remove_one_port(&serial_pxa_reg, &sport->port); + + return 0; +} + +static struct device_driver serial_pxa_driver = { + .name = "pxa2xx-uart", + .bus = &platform_bus_type, + .probe = serial_pxa_probe, + .remove = serial_pxa_remove, + + .suspend = serial_pxa_suspend, + .resume = serial_pxa_resume, +}; + +int __init serial_pxa_init(void) +{ + int ret; + + ret = uart_register_driver(&serial_pxa_reg); + if (ret != 0) + return ret; + + ret = driver_register(&serial_pxa_driver); + if (ret != 0) + uart_unregister_driver(&serial_pxa_reg); + + return ret; +} + +void __exit serial_pxa_exit(void) +{ + driver_unregister(&serial_pxa_driver); uart_unregister_driver(&serial_pxa_reg); } -- cgit v1.2.3 From 14881d2b19e687b2788d131ac54e9e7ee338c45c Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 22 Jun 2004 16:55:39 +0100 Subject: [ARM] Move cpu_switch_mm() and cpu_get_pgd() to asm/proc-fns.h --- include/asm-arm/cpu-multi32.h | 17 +---------------- include/asm-arm/cpu-single.h | 21 ++------------------- include/asm-arm/proc-fns.h | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 35 deletions(-) diff --git a/include/asm-arm/cpu-multi32.h b/include/asm-arm/cpu-multi32.h index 00f936197ad9..ff48022e4720 100644 --- a/include/asm-arm/cpu-multi32.h +++ b/include/asm-arm/cpu-multi32.h @@ -7,9 +7,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef __ASSEMBLY__ - -#include #include struct mm_struct; @@ -64,16 +61,4 @@ extern struct processor { #define cpu_do_idle() processor._do_idle() #define cpu_dcache_clean_area(addr,sz) processor.dcache_clean_area(addr,sz) #define cpu_set_pte(ptep, pte) processor.set_pte(ptep, pte) - -#define cpu_switch_mm(pgd,mm) processor.switch_mm(__virt_to_phys((unsigned long)(pgd)),mm) - -#define cpu_get_pgd() \ - ({ \ - unsigned long pg; \ - __asm__("mrc p15, 0, %0, c2, c0, 0" \ - : "=r" (pg) : : "cc"); \ - pg &= ~0x3fff; \ - (pgd_t *)phys_to_virt(pg); \ - }) - -#endif +#define cpu_do_switch_mm(pgd,mm) processor.switch_mm(pgd,mm) diff --git a/include/asm-arm/cpu-single.h b/include/asm-arm/cpu-single.h index cc213ad7167f..b5ec5d54665d 100644 --- a/include/asm-arm/cpu-single.h +++ b/include/asm-arm/cpu-single.h @@ -27,12 +27,9 @@ #define cpu_reset __cpu_fn(CPU_NAME,_reset) #define cpu_do_idle __cpu_fn(CPU_NAME,_do_idle) #define cpu_dcache_clean_area __cpu_fn(CPU_NAME,_dcache_clean_area) -#define cpu__switch_mm __cpu_fn(CPU_NAME,_switch_mm) +#define cpu_do_switch_mm __cpu_fn(CPU_NAME,_switch_mm) #define cpu_set_pte __cpu_fn(CPU_NAME,_set_pte) -#ifndef __ASSEMBLY__ - -#include #include struct mm_struct; @@ -42,20 +39,6 @@ extern void cpu_proc_init(void); extern void cpu_proc_fin(void); extern int cpu_do_idle(void); extern void cpu_dcache_clean_area(void *, int); -extern void cpu__switch_mm(unsigned long pgd_phys, struct mm_struct *mm); +extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); extern void cpu_set_pte(pte_t *ptep, pte_t pte); - extern volatile void cpu_reset(unsigned long addr); - -#define cpu_switch_mm(pgd,mm) cpu__switch_mm(__virt_to_phys((unsigned long)(pgd)),mm) - -#define cpu_get_pgd() \ - ({ \ - unsigned long pg; \ - __asm__("mrc p15, 0, %0, c2, c0, 0" \ - : "=r" (pg) : : "cc"); \ - pg &= ~0x3fff; \ - (pgd_t *)phys_to_virt(pg); \ - }) - -#endif diff --git a/include/asm-arm/proc-fns.h b/include/asm-arm/proc-fns.h index 9599c6e2f55a..7bef2bf6be51 100644 --- a/include/asm-arm/proc-fns.h +++ b/include/asm-arm/proc-fns.h @@ -148,11 +148,27 @@ # endif #endif +#ifndef __ASSEMBLY__ + #ifndef MULTI_CPU #include "asm/cpu-single.h" #else #include "asm/cpu-multi32.h" #endif +#include + +#define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm) + +#define cpu_get_pgd() \ + ({ \ + unsigned long pg; \ + __asm__("mrc p15, 0, %0, c2, c0, 0" \ + : "=r" (pg) : : "cc"); \ + pg &= ~0x3fff; \ + (pgd_t *)phys_to_virt(pg); \ + }) + +#endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* __ASM_PROCFNS_H */ -- cgit v1.2.3 From f4445c9528fbc07398c57ada10243c50eafd9b84 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 22 Jun 2004 18:23:52 +0100 Subject: [ARM] Correct MMCI clock rate on Integrator/CP. --- arch/arm/mach-integrator/integrator_cp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index f63e45cbe8fa..990ac40ab246 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -249,7 +249,7 @@ static struct clk cp_clcd_clk = { static struct clk cp_mmci_clk = { .name = "MCLK", - .rate = 33000000, + .rate = 14745600, }; /* @@ -351,7 +351,7 @@ static unsigned int mmc_status(struct device *dev) } static struct mmc_platform_data mmc_data = { - .mclk = 33000000, + .mclk = 14745600, .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .status = mmc_status, }; -- cgit v1.2.3 From 3f6e51d318598f0e5ac6869971a39054e3b502ee Mon Sep 17 00:00:00 2001 From: John Lenz Date: Wed, 23 Jun 2004 02:55:42 +0100 Subject: [ARM PATCH] 1935/1: Fix bug in sa1111 driver Patch from John Lenz The __sa1111_probe function is declared __init, and it is called from the sa1111_probe function, which is not declared __init. Signed-off-by: John Lenz --- arch/arm/common/sa1111.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index ee4b692e1d68..83eee1aa27e7 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -610,7 +610,7 @@ out: * %-EBUSY physical address already marked in-use. * %0 successful. */ -static int __init +static int __sa1111_probe(struct device *me, struct resource *mem, int irq) { struct sa1111 *sachip; -- cgit v1.2.3 From f0524a165567f11c0d1a16865e29b9f6069c2082 Mon Sep 17 00:00:00 2001 From: John Lenz Date: Wed, 23 Jun 2004 02:59:35 +0100 Subject: [ARM PATCH] 1936/1: Update collie fb entries to use new style initializers Patch from John Lenz Switches the collie framebuffer mach_info structure to use the new initializers. Signed-off-by: John Lenz --- drivers/video/sa1100fb.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index b14a667dbd81..1bca4cd1f71b 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -328,17 +328,17 @@ static struct sa1100fb_mach_info brutus_info __initdata = { #ifdef CONFIG_SA1100_COLLIE static struct sa1100fb_mach_info collie_info __initdata = { - pixclock: 171521, bpp: 16, - xres: 320, yres: 240, + .pixclock = 171521, .bpp = 16, + .xres = 320, .yres = 240, - hsync_len: 5, vsync_len: 1, - left_margin: 11, upper_margin: 2, - right_margin: 30, lower_margin: 0, + .hsync_len = 5, .vsync_len = 1, + .left_margin = 11, .upper_margin = 2, + .right_margin = 30, .lower_margin = 0, - sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act, - lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), }; #endif -- cgit v1.2.3 From f770ee2f181df2a5a0c590ed7c2aecc19ad98cf3 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 23 Jun 2004 03:03:51 +0100 Subject: [ARM PATCH] 1939/1: SA1100 watchdog driver also works on PXA2xx Patch from Ian Campbell The SA1100 watchdog driver also works fine on the PXA2xx. Tested on a PXA255 based platform. --- drivers/char/watchdog/Kconfig | 11 ++++++----- drivers/char/watchdog/sa1100_wdt.c | 8 ++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index c2b2dec8009c..703adb11115e 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -96,12 +96,13 @@ config IXP4XX_WATCHDOG Say N if you are unsure. config SA1100_WATCHDOG - tristate "SA1100 watchdog" - depends on WATCHDOG && ARCH_SA1100 + tristate "SA1100/PXA2xx watchdog" + depends on WATCHDOG && ( ARCH_SA1100 || ARCH_PXA ) help - Watchdog timer embedded into SA11x0 chips. This will reboot your - system when timeout is reached. - NOTE, that once enabled, this timer cannot be disabled. + Watchdog timer embedded into SA11x0 and PXA2xx chips. This will + reboot your system when timeout is reached. + + NOTE: once enabled, this timer cannot be disabled. To compile this driver as a module, choose M here: the module will be called sa1100_wdt. diff --git a/drivers/char/watchdog/sa1100_wdt.c b/drivers/char/watchdog/sa1100_wdt.c index 862fb9ab344a..aa3901fbab26 100644 --- a/drivers/char/watchdog/sa1100_wdt.c +++ b/drivers/char/watchdog/sa1100_wdt.c @@ -1,5 +1,5 @@ /* - * Watchdog driver for the SA11x0 + * Watchdog driver for the SA11x0/PXA2xx * * (c) Copyright 2000 Oleg Drokin * Based on SoftDog driver by Alan Cox @@ -174,7 +174,7 @@ static struct file_operations sa1100dog_fops = static struct miscdevice sa1100dog_miscdev = { .minor = WATCHDOG_MINOR, - .name = "SA1100 watchdog", + .name = "SA1100/PXA2xx watchdog", .fops = &sa1100dog_fops, }; @@ -194,7 +194,7 @@ static int __init sa1100dog_init(void) ret = misc_register(&sa1100dog_miscdev); if (ret == 0) - printk("SA1100 Watchdog Timer: timer margin %d sec\n", + printk("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n", margin); return ret; @@ -209,7 +209,7 @@ module_init(sa1100dog_init); module_exit(sa1100dog_exit); MODULE_AUTHOR("Oleg Drokin "); -MODULE_DESCRIPTION("SA1100 Watchdog"); +MODULE_DESCRIPTION("SA1100/PXA2xx Watchdog"); module_param(margin, int, 0); MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)"); -- cgit v1.2.3 From 797b051552940428abeeb75820720d47c7640527 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Wed, 23 Jun 2004 03:07:38 +0100 Subject: [ARM PATCH] 1940/1: asm-arm/checksum.h - missing include Patch from David Vrabel Missing include (cf. include/asm-i386/checksum.h) in include/asm-arm/checksum.h. --- include/asm-arm/checksum.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/asm-arm/checksum.h b/include/asm-arm/checksum.h index daa0f4e0abbf..f82f595c75af 100644 --- a/include/asm-arm/checksum.h +++ b/include/asm-arm/checksum.h @@ -9,6 +9,8 @@ #ifndef __ASM_ARM_CHECKSUM_H #define __ASM_ARM_CHECKSUM_H +#include + /* * computes the checksum of a memory block at buff, length len, * and adds in "sum" (32-bit) -- cgit v1.2.3 From 48c1a5733d9a55cca607a762c65c88096b329bbc Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 22 Jun 2004 12:42:16 -0400 Subject: [libata sata_sil] Re-fix mod15write bug Certain early SATA drives have problems with write requests whose length satisfy the equation "sectors % 15 == 1", on the SiI 3112. Other drives, and other SiI controllers, are not affected. The fix for this problem is to avoid such requests, in one of three ways, for the affect drive+controller combos: 1) Limit all writes to 15 sectors 2) Use block layer features to avoid creating requests whose length satisfies the above equation. 3) When a request satisfies the above equation, split the request into two writes, neither of which satisfies the equation. I chose fix #1, the most simple to implement. After discussion with Silicon Image and others regarding the impact of this fix, I have decided to remain with fix #1, and will not be implementing a "better fix". This means that the affected SATA drives will see decreased performance, but set of affected drives is small and will never grow larger. Further, the complexity of implementing solution #2 or solution #3 is rather large. When implementing lba48 'large request' support, I unintentionally broke the fix for these affected drives. Kudos to Ricky Beam for noticing this. This change restores the fix, by adding a flag ATA_DFLAG_LOCK_SECTORS to indicate that the max_sectors value set by the low-level driver should never be changed. --- drivers/scsi/libata-scsi.c | 3 ++- drivers/scsi/sata_sil.c | 1 + include/linux/libata.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index fed311e81c50..1c24c0eefe0e 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -182,7 +182,8 @@ int ata_scsi_slave_config(struct scsi_device *sdev) * 65534 when Jens Axboe's patch for dynamically * determining max_sectors is merged. */ - if (dev->flags & ATA_DFLAG_LBA48) { + if ((dev->flags & ATA_DFLAG_LBA48) && + ((dev->flags & ATA_DFLAG_LOCK_SECTORS) == 0)) { sdev->host->max_sectors = 2048; blk_queue_max_sectors(sdev->request_queue, 2048); } diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index 49ce4d02c1fd..12043e8f84cb 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -302,6 +302,7 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) ap->id, dev->devno); ap->host->max_sectors = 15; ap->host->hostt->max_sectors = 15; + dev->flags |= ATA_DFLAG_LOCK_SECTORS; return; } diff --git a/include/linux/libata.h b/include/linux/libata.h index 787f3583729a..a40286d08e23 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -91,6 +91,7 @@ enum { ATA_DFLAG_MASTER = (1 << 2), /* is device 0? */ ATA_DFLAG_WCACHE = (1 << 3), /* has write cache we can * (hopefully) flush? */ + ATA_DFLAG_LOCK_SECTORS = (1 << 4), /* don't adjust max_sectors */ ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ -- cgit v1.2.3 From b62102f692b387f5d3cd2e6d4b8c4bfecdd08c2d Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 22 Jun 2004 05:51:29 -0700 Subject: [PATCH] ppc32: Cleanups & warning fixes of traps.c This cleans up arch/ppc/kernel/traps.c and vecemu.c to use the same formatting style for all functions, and fixes 2 warnings in the altivec floating point emulation code. No functional change. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Linus Torvalds --- arch/ppc/kernel/traps.c | 53 +++++++++++++++------------------------------ arch/ppc/kernel/vecemu.c | 3 +-- include/asm-ppc/processor.h | 2 ++ 3 files changed, 21 insertions(+), 37 deletions(-) diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index ebe93fe949b8..d72c35081da2 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -103,8 +103,7 @@ void die(const char * str, struct pt_regs * fp, long err) do_exit(err); } -void -_exception(int signr, struct pt_regs *regs, int code, unsigned long addr) +void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) { siginfo_t info; @@ -200,8 +199,7 @@ static inline int check_io_access(struct pt_regs *regs) #define clear_single_step(regs) ((regs)->msr &= ~MSR_SE) #endif -void -MachineCheckException(struct pt_regs *regs) +void MachineCheckException(struct pt_regs *regs) { unsigned long reason = get_mc_reason(regs); @@ -329,8 +327,7 @@ MachineCheckException(struct pt_regs *regs) die("machine check", regs, SIGBUS); } -void -SMIException(struct pt_regs *regs) +void SMIException(struct pt_regs *regs) { debugger(regs); #if !(defined(CONFIG_XMON) || defined(CONFIG_KGDB)) @@ -339,24 +336,21 @@ SMIException(struct pt_regs *regs) #endif } -void -UnknownException(struct pt_regs *regs) +void UnknownException(struct pt_regs *regs) { printk("Bad trap at PC: %lx, MSR: %lx, vector=%lx %s\n", regs->nip, regs->msr, regs->trap, print_tainted()); _exception(SIGTRAP, regs, 0, 0); } -void -InstructionBreakpoint(struct pt_regs *regs) +void InstructionBreakpoint(struct pt_regs *regs) { if (debugger_iabr_match(regs)) return; _exception(SIGTRAP, regs, TRAP_BRKPT, 0); } -void -RunModeException(struct pt_regs *regs) +void RunModeException(struct pt_regs *regs) { _exception(SIGTRAP, regs, 0, 0); } @@ -374,8 +368,7 @@ RunModeException(struct pt_regs *regs) #define INST_MFSPR_PVR 0x7c1f42a6 #define INST_MFSPR_PVR_MASK 0xfc1fffff -static int -emulate_instruction(struct pt_regs *regs) +static int emulate_instruction(struct pt_regs *regs) { u32 instword; u32 rd; @@ -438,8 +431,7 @@ static struct bug_entry *find_bug(unsigned long bugaddr) return module_find_bug(bugaddr); } -int -check_bug_trap(struct pt_regs *regs) +int check_bug_trap(struct pt_regs *regs) { struct bug_entry *bug; unsigned long addr; @@ -476,8 +468,7 @@ check_bug_trap(struct pt_regs *regs) return 0; } -void -ProgramCheckException(struct pt_regs *regs) +void ProgramCheckException(struct pt_regs *regs) { unsigned int reason = get_reason(regs); extern int do_mathemu(struct pt_regs *regs); @@ -550,8 +541,7 @@ ProgramCheckException(struct pt_regs *regs) _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); } -void -SingleStepException(struct pt_regs *regs) +void SingleStepException(struct pt_regs *regs) { regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */ if (debugger_sstep(regs)) @@ -559,8 +549,7 @@ SingleStepException(struct pt_regs *regs) _exception(SIGTRAP, regs, TRAP_TRACE, 0); } -void -AlignmentException(struct pt_regs *regs) +void AlignmentException(struct pt_regs *regs) { int fixed; @@ -580,8 +569,7 @@ AlignmentException(struct pt_regs *regs) _exception(SIGBUS, regs, BUS_ADRALN, regs->dar); } -void -StackOverflow(struct pt_regs *regs) +void StackOverflow(struct pt_regs *regs) { printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n", current, regs->gpr[1]); @@ -598,8 +586,7 @@ void nonrecoverable_exception(struct pt_regs *regs) die("nonrecoverable exception", regs, SIGKILL); } -void -trace_syscall(struct pt_regs *regs) +void trace_syscall(struct pt_regs *regs) { printk("Task: %p(%d), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld %s\n", current, current->pid, regs->nip, regs->link, regs->gpr[0], @@ -607,8 +594,7 @@ trace_syscall(struct pt_regs *regs) } #ifdef CONFIG_8xx -void -SoftwareEmulation(struct pt_regs *regs) +void SoftwareEmulation(struct pt_regs *regs) { extern int do_mathemu(struct pt_regs *); extern int Soft_emulate_8xx(struct pt_regs *); @@ -660,8 +646,7 @@ void DebugException(struct pt_regs *regs, unsigned long debug_status) #endif /* CONFIG_4xx || CONFIG_BOOKE */ #if !defined(CONFIG_TAU_INT) -void -TAUException(struct pt_regs *regs) +void TAUException(struct pt_regs *regs) { printk("TAU trap at PC: %lx, MSR: %lx, vector=%lx %s\n", regs->nip, regs->msr, regs->trap, print_tainted()); @@ -683,14 +668,13 @@ void AltivecUnavailException(struct pt_regs *regs) /* The kernel has executed an altivec instruction without first enabling altivec. Whinge but let it do it. */ if (++kernel_altivec_count < 10) - printk(KERN_ERR "AltiVec used in kernel (task=%p, pc=%x)\n", + printk(KERN_ERR "AltiVec used in kernel (task=%p, pc=%lx)\n", current, regs->nip); regs->msr |= MSR_VEC; } #ifdef CONFIG_ALTIVEC -void -AltivecAssistException(struct pt_regs *regs) +void AltivecAssistException(struct pt_regs *regs) { int err; @@ -734,8 +718,7 @@ void CacheLockingException(struct pt_regs *regs, unsigned long address, #endif /* CONFIG_FSL_BOOKE */ #ifdef CONFIG_SPE -void -SPEFloatingPointException(struct pt_regs *regs) +void SPEFloatingPointException(struct pt_regs *regs) { unsigned long spefscr; int fpexc_mode; diff --git a/arch/ppc/kernel/vecemu.c b/arch/ppc/kernel/vecemu.c index 1430ef59279c..2411a1cbc638 100644 --- a/arch/ppc/kernel/vecemu.c +++ b/arch/ppc/kernel/vecemu.c @@ -256,8 +256,7 @@ static unsigned int rfin(unsigned int x) return (x + half) & ~(0x7fffff >> exp); } -int -emulate_altivec(struct pt_regs *regs) +int emulate_altivec(struct pt_regs *regs) { unsigned int instr, i; unsigned int va, vb, vc, vd; diff --git a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h index fe7a94383a1d..63fc68e784c5 100644 --- a/include/asm-ppc/processor.h +++ b/include/asm-ppc/processor.h @@ -197,6 +197,8 @@ extern inline void prefetchw(const void *x) #define spin_lock_prefetch(x) prefetchw(x) +extern int emulate_altivec(struct pt_regs *regs); + #endif /* !__ASSEMBLY__ */ #endif /* __ASM_PPC_PROCESSOR_H */ -- cgit v1.2.3 From e5603f997d01e56bae083ff0ee3a0e7b381c90ef Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 22 Jun 2004 05:51:41 -0700 Subject: [PATCH] ppc32: oprofile support This adds basic oprofile support to ppc32. Originally from Anton Blanchard, I just re-diffed it against current kernels. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Linus Torvalds --- arch/ppc/Kconfig | 1 + arch/ppc/Makefile | 2 ++ arch/ppc/kernel/time.c | 22 +++++++++++++++------- arch/ppc/oprofile/Kconfig | 23 +++++++++++++++++++++++ arch/ppc/oprofile/Makefile | 9 +++++++++ arch/ppc/oprofile/init.c | 23 +++++++++++++++++++++++ 6 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 arch/ppc/oprofile/Kconfig create mode 100644 arch/ppc/oprofile/Makefile create mode 100644 arch/ppc/oprofile/init.c diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 2b49740fbe10..ac5784c618b2 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -1183,6 +1183,7 @@ endmenu source "lib/Kconfig" +source "arch/ppc/oprofile/Kconfig" menu "Kernel hacking" diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index b050a1b03e34..52782b7ae2f1 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -50,6 +50,8 @@ drivers-$(CONFIG_8xx) += arch/ppc/8xx_io/ drivers-$(CONFIG_4xx) += arch/ppc/4xx_io/ drivers-$(CONFIG_8260) += arch/ppc/8260_io/ +drivers-$(CONFIG_OPROFILE) += arch/ppc/oprofile/ + BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm .PHONY: $(BOOT_TARGETS) diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c index 96a6138e4109..cfeff0479c2e 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -107,17 +108,23 @@ static inline int tb_delta(unsigned *jiffy_stamp) { return delta; } -extern unsigned long prof_cpu_mask; -extern unsigned int * prof_buffer; -extern unsigned long prof_len; -extern unsigned long prof_shift; extern char _stext; -static inline void ppc_do_profile (unsigned long nip) +static inline void ppc_do_profile (struct pt_regs *regs) { + unsigned long nip; + extern unsigned long prof_cpu_mask; + + profile_hook(regs); + + if (user_mode(regs)) + return; + if (!prof_buffer) return; + nip = instruction_pointer(regs); + /* * Only measure the CPUs specified by /proc/irq/prof_cpu_mask. * (default is all CPUs.) @@ -156,8 +163,9 @@ void timer_interrupt(struct pt_regs * regs) while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) < 0) { jiffy_stamp += tb_ticks_per_jiffy; - if (!user_mode(regs)) - ppc_do_profile(instruction_pointer(regs)); + + ppc_do_profile(regs); + if (smp_processor_id()) continue; diff --git a/arch/ppc/oprofile/Kconfig b/arch/ppc/oprofile/Kconfig new file mode 100644 index 000000000000..19d37730b664 --- /dev/null +++ b/arch/ppc/oprofile/Kconfig @@ -0,0 +1,23 @@ + +menu "Profiling support" + depends on EXPERIMENTAL + +config PROFILING + bool "Profiling support (EXPERIMENTAL)" + help + Say Y here to enable the extended profiling support mechanisms used + by profilers such as OProfile. + + +config OPROFILE + tristate "OProfile system profiling (EXPERIMENTAL)" + depends on PROFILING + help + OProfile is a profiling system capable of profiling the + whole system, include the kernel, kernel modules, libraries, + and applications. + + If unsure, say N. + +endmenu + diff --git a/arch/ppc/oprofile/Makefile b/arch/ppc/oprofile/Makefile new file mode 100644 index 000000000000..06e7c81ead2e --- /dev/null +++ b/arch/ppc/oprofile/Makefile @@ -0,0 +1,9 @@ +obj-$(CONFIG_OPROFILE) += oprofile.o + +DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \ + oprof.o cpu_buffer.o buffer_sync.o \ + event_buffer.o oprofile_files.o \ + oprofilefs.o oprofile_stats.o \ + timer_int.o ) + +oprofile-y := $(DRIVER_OBJS) init.o diff --git a/arch/ppc/oprofile/init.c b/arch/ppc/oprofile/init.c new file mode 100644 index 000000000000..e4217d66164e --- /dev/null +++ b/arch/ppc/oprofile/init.c @@ -0,0 +1,23 @@ +/** + * @file init.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#include +#include +#include +#include + +int __init oprofile_arch_init(struct oprofile_operations ** ops) +{ + return -ENODEV; +} + + +void oprofile_arch_exit(void) +{ +} -- cgit v1.2.3 From ca216b8acd734682fa53d5c447bb891fa466308d Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 22 Jun 2004 05:51:52 -0700 Subject: [PATCH] ppc32: Support for new Apple laptop models This adds support for newer Apple laptop models. It adds the basic identification for the new motherboards and the cpufreq support for models using the new 7447A CPU from Motorola. This is mostly the work of John Steele Scott with some bits from Sebastian Henschel and some rework by myself. Please apply, Signed-off-by: John Steele Scott Signed-off-by: Sebastian Henschel Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Linus Torvalds --- arch/ppc/kernel/misc.S | 18 +++ arch/ppc/platforms/pmac_cpufreq.c | 311 +++++++++++++++++++++++--------------- arch/ppc/platforms/pmac_feature.c | 32 ++++ include/asm-ppc/pmac_feature.h | 6 + include/asm-ppc/reg.h | 1 + include/asm-ppc/uninorth.h | 6 + 6 files changed, 256 insertions(+), 118 deletions(-) diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 38cd36d6cbe9..873199e435f6 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -253,6 +253,24 @@ _GLOBAL(low_choose_750fx_pll) mtmsr r7 blr +_GLOBAL(low_choose_7447a_dfs) + /* Clear MSR:EE */ + mfmsr r7 + rlwinm r0,r7,0,17,15 + mtmsr r0 + + /* Calc new HID1 value */ + mfspr r4,SPRN_HID1 + insrwi r4,r3,1,9 /* insert parameter into bit 9 */ + sync + mtspr SPRN_HID1,r4 + sync + isync + + /* Return */ + mtmsr r7 + blr + #endif /* CONFIG_CPU_FREQ_PMAC && CONFIG_6xx */ /* void local_save_flags_ptr(unsigned long *flags) */ diff --git a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c index 2c8cec2723ad..b26c7e158792 100644 --- a/arch/ppc/platforms/pmac_cpufreq.c +++ b/arch/ppc/platforms/pmac_cpufreq.c @@ -1,7 +1,8 @@ /* * arch/ppc/platforms/pmac_cpufreq.c * - * Copyright (C) 2002 - 2003 Benjamin Herrenschmidt + * Copyright (C) 2002 - 2004 Benjamin Herrenschmidt + * Copyright (C) 2004 John Steele Scott * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -47,6 +48,7 @@ #warning "WARNING, CPUFREQ not recommended on SMP kernels" #endif +extern void low_choose_7447a_dfs(int dfs); extern void low_choose_750fx_pll(int pll); extern void low_sleep_handler(void); extern void openpic_suspend(struct sys_device *sysdev, u32 state); @@ -54,18 +56,27 @@ extern void openpic_resume(struct sys_device *sysdev); extern void enable_kernel_altivec(void); extern void enable_kernel_fp(void); +/* + * Currently, PowerMac cpufreq supports only high & low frequencies + * that are set by the firmware + */ static unsigned int low_freq; static unsigned int hi_freq; static unsigned int cur_freq; -/* Clean that up some day ... use a func ptr or at least an enum... */ -static int cpufreq_uses_pmu; -static int cpufreq_uses_gpios; +/* + * Different models uses different mecanisms to switch the frequency + */ +static int (*set_speed_proc)(int low_speed); +/* + * Some definitions used by the various speedprocs + */ static u32 voltage_gpio; static u32 frequency_gpio; static u32 slew_done_gpio; + #define PMAC_CPU_LOW_SPEED 1 #define PMAC_CPU_HIGH_SPEED 0 @@ -123,9 +134,39 @@ static int __pmac cpu_750fx_cpu_speed(int low_speed) return 0; } +/* Switch CPU speed using DFS */ +static int __pmac dfs_set_cpu_speed(int low_speed) +{ + if (low_speed == 0) { + /* ramping up, set voltage first */ + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/1000); + } else { + /* ramping down, enable aack delay first */ + pmac_call_feature(PMAC_FTR_AACK_DELAY_ENABLE, NULL, 1, 0); + } + + /* set frequency */ + low_choose_7447a_dfs(low_speed); + + if (low_speed == 1) { + /* ramping down, set voltage last */ + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/1000); + } else { + /* ramping up, disable aack delay last */ + pmac_call_feature(PMAC_FTR_AACK_DELAY_ENABLE, NULL, 0, 0); + } + + return 0; +} + + /* Switch CPU speed using slewing GPIOs */ -static int __pmac gpios_set_cpu_speed(unsigned int low_speed) +static int __pmac gpios_set_cpu_speed(int low_speed) { int gpio; @@ -138,7 +179,8 @@ static int __pmac gpios_set_cpu_speed(unsigned int low_speed) } /* Set frequency */ - pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, frequency_gpio, low_speed ? 0x04 : 0x05); + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, frequency_gpio, + low_speed ? 0x04 : 0x05); udelay(200); do { set_current_state(TASK_UNINTERRUPTIBLE); @@ -163,7 +205,7 @@ static int __pmac gpios_set_cpu_speed(unsigned int low_speed) /* Switch CPU speed under PMU control */ -static int __pmac pmu_set_cpu_speed(unsigned int low_speed) +static int __pmac pmu_set_cpu_speed(int low_speed) { struct adb_request req; unsigned long save_l2cr; @@ -269,12 +311,7 @@ static int __pmac do_set_cpu_speed(int speed_mode) return 0; cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - if (cpufreq_uses_pmu) - rc = pmu_set_cpu_speed(speed_mode); - else if (cpufreq_uses_gpios) - rc = gpios_set_cpu_speed(speed_mode); - else - rc = cpu_750fx_cpu_speed(speed_mode); + set_speed_proc(speed_mode == PMAC_CPU_LOW_SPEED); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); cur_freq = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; @@ -338,20 +375,137 @@ static struct cpufreq_driver pmac_cpufreq_driver = { }; +static int __pmac pmac_cpufreq_init_MacRISC3(struct device_node *cpunode) +{ + struct device_node *volt_gpio_np = of_find_node_by_name(NULL, + "voltage-gpio"); + struct device_node *freq_gpio_np = of_find_node_by_name(NULL, + "frequency-gpio"); + struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL, + "slewing-done"); + u32 *value; + + /* + * Check to see if it's GPIO driven or PMU only + * + * The way we extract the GPIO address is slightly hackish, but it + * works well enough for now. We need to abstract the whole GPIO + * stuff sooner or later anyway + */ + + if (volt_gpio_np) + voltage_gpio = read_gpio(volt_gpio_np); + if (freq_gpio_np) + frequency_gpio = read_gpio(freq_gpio_np); + if (slew_done_gpio_np) + slew_done_gpio = read_gpio(slew_done_gpio_np); + + /* If we use the frequency GPIOs, calculate the min/max speeds based + * on the bus frequencies + */ + if (frequency_gpio && slew_done_gpio) { + int lenp, rc; + u32 *freqs, *ratio; + + freqs = (u32 *)get_property(cpunode, "bus-frequencies", &lenp); + lenp /= sizeof(u32); + if (freqs == NULL || lenp != 2) { + printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n"); + return 1; + } + ratio = (u32 *)get_property(cpunode, "processor-to-bus-ratio*2", NULL); + if (ratio == NULL) { + printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n"); + return 1; + } + + /* Get the min/max bus frequencies */ + low_freq = min(freqs[0], freqs[1]); + hi_freq = max(freqs[0], freqs[1]); + + /* Grrrr.. It _seems_ that the device-tree is lying on the low bus + * frequency, it claims it to be around 84Mhz on some models while + * it appears to be approx. 101Mhz on all. Let's hack around here... + * fortunately, we don't need to be too precise + */ + if (low_freq < 98000000) + low_freq = 101000000; + + /* Convert those to CPU core clocks */ + low_freq = (low_freq * (*ratio)) / 2000; + hi_freq = (hi_freq * (*ratio)) / 2000; + + /* Now we get the frequencies, we read the GPIO to see what is out current + * speed + */ + rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0); + cur_freq = (rc & 0x01) ? hi_freq : low_freq; + + set_speed_proc = gpios_set_cpu_speed; + return 1; + } + + /* If we use the PMU, look for the min & max frequencies in the + * device-tree + */ + value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL); + if (!value) + return 1; + low_freq = (*value) / 1000; + /* The PowerBook G4 12" (PowerBook6,1) has an error in the device-tree + * here */ + if (low_freq < 100000) + low_freq *= 10; + + value = (u32 *)get_property(cpunode, "max-clock-frequency", NULL); + if (!value) + return 1; + hi_freq = (*value) / 1000; + set_speed_proc = pmu_set_cpu_speed; + + return 0; +} + +static int __pmac pmac_cpufreq_init_7447A(struct device_node *cpunode) +{ + struct device_node *volt_gpio_np; + + /* OF only reports the high frequency */ + hi_freq = cur_freq; + low_freq = cur_freq/2; + if (mfspr(HID1) & HID1_DFS) + cur_freq = low_freq; + else + cur_freq = hi_freq; + + volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select"); + if (!volt_gpio_np){ + printk(KERN_ERR "cpufreq: missing cpu-vcore-select gpio\n"); + return 1; + } + + u32 *reg = (u32 *)get_property(volt_gpio_np, "reg", NULL); + voltage_gpio = *reg; + set_speed_proc = dfs_set_cpu_speed; + + return 0; +} + /* Currently, we support the following machines: * * - Titanium PowerBook 1Ghz (PMU based, 667Mhz & 1Ghz) * - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz) + * - Titanium PowerBook 400 (PMU based, 300Mhz & 400Mhz) * - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz) * - iBook2 500 (PMU based, 400Mhz & 500Mhz) * - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage) - * - Recent MacRISC3 machines + * - Recent MacRISC3 laptops + * - iBook G4s and PowerBook G4s with 7447A CPUs */ static int __init pmac_cpufreq_setup(void) { struct device_node *cpunode; u32 *value; - int has_freq_ctl = 0; if (strstr(cmd_line, "nocpufreq")) return 0; @@ -367,113 +521,36 @@ static int __init pmac_cpufreq_setup(void) goto out; cur_freq = (*value) / 1000; - /* Check for newer machines */ - if (machine_is_compatible("PowerBook3,4") || - machine_is_compatible("PowerBook3,5") || - machine_is_compatible("MacRISC3")) { - struct device_node *volt_gpio_np = of_find_node_by_name(NULL, "voltage-gpio"); - struct device_node *freq_gpio_np = of_find_node_by_name(NULL, "frequency-gpio"); - struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL, "slewing-done"); - - /* - * Check to see if it's GPIO driven or PMU only - * - * The way we extract the GPIO address is slightly hackish, but it - * works well enough for now. We need to abstract the whole GPIO - * stuff sooner or later anyway - */ - - if (volt_gpio_np) - voltage_gpio = read_gpio(volt_gpio_np); - if (freq_gpio_np) - frequency_gpio = read_gpio(freq_gpio_np); - if (slew_done_gpio_np) - slew_done_gpio = read_gpio(slew_done_gpio_np); - - /* If we use the frequency GPIOs, calculate the min/max speeds based - * on the bus frequencies - */ - if (frequency_gpio && slew_done_gpio) { - int lenp, rc; - u32 *freqs, *ratio; - - freqs = (u32 *)get_property(cpunode, "bus-frequencies", &lenp); - lenp /= sizeof(u32); - if (freqs == NULL || lenp != 2) { - printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n"); - goto out; - } - ratio = (u32 *)get_property(cpunode, "processor-to-bus-ratio*2", NULL); - if (ratio == NULL) { - printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n"); - goto out; - } - - /* Get the min/max bus frequencies */ - low_freq = min(freqs[0], freqs[1]); - hi_freq = max(freqs[0], freqs[1]); - - /* Grrrr.. It _seems_ that the device-tree is lying on the low bus - * frequency, it claims it to be around 84Mhz on some models while - * it appears to be approx. 101Mhz on all. Let's hack around here... - * fortunately, we don't need to be too precise - */ - if (low_freq < 98000000) - low_freq = 101000000; - - /* Convert those to CPU core clocks */ - low_freq = (low_freq * (*ratio)) / 2000; - hi_freq = (hi_freq * (*ratio)) / 2000; - - /* Now we get the frequencies, we read the GPIO to see what is out current - * speed - */ - rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0); - cur_freq = (rc & 0x01) ? hi_freq : low_freq; - - has_freq_ctl = 1; - cpufreq_uses_gpios = 1; - goto out; - } - - /* If we use the PMU, look for the min & max frequencies in the - * device-tree - */ - value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL); - if (!value) - goto out; - low_freq = (*value) / 1000; - /* The PowerBook G4 12" (PowerBook6,1) has an error in the device-tree - * here */ - if (low_freq < 100000) - low_freq *= 10; - - value = (u32 *)get_property(cpunode, "max-clock-frequency", NULL); - if (!value) - goto out; - hi_freq = (*value) / 1000; - has_freq_ctl = 1; - cpufreq_uses_pmu = 1; - } + /* Check for 7447A based iBook G4 or PowerBook */ + if (machine_is_compatible("PowerBook6,5") || + machine_is_compatible("PowerBook6,4") || + machine_is_compatible("PowerBook5,5") || + machine_is_compatible("PowerBook5,4")) { + pmac_cpufreq_init_7447A(cpunode); + /* Check for other MacRISC3 machines */ + } else if (machine_is_compatible("PowerBook3,4") || + machine_is_compatible("PowerBook3,5") || + machine_is_compatible("MacRISC3")) { + pmac_cpufreq_init_MacRISC3(cpunode); /* Else check for iBook2 500 */ - else if (machine_is_compatible("PowerBook4,1")) { + } else if (machine_is_compatible("PowerBook4,1")) { /* We only know about 500Mhz model */ if (cur_freq < 450000 || cur_freq > 550000) goto out; hi_freq = cur_freq; low_freq = 400000; - has_freq_ctl = 1; - cpufreq_uses_pmu = 1; + set_speed_proc = pmu_set_cpu_speed; } - /* Else check for TiPb 500 */ + /* Else check for TiPb 400 & 500 */ else if (machine_is_compatible("PowerBook3,2")) { - /* We only know about 500Mhz model */ - if (cur_freq < 450000 || cur_freq > 550000) + /* We only know about the 400 MHz and the 500Mhz model + * they both have 300 MHz as low frequency + */ + if (cur_freq < 350000 || cur_freq > 550000) goto out; hi_freq = cur_freq; low_freq = 300000; - has_freq_ctl = 1; - cpufreq_uses_pmu = 1; + set_speed_proc = pmu_set_cpu_speed; } /* Else check for 750FX */ else if (PVR_VER(mfspr(PVR)) == 0x7000) { @@ -483,21 +560,19 @@ static int __init pmac_cpufreq_setup(void) value = (u32 *)get_property(cpunode, "reduced-clock-frequency", NULL); if (!value) goto out; - low_freq = (*value) / 1000; - cpufreq_uses_pmu = 0; - has_freq_ctl = 1; + low_freq = (*value) / 1000; + set_speed_proc = cpu_750fx_cpu_speed; } out: - if (!has_freq_ctl) + if (set_speed_proc == NULL) return -ENODEV; pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq; pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq; printk(KERN_INFO "Registering PowerMac CPU frequency driver\n"); - printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz, switch method: %s\n", - low_freq/1000, hi_freq/1000, cur_freq/1000, - cpufreq_uses_pmu ? "PMU" : (cpufreq_uses_gpios ? "GPIOs" : "CPU")); + printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz\n", + low_freq/1000, hi_freq/1000, cur_freq/1000); return cpufreq_register_driver(&pmac_cpufreq_driver); } diff --git a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c index abd06fc82a34..35714de243b8 100644 --- a/arch/ppc/platforms/pmac_feature.c +++ b/arch/ppc/platforms/pmac_feature.c @@ -1282,6 +1282,25 @@ core99_firewire_cable_power(struct device_node* node, long param, long value) return 0; } +static long __pmac +intrepid_aack_delay_enable(struct device_node* node, long param, long value) +{ + unsigned long flags; + + if (uninorth_rev < 0xd2) + return -ENODEV; + + LOCK(flags); + if (param) + UN_BIS(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE); + else + UN_BIC(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE); + UNLOCK(flags); + + return 0; +} + + #endif /* CONFIG_POWER4 */ static long __pmac @@ -1914,6 +1933,7 @@ static struct feature_table_entry intrepid_features[] __pmacdata = { { PMAC_FTR_SLEEP_STATE, core99_sleep_state }, { PMAC_FTR_READ_GPIO, core99_read_gpio }, { PMAC_FTR_WRITE_GPIO, core99_write_gpio }, + { PMAC_FTR_AACK_DELAY_ENABLE, intrepid_aack_delay_enable }, { 0, NULL } }; @@ -2116,6 +2136,14 @@ static struct pmac_mb_def pmac_mb_defs[] __pmacdata = { PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, }, + { "PowerBook5,4", "PowerBook G4 15\"", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, + { "PowerBook5,5", "PowerBook G4 17\"", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, { "PowerBook6,1", "PowerBook G4 12\"", PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, @@ -2128,6 +2156,10 @@ static struct pmac_mb_def pmac_mb_defs[] __pmacdata = { PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, }, + { "PowerBook6,4", "PowerBook G4 12\"", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, { "PowerBook6,5", "iBook G4", PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, diff --git a/include/asm-ppc/pmac_feature.h b/include/asm-ppc/pmac_feature.h index 11065e368382..ee15e9c59aa2 100644 --- a/include/asm-ppc/pmac_feature.h +++ b/include/asm-ppc/pmac_feature.h @@ -273,6 +273,12 @@ static inline long pmac_call_feature(int selector, struct device_node* node, */ #define PMAC_FTR_ENABLE_MPIC PMAC_FTR_DEF(19) +/* PMAC_FTR_AACK_DELAY_ENABLE (NULL, int enable, 0) + * + * Enable/disable the AACK delay on the northbridge for systems using DFS + */ +#define PMAC_FTR_AACK_DELAY_ENABLE PMAC_FTR_DEF(20) + /* Don't use those directly, they are for the sake of pmac_setup.c */ extern long pmac_do_feature_call(unsigned int selector, ...); diff --git a/include/asm-ppc/reg.h b/include/asm-ppc/reg.h index f02ec3cf65ec..15c93af4079a 100644 --- a/include/asm-ppc/reg.h +++ b/include/asm-ppc/reg.h @@ -174,6 +174,7 @@ #define SPRN_HID1 0x3F1 /* Hardware Implementation Register 1 */ #define HID1_EMCP (1<<31) /* 7450 Machine Check Pin Enable */ +#define HID1_DFS (1<<22) /* 7447A Dynamic Frequency Scaling */ #define HID1_PC0 (1<<16) /* 7450 PLL_CFG[0] */ #define HID1_PC1 (1<<15) /* 7450 PLL_CFG[1] */ #define HID1_PC2 (1<<14) /* 7450 PLL_CFG[2] */ diff --git a/include/asm-ppc/uninorth.h b/include/asm-ppc/uninorth.h index eeff122f365b..2cf025936edf 100644 --- a/include/asm-ppc/uninorth.h +++ b/include/asm-ppc/uninorth.h @@ -142,6 +142,12 @@ */ #define UNI_N_HWINIT_STATE_CPU1_FLAG 0x10000000 +/* This register controls AACK delay, which is set when 2004 iBook/PowerBook + * is in low speed mode. + */ +#define UNI_N_AACK_DELAY 0x0100 +#define UNI_N_AACK_DELAY_ENABLE 0x00000001 + /* Uninorth 1.5 rev. has additional perf. monitor registers at 0xf00-0xf50 */ -- cgit v1.2.3 From 6340e7ba74ed8334a6a0505121c995a5baa70d7c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 22 Jun 2004 05:52:02 -0700 Subject: [PATCH] radeonfb: Fix panel detection on some laptops The code in radeonfb looking for the BIOS image currently uses the BIOS ROM if any, and falls back to the RAM image if not found. This is unfortunatly not correct for a bunch of laptops where the real panel data are only present in the RAM image. This works around this problem by preferring the RAM image on mobility chipsets. This is definitely not the best workaround, we need some arch support for linking the RAM image to the PCI ID (preferrably by having the arch snapshot it during boot, isolating us completely from the details of where this image is in memory). I'll see how we can get such an improvement later. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Linus Torvalds --- drivers/video/aty/radeon_base.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index aa01713469ff..69b19c22f68f 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -2268,9 +2268,17 @@ static int radeonfb_pci_register (struct pci_dev *pdev, /* * Map the BIOS ROM if any and retreive PLL parameters from - * either BIOS or Open Firmware + * the BIOS. We skip that on mobility chips as the real panel + * values we need aren't in the ROM but in the BIOS image in + * memory. This is definitely not the best meacnism though, + * we really need the arch code to tell us which is the "primary" + * video adapter to use the memory image (or better, the arch + * should provide us a copy of the BIOS image to shield us from + * archs who would store that elsewhere and/or could initialize + * more than one adapter during boot). */ - radeon_map_ROM(rinfo, pdev); + if (!rinfo->is_mobility) + radeon_map_ROM(rinfo, pdev); /* * On x86, the primary display on laptop may have it's BIOS @@ -2283,6 +2291,12 @@ static int radeonfb_pci_register (struct pci_dev *pdev, radeon_find_mem_vbios(rinfo); #endif /* __i386__ */ + /* If both above failed, try the BIOS ROM again for mobility + * chips + */ + if (rinfo->bios_seg == NULL && rinfo->is_mobility) + radeon_map_ROM(rinfo, pdev); + /* Get informations about the board's PLL */ radeon_get_pllinfo(rinfo); -- cgit v1.2.3 From 7a08473bfee8b94befd7b38333d747290668848a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 22 Jun 2004 05:52:14 -0700 Subject: [PATCH] Handle altivec assist exception properly This is the PPC64 counterpart of the PPC32 Altivec assist exception handler that went in recently. On PPC64 machines with Altivec (i.e. machines that use the PPC970 chip, such as the G5 powermac), the altivec floating-point instructions can operate in two modes: one where denormalized inputs or outputs are truncated to zero, and one where they aren't. In the latter mode the processor can take an exception when it encounters denormalized floating-point inputs or outputs rather than dealing with them in hardware. This patch adds code to deal properly with the exception, by emulating the instruction that caused the exception. Previously the kernel just switched the altivec unit into the truncate-to-zero mode, which works but is a bit gross. Fortunately there are only a limited set of altivec instructions which can generate the assist exception, so we don't have to emulate the whole altivec instruction set. Note that Altivec is Motorola's name for the PowerPC vector/SIMD instructions; IBM calls the same thing VMX, and currently only IBM makes 64-bit PowerPC CPU chips. Nevertheless, I have used the term Altivec in the PPC64 code for consistency with the PPC32 code. Signed-off-by: Paul Mackerras Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/Makefile | 2 + arch/ppc64/kernel/traps.c | 34 ++++- arch/ppc64/kernel/vecemu.c | 346 +++++++++++++++++++++++++++++++++++++++++++++ arch/ppc64/kernel/vector.S | 172 ++++++++++++++++++++++ include/asm-ppc64/system.h | 1 + 5 files changed, 553 insertions(+), 2 deletions(-) create mode 100644 arch/ppc64/kernel/vecemu.c create mode 100644 arch/ppc64/kernel/vector.S diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index c36dd89a4e3b..fda27888edd3 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -56,4 +56,6 @@ ifdef CONFIG_SMP obj-$(CONFIG_PPC_PMAC) += pmac_smp.o smp-tbsync.o endif +obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o + CFLAGS_ioctl32.o += -Ifs/ diff --git a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c index 593319735e5e..4de4982f58f3 100644 --- a/arch/ppc64/kernel/traps.c +++ b/arch/ppc64/kernel/traps.c @@ -544,9 +544,39 @@ AlignmentException(struct pt_regs *regs) void AltivecAssistException(struct pt_regs *regs) { + int err; + siginfo_t info; + + if (!user_mode(regs)) { + printk(KERN_EMERG "VMX/Altivec assist exception in kernel mode" + " at %lx\n", regs->nip); + die("Kernel VMX/Altivec assist exception", regs, SIGILL); + } + flush_altivec_to_thread(current); - /* XXX quick hack for now: set the non-Java bit in the VSCR */ - current->thread.vscr.u[3] |= 0x10000; + + err = emulate_altivec(regs); + if (err == 0) { + regs->nip += 4; /* skip emulated instruction */ + emulate_single_step(regs); + return; + } + + if (err == -EFAULT) { + /* got an error reading the instruction */ + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = SEGV_MAPERR; + info.si_addr = (void *) regs->nip; + force_sig_info(SIGSEGV, &info, current); + } else { + /* didn't recognize the instruction */ + /* XXX quick hack for now: set the non-Java bit in the VSCR */ + if (printk_ratelimit()) + printk(KERN_ERR "Unrecognized altivec instruction " + "in %s at %lx\n", current->comm, regs->nip); + current->thread.vscr.u[3] |= 0x10000; + } } #endif /* CONFIG_ALTIVEC */ diff --git a/arch/ppc64/kernel/vecemu.c b/arch/ppc64/kernel/vecemu.c new file mode 100644 index 000000000000..1430ef59279c --- /dev/null +++ b/arch/ppc64/kernel/vecemu.c @@ -0,0 +1,346 @@ +/* + * Routines to emulate some Altivec/VMX instructions, specifically + * those that can trap when given denormalized operands in Java mode. + */ +#include +#include +#include +#include +#include +#include + +/* Functions in vector.S */ +extern void vaddfp(vector128 *dst, vector128 *a, vector128 *b); +extern void vsubfp(vector128 *dst, vector128 *a, vector128 *b); +extern void vmaddfp(vector128 *dst, vector128 *a, vector128 *b, vector128 *c); +extern void vnmsubfp(vector128 *dst, vector128 *a, vector128 *b, vector128 *c); +extern void vrefp(vector128 *dst, vector128 *src); +extern void vrsqrtefp(vector128 *dst, vector128 *src); +extern void vexptep(vector128 *dst, vector128 *src); + +static unsigned int exp2s[8] = { + 0x800000, + 0x8b95c2, + 0x9837f0, + 0xa5fed7, + 0xb504f3, + 0xc5672a, + 0xd744fd, + 0xeac0c7 +}; + +/* + * Computes an estimate of 2^x. The `s' argument is the 32-bit + * single-precision floating-point representation of x. + */ +static unsigned int eexp2(unsigned int s) +{ + int exp, pwr; + unsigned int mant, frac; + + /* extract exponent field from input */ + exp = ((s >> 23) & 0xff) - 127; + if (exp > 7) { + /* check for NaN input */ + if (exp == 128 && (s & 0x7fffff) != 0) + return s | 0x400000; /* return QNaN */ + /* 2^-big = 0, 2^+big = +Inf */ + return (s & 0x80000000)? 0: 0x7f800000; /* 0 or +Inf */ + } + if (exp < -23) + return 0x3f800000; /* 1.0 */ + + /* convert to fixed point integer in 9.23 representation */ + pwr = (s & 0x7fffff) | 0x800000; + if (exp > 0) + pwr <<= exp; + else + pwr >>= -exp; + if (s & 0x80000000) + pwr = -pwr; + + /* extract integer part, which becomes exponent part of result */ + exp = (pwr >> 23) + 126; + if (exp >= 254) + return 0x7f800000; + if (exp < -23) + return 0; + + /* table lookup on top 3 bits of fraction to get mantissa */ + mant = exp2s[(pwr >> 20) & 7]; + + /* linear interpolation using remaining 20 bits of fraction */ + asm("mulhwu %0,%1,%2" : "=r" (frac) + : "r" (pwr << 12), "r" (0x172b83ff)); + asm("mulhwu %0,%1,%2" : "=r" (frac) : "r" (frac), "r" (mant)); + mant += frac; + + if (exp >= 0) + return mant + (exp << 23); + + /* denormalized result */ + exp = -exp; + mant += 1 << (exp - 1); + return mant >> exp; +} + +/* + * Computes an estimate of log_2(x). The `s' argument is the 32-bit + * single-precision floating-point representation of x. + */ +static unsigned int elog2(unsigned int s) +{ + int exp, mant, lz, frac; + + exp = s & 0x7f800000; + mant = s & 0x7fffff; + if (exp == 0x7f800000) { /* Inf or NaN */ + if (mant != 0) + s |= 0x400000; /* turn NaN into QNaN */ + return s; + } + if ((exp | mant) == 0) /* +0 or -0 */ + return 0xff800000; /* return -Inf */ + + if (exp == 0) { + /* denormalized */ + asm("cntlzw %0,%1" : "=r" (lz) : "r" (mant)); + mant <<= lz - 8; + exp = (-118 - lz) << 23; + } else { + mant |= 0x800000; + exp -= 127 << 23; + } + + if (mant >= 0xb504f3) { /* 2^0.5 * 2^23 */ + exp |= 0x400000; /* 0.5 * 2^23 */ + asm("mulhwu %0,%1,%2" : "=r" (mant) + : "r" (mant), "r" (0xb504f334)); /* 2^-0.5 * 2^32 */ + } + if (mant >= 0x9837f0) { /* 2^0.25 * 2^23 */ + exp |= 0x200000; /* 0.25 * 2^23 */ + asm("mulhwu %0,%1,%2" : "=r" (mant) + : "r" (mant), "r" (0xd744fccb)); /* 2^-0.25 * 2^32 */ + } + if (mant >= 0x8b95c2) { /* 2^0.125 * 2^23 */ + exp |= 0x100000; /* 0.125 * 2^23 */ + asm("mulhwu %0,%1,%2" : "=r" (mant) + : "r" (mant), "r" (0xeac0c6e8)); /* 2^-0.125 * 2^32 */ + } + if (mant > 0x800000) { /* 1.0 * 2^23 */ + /* calculate (mant - 1) * 1.381097463 */ + /* 1.381097463 == 0.125 / (2^0.125 - 1) */ + asm("mulhwu %0,%1,%2" : "=r" (frac) + : "r" ((mant - 0x800000) << 1), "r" (0xb0c7cd3a)); + exp += frac; + } + s = exp & 0x80000000; + if (exp != 0) { + if (s) + exp = -exp; + asm("cntlzw %0,%1" : "=r" (lz) : "r" (exp)); + lz = 8 - lz; + if (lz > 0) + exp >>= lz; + else if (lz < 0) + exp <<= -lz; + s += ((lz + 126) << 23) + exp; + } + return s; +} + +#define VSCR_SAT 1 + +static int ctsxs(unsigned int x, int scale, unsigned int *vscrp) +{ + int exp, mant; + + exp = (x >> 23) & 0xff; + mant = x & 0x7fffff; + if (exp == 255 && mant != 0) + return 0; /* NaN -> 0 */ + exp = exp - 127 + scale; + if (exp < 0) + return 0; /* round towards zero */ + if (exp >= 31) { + /* saturate, unless the result would be -2^31 */ + if (x + (scale << 23) != 0xcf000000) + *vscrp |= VSCR_SAT; + return (x & 0x80000000)? 0x80000000: 0x7fffffff; + } + mant |= 0x800000; + mant = (mant << 7) >> (30 - exp); + return (x & 0x80000000)? -mant: mant; +} + +static unsigned int ctuxs(unsigned int x, int scale, unsigned int *vscrp) +{ + int exp; + unsigned int mant; + + exp = (x >> 23) & 0xff; + mant = x & 0x7fffff; + if (exp == 255 && mant != 0) + return 0; /* NaN -> 0 */ + exp = exp - 127 + scale; + if (exp < 0) + return 0; /* round towards zero */ + if (x & 0x80000000) { + /* negative => saturate to 0 */ + *vscrp |= VSCR_SAT; + return 0; + } + if (exp >= 32) { + /* saturate */ + *vscrp |= VSCR_SAT; + return 0xffffffff; + } + mant |= 0x800000; + mant = (mant << 8) >> (31 - exp); + return mant; +} + +/* Round to floating integer, towards 0 */ +static unsigned int rfiz(unsigned int x) +{ + int exp; + + exp = ((x >> 23) & 0xff) - 127; + if (exp == 128 && (x & 0x7fffff) != 0) + return x | 0x400000; /* NaN -> make it a QNaN */ + if (exp >= 23) + return x; /* it's an integer already (or Inf) */ + if (exp < 0) + return x & 0x80000000; /* |x| < 1.0 rounds to 0 */ + return x & ~(0x7fffff >> exp); +} + +/* Round to floating integer, towards +/- Inf */ +static unsigned int rfii(unsigned int x) +{ + int exp, mask; + + exp = ((x >> 23) & 0xff) - 127; + if (exp == 128 && (x & 0x7fffff) != 0) + return x | 0x400000; /* NaN -> make it a QNaN */ + if (exp >= 23) + return x; /* it's an integer already (or Inf) */ + if ((x & 0x7fffffff) == 0) + return x; /* +/-0 -> +/-0 */ + if (exp < 0) + /* 0 < |x| < 1.0 rounds to +/- 1.0 */ + return (x & 0x80000000) | 0x3f800000; + mask = 0x7fffff >> exp; + /* mantissa overflows into exponent - that's OK, + it can't overflow into the sign bit */ + return (x + mask) & ~mask; +} + +/* Round to floating integer, to nearest */ +static unsigned int rfin(unsigned int x) +{ + int exp, half; + + exp = ((x >> 23) & 0xff) - 127; + if (exp == 128 && (x & 0x7fffff) != 0) + return x | 0x400000; /* NaN -> make it a QNaN */ + if (exp >= 23) + return x; /* it's an integer already (or Inf) */ + if (exp < -1) + return x & 0x80000000; /* |x| < 0.5 -> +/-0 */ + if (exp == -1) + /* 0.5 <= |x| < 1.0 rounds to +/- 1.0 */ + return (x & 0x80000000) | 0x3f800000; + half = 0x400000 >> exp; + /* add 0.5 to the magnitude and chop off the fraction bits */ + return (x + half) & ~(0x7fffff >> exp); +} + +int +emulate_altivec(struct pt_regs *regs) +{ + unsigned int instr, i; + unsigned int va, vb, vc, vd; + vector128 *vrs; + + if (get_user(instr, (unsigned int *) regs->nip)) + return -EFAULT; + if ((instr >> 26) != 4) + return -EINVAL; /* not an altivec instruction */ + vd = (instr >> 21) & 0x1f; + va = (instr >> 16) & 0x1f; + vb = (instr >> 11) & 0x1f; + vc = (instr >> 6) & 0x1f; + + vrs = current->thread.vr; + switch (instr & 0x3f) { + case 10: + switch (vc) { + case 0: /* vaddfp */ + vaddfp(&vrs[vd], &vrs[va], &vrs[vb]); + break; + case 1: /* vsubfp */ + vsubfp(&vrs[vd], &vrs[va], &vrs[vb]); + break; + case 4: /* vrefp */ + vrefp(&vrs[vd], &vrs[vb]); + break; + case 5: /* vrsqrtefp */ + vrsqrtefp(&vrs[vd], &vrs[vb]); + break; + case 6: /* vexptefp */ + for (i = 0; i < 4; ++i) + vrs[vd].u[i] = eexp2(vrs[vb].u[i]); + break; + case 7: /* vlogefp */ + for (i = 0; i < 4; ++i) + vrs[vd].u[i] = elog2(vrs[vb].u[i]); + break; + case 8: /* vrfin */ + for (i = 0; i < 4; ++i) + vrs[vd].u[i] = rfin(vrs[vb].u[i]); + break; + case 9: /* vrfiz */ + for (i = 0; i < 4; ++i) + vrs[vd].u[i] = rfiz(vrs[vb].u[i]); + break; + case 10: /* vrfip */ + for (i = 0; i < 4; ++i) { + u32 x = vrs[vb].u[i]; + x = (x & 0x80000000)? rfiz(x): rfii(x); + vrs[vd].u[i] = x; + } + break; + case 11: /* vrfim */ + for (i = 0; i < 4; ++i) { + u32 x = vrs[vb].u[i]; + x = (x & 0x80000000)? rfii(x): rfiz(x); + vrs[vd].u[i] = x; + } + break; + case 14: /* vctuxs */ + for (i = 0; i < 4; ++i) + vrs[vd].u[i] = ctuxs(vrs[vb].u[i], va, + ¤t->thread.vscr.u[3]); + break; + case 15: /* vctsxs */ + for (i = 0; i < 4; ++i) + vrs[vd].u[i] = ctsxs(vrs[vb].u[i], va, + ¤t->thread.vscr.u[3]); + break; + default: + return -EINVAL; + } + break; + case 46: /* vmaddfp */ + vmaddfp(&vrs[vd], &vrs[va], &vrs[vb], &vrs[vc]); + break; + case 47: /* vnmsubfp */ + vnmsubfp(&vrs[vd], &vrs[va], &vrs[vb], &vrs[vc]); + break; + default: + return -EINVAL; + } + + return 0; +} diff --git a/arch/ppc64/kernel/vector.S b/arch/ppc64/kernel/vector.S new file mode 100644 index 000000000000..940cd7287346 --- /dev/null +++ b/arch/ppc64/kernel/vector.S @@ -0,0 +1,172 @@ +#include +#include + +/* + * The routines below are in assembler so we can closely control the + * usage of floating-point registers. These routines must be called + * with preempt disabled. + */ + .section ".toc","aw" +fpzero: + .tc FD_0_0[TC],0 +fpone: + .tc FD_3ff00000_0[TC],0x3ff0000000000000 /* 1.0 */ +fphalf: + .tc FD_3fe00000_0[TC],0x3fe0000000000000 /* 0.5 */ + + .text +/* + * Internal routine to enable floating point and set FPSCR to 0. + * Don't call it from C; it doesn't use the normal calling convention. + */ +fpenable: + mfmsr r10 + ori r11,r10,MSR_FP + mtmsr r11 + isync + stfd fr31,-8(r1) + stfd fr0,-16(r1) + stfd fr1,-24(r1) + mffs fr31 + lfd fr1,fpzero@toc(r2) + mtfsf 0xff,fr1 + blr + +fpdisable: + mtlr r12 + mtfsf 0xff,fr31 + lfd fr1,-24(r1) + lfd fr0,-16(r1) + lfd fr31,-8(r1) + mtmsr r10 + isync + blr + +/* + * Vector add, floating point. + */ +_GLOBAL(vaddfp) + mflr r12 + bl fpenable + li r0,4 + mtctr r0 + li r6,0 +1: lfsx fr0,r4,r6 + lfsx fr1,r5,r6 + fadds fr0,fr0,fr1 + stfsx fr0,r3,r6 + addi r6,r6,4 + bdnz 1b + b fpdisable + +/* + * Vector subtract, floating point. + */ +_GLOBAL(vsubfp) + mflr r12 + bl fpenable + li r0,4 + mtctr r0 + li r6,0 +1: lfsx fr0,r4,r6 + lfsx fr1,r5,r6 + fsubs fr0,fr0,fr1 + stfsx fr0,r3,r6 + addi r6,r6,4 + bdnz 1b + b fpdisable + +/* + * Vector multiply and add, floating point. + */ +_GLOBAL(vmaddfp) + mflr r12 + bl fpenable + stfd fr2,-32(r1) + li r0,4 + mtctr r0 + li r7,0 +1: lfsx fr0,r4,r7 + lfsx fr1,r5,r7 + lfsx fr2,r6,r7 + fmadds fr0,fr0,fr1,fr2 + stfsx fr0,r3,r7 + addi r7,r7,4 + bdnz 1b + lfd fr2,-32(r1) + b fpdisable + +/* + * Vector negative multiply and subtract, floating point. + */ +_GLOBAL(vnmsubfp) + mflr r12 + bl fpenable + stfd fr2,-32(r1) + li r0,4 + mtctr r0 + li r7,0 +1: lfsx fr0,r4,r7 + lfsx fr1,r5,r7 + lfsx fr2,r6,r7 + fnmsubs fr0,fr0,fr1,fr2 + stfsx fr0,r3,r7 + addi r7,r7,4 + bdnz 1b + lfd fr2,-32(r1) + b fpdisable + +/* + * Vector reciprocal estimate. We just compute 1.0/x. + * r3 -> destination, r4 -> source. + */ +_GLOBAL(vrefp) + mflr r12 + bl fpenable + li r0,4 + lfd fr1,fpone@toc(r2) + mtctr r0 + li r6,0 +1: lfsx fr0,r4,r6 + fdivs fr0,fr1,fr0 + stfsx fr0,r3,r6 + addi r6,r6,4 + bdnz 1b + b fpdisable + +/* + * Vector reciprocal square-root estimate, floating point. + * We use the frsqrte instruction for the initial estimate followed + * by 2 iterations of Newton-Raphson to get sufficient accuracy. + * r3 -> destination, r4 -> source. + */ +_GLOBAL(vrsqrtefp) + mflr r12 + bl fpenable + stfd fr2,-32(r1) + stfd fr3,-40(r1) + stfd fr4,-48(r1) + stfd fr5,-56(r1) + li r0,4 + lfd fr4,fpone@toc(r2) + lfd fr5,fphalf@toc(r2) + mtctr r0 + li r6,0 +1: lfsx fr0,r4,r6 + frsqrte fr1,fr0 /* r = frsqrte(s) */ + fmuls fr3,fr1,fr0 /* r * s */ + fmuls fr2,fr1,fr5 /* r * 0.5 */ + fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */ + fmadds fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */ + fmuls fr3,fr1,fr0 /* r * s */ + fmuls fr2,fr1,fr5 /* r * 0.5 */ + fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */ + fmadds fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */ + stfsx fr1,r3,r6 + addi r6,r6,4 + bdnz 1b + lfd fr5,-56(r1) + lfd fr4,-48(r1) + lfd fr3,-40(r1) + lfd fr2,-32(r1) + b fpdisable diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h index 67ac484a14cd..06ecd1bb285d 100644 --- a/include/asm-ppc64/system.h +++ b/include/asm-ppc64/system.h @@ -116,6 +116,7 @@ extern void enable_kernel_fp(void); extern void giveup_altivec(struct task_struct *); extern void disable_kernel_altivec(void); extern void enable_kernel_altivec(void); +extern int emulate_altivec(struct pt_regs *); extern void cvt_fd(float *from, double *to, unsigned long *fpscr); extern void cvt_df(double *from, float *to, unsigned long *fpscr); -- cgit v1.2.3 From f4897eb32ff3d6629e53f67e30d88bb8736b7148 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 22 Jun 2004 05:53:47 -0700 Subject: [PATCH] ppc32: Support for new Apple laptop models This adds sound support for some of the newer PowerBooks. It appears that this chip supports the AWACS sample rates, but has a snapper-style mixer. Tested and works on my PowerBook5,4. Signed-off-by: Jesse Barnes Signed-off-by: Linus Torvalds --- sound/ppc/pmac.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 95dfeef913f1..4f80fec4f5c7 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -931,6 +931,13 @@ static int __init snd_pmac_detect(pmac_t *chip) chip->freq_table = tumbler_freqs; chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */ } + if (device_is_compatible(sound, "AOAKeylargo")) { + /* Seems to support the stock AWACS frequencies, but has + a snapper mixer */ + chip->model = PMAC_SNAPPER; + // chip->can_byte_swap = 0; /* FIXME: check this */ + chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */ + } prop = (unsigned int *)get_property(sound, "device-id", 0); if (prop) chip->device_id = *prop; -- cgit v1.2.3 From 5b447af241fb585dba442bf81c0a974076021f84 Mon Sep 17 00:00:00 2001 From: Hideaki Yoshifuji Date: Tue, 22 Jun 2004 17:44:19 -0700 Subject: [NETFILTER]: Fix iptable_raw.c build with older gcc. --- net/ipv4/netfilter/iptable_raw.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index 0fd648ac0df3..63c6254607b3 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -54,7 +54,9 @@ static struct }, .target = { .target = { - .u.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), + .u = { + .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), + }, }, .verdict = -NF_ACCEPT - 1, }, @@ -68,7 +70,9 @@ static struct }, .target = { .target = { - .u.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), + .u = { + .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), + }, }, .verdict = -NF_ACCEPT - 1, }, @@ -82,9 +86,11 @@ static struct }, .target = { .target = { - .u.user = { - .target_size = IPT_ALIGN(sizeof(struct ipt_error_target)), - .name = IPT_ERROR_TARGET, + .u = { + .user = { + .target_size = IPT_ALIGN(sizeof(struct ipt_error_target)), + .name = IPT_ERROR_TARGET, + }, }, }, .errorname = "ERROR", -- cgit v1.2.3 From 28908331d2b9cb76da6cb87242e264387ce49682 Mon Sep 17 00:00:00 2001 From: Alexander Viro Date: Tue, 22 Jun 2004 20:55:18 -0700 Subject: [PATCH] bug in V-link handling (arch/i386/pci/irq.c) Via southbridges use register 0x3c of the on-board devices (USB and AC97) to control interrupt routing for those. In drivers/pci/quirks.c we set it correctly (dev->irq & 15). However, in pirq_enable_irq() where the second half of that stuff lives, we forget to apply the mask. That's what causes problems with ioapic on via motherboards in 2.6. One-liner below ACKed by Alan, verified on via-based boxen here, obviously doesn't affect non-via ones (we only set interrupt_line_quirk for via chipsets). --- arch/i386/pci/irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index 08314fa39f24..70e12d2e1d8a 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -1030,7 +1030,7 @@ int pirq_enable_irq(struct pci_dev *dev) /* VIA bridges use interrupt line for apic/pci steering across the V-Link */ else if (interrupt_line_quirk) - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq & 15); return 0; } -- cgit v1.2.3