From d8a22dd28aef1679d249dcbad0c3addfdba7b658 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 8 Jul 2003 09:37:00 -0500 Subject: [PATCH] consistant names for device model related struct members currently the embedded struct devices and class devices have totally irregular and sometimes confusing (sdev_driverfs_dev) names. Name them consistanly s{dev,host}_{class,gen}dev. --- include/scsi/scsi_device.h | 7 +++---- include/scsi/scsi_host.h | 17 +++++++---------- 2 files changed, 10 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index c49c124fde74..de5ff9fd6c4a 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -11,8 +11,6 @@ struct scsi_mode_data; struct scsi_device { - struct class_device sdev_classdev; - struct list_head siblings; /* list of all devices on this host */ struct list_head same_target_siblings; /* just the devices sharing same target id */ struct Scsi_Host *host; @@ -86,10 +84,11 @@ struct scsi_device { unsigned int max_device_blocked; /* what device_blocked counts down from */ #define SCSI_DEFAULT_DEVICE_BLOCKED 3 - struct device sdev_driverfs_dev; + struct device sdev_gendev; + struct class_device sdev_classdev; }; #define to_scsi_device(d) \ - container_of(d, struct scsi_device, sdev_driverfs_dev) + container_of(d, struct scsi_device, sdev_gendev) extern struct scsi_device *scsi_add_device(struct Scsi_Host *, uint, uint, uint); diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index d92dc75d131d..327e58f4a7de 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -442,12 +442,6 @@ struct Scsi_Host { */ unsigned int max_host_blocked; - /* - * Support for sysfs - */ - struct device host_gendev; - struct class_device class_dev; - /* legacy crap */ unsigned long base; unsigned long io_port; @@ -455,6 +449,9 @@ struct Scsi_Host { unsigned char dma_channel; unsigned int irq; + /* ldm bits */ + struct device shost_gendev; + struct class_device shost_classdev; /* * List of hosts per template. @@ -474,9 +471,9 @@ struct Scsi_Host { __attribute__ ((aligned (sizeof(unsigned long)))); }; #define dev_to_shost(d) \ - container_of(d, struct Scsi_Host, host_gendev) + container_of(d, struct Scsi_Host, shost_gendev) #define class_to_shost(d) \ - container_of(d, struct Scsi_Host, class_dev) + container_of(d, struct Scsi_Host, shost_classdev) extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int); extern int scsi_add_host(struct Scsi_Host *, struct device *); @@ -495,12 +492,12 @@ static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock) static inline void scsi_set_device(struct Scsi_Host *shost, struct device *dev) { - shost->host_gendev.parent = dev; + shost->shost_gendev.parent = dev; } static inline struct device *scsi_get_device(struct Scsi_Host *shost) { - return shost->host_gendev.parent; + return shost->shost_gendev.parent; } extern void scsi_sysfs_release_attributes(struct scsi_host_template *); -- cgit v1.2.3 From a1b6bcff325de4e99f3855dacc84abe087c2c666 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 8 Jul 2003 09:38:24 -0500 Subject: [PATCH] rework shost/sdev attribute handling I've finally found some time to look over the per-driver sdev/shost attribute handling and I'm not so happy with it. First it adds new writeable variables to the host templates which is otherwise almost readonly, the other thing is that it needs per-template procedure calls in the drivers wheras we have moved away from that. Also it looks a bit coplicated :) I've attached a patch below that makes the attributes handling a lot simpler. Details: - the shost_attrs and sdev_attrs in the host template are now used to store the attributes overriden or added by the LLDD. - the midlayer creates those first and then the generic attributes that haven't been overridded and the other way around. - the host attributes are properly unregistered now and don't leak anymore. Unlike the first patch the attribute inheritance is back. --- drivers/scsi/53c700.c | 25 ++--- drivers/scsi/NCR_D700.c | 1 - drivers/scsi/NCR_Q720.c | 1 - drivers/scsi/hosts.c | 6 -- drivers/scsi/lasi700.c | 1 - drivers/scsi/scsi.h | 5 - drivers/scsi/scsi_priv.h | 5 - drivers/scsi/scsi_sysfs.c | 257 ++++++++++++++++++++-------------------------- include/scsi/scsi_host.h | 6 +- 9 files changed, 120 insertions(+), 187 deletions(-) (limited to 'include') diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 45d15d377c2f..1ac43ff33884 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -172,7 +172,7 @@ STATIC void NCR_700_chip_reset(struct Scsi_Host *host); STATIC int NCR_700_slave_configure(Scsi_Device *SDpnt); STATIC void NCR_700_slave_destroy(Scsi_Device *SDpnt); -static struct device_attribute **NCR_700_dev_attrs = NULL; +STATIC struct device_attribute *NCR_700_dev_attrs[]; static char *NCR_700_phase[] = { "", @@ -2027,25 +2027,12 @@ static struct device_attribute NCR_700_active_tags_attr = { .show = NCR_700_show_active_tags, }; -STATIC int __init -NCR_700_init(void) -{ - scsi_sysfs_modify_sdev_attribute(&NCR_700_dev_attrs, - &NCR_700_queue_depth_attr); - scsi_sysfs_modify_sdev_attribute(&NCR_700_dev_attrs, - &NCR_700_active_tags_attr); - return 0; -} - -/* NULL exit routine to keep modutils happy */ -STATIC void __exit -NCR_700_exit(void) -{ -} +STATIC struct device_attribute *NCR_700_dev_attrs[] = { + &NCR_700_queue_depth_attr, + &NCR_700_active_tags_attr, + NULL, +}; EXPORT_SYMBOL(NCR_700_detect); EXPORT_SYMBOL(NCR_700_release); EXPORT_SYMBOL(NCR_700_intr); - -module_init(NCR_700_init); -module_exit(NCR_700_exit); diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c index f1eb7aaf22e4..0d7a71abee9a 100644 --- a/drivers/scsi/NCR_D700.c +++ b/drivers/scsi/NCR_D700.c @@ -387,7 +387,6 @@ static int __init NCR_D700_init(void) static void __exit NCR_D700_exit(void) { mca_unregister_driver(&NCR_D700_driver); - scsi_sysfs_release_attributes(&NCR_D700_driver_template); } module_init(NCR_D700_init); diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c index c45c353cc9ad..5a3fcbeeed1a 100644 --- a/drivers/scsi/NCR_Q720.c +++ b/drivers/scsi/NCR_Q720.c @@ -347,7 +347,6 @@ static void __exit NCR_Q720_exit(void) { mca_unregister_driver(&NCR_Q720_driver); - //scsi_sysfs_release_attributes(&NCR_Q720_driver_template); } module_init(NCR_Q720_init); diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index ccfb10644a3b..969f8db554b2 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -151,12 +151,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) dump_stack(); } - /* if its not set in the template, use the default */ - if (!sht->shost_attrs) - sht->shost_attrs = scsi_sysfs_shost_attrs; - if (!sht->sdev_attrs) - sht->sdev_attrs = scsi_sysfs_sdev_attrs; - shost = kmalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask); if (!shost) return NULL; diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c index b5c4b51b3cf3..5acab4b2124d 100644 --- a/drivers/scsi/lasi700.c +++ b/drivers/scsi/lasi700.c @@ -165,7 +165,6 @@ static void __exit lasi700_exit(void) { unregister_parisc_driver(&lasi700_driver); - scsi_sysfs_release_attributes(&lasi700_template); } module_init(lasi700_init); diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h index 3ff36ab84744..5d2e6d8aec01 100644 --- a/drivers/scsi/scsi.h +++ b/drivers/scsi/scsi.h @@ -174,11 +174,6 @@ extern const char *scsi_extd_sense_format(unsigned char, unsigned char); #define SCSI_MLQUEUE_DEVICE_BUSY 0x1056 #define SCSI_MLQUEUE_EH_RETRY 0x1057 -extern int scsi_sysfs_modify_sdev_attribute(struct device_attribute ***dev_attrs, - struct device_attribute *attr); -extern int scsi_sysfs_modify_shost_attribute(struct class_device_attribute ***class_attrs, - struct class_device_attribute *attr); - /* * Legacy dma direction interfaces. * diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 6346005e64c7..e8f4d1ff6559 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -117,11 +117,6 @@ extern void scsi_sysfs_remove_host(struct Scsi_Host *); extern int scsi_sysfs_register(void); extern void scsi_sysfs_unregister(void); -/* definitions for the linker default sections covering the host - * class and device attributes */ -extern struct class_device_attribute *scsi_sysfs_shost_attrs[]; -extern struct device_attribute *scsi_sysfs_sdev_attrs[]; - extern struct class shost_class; extern struct bus_type scsi_bus_type; diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 5cb7d844f624..3801b768c733 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -45,7 +45,7 @@ shost_rd_attr(cmd_per_lun, "%hd\n"); shost_rd_attr(sg_tablesize, "%hu\n"); shost_rd_attr(unchecked_isa_dma, "%d\n"); -struct class_device_attribute *scsi_sysfs_shost_attrs[] = { +static struct class_device_attribute *scsi_sysfs_shost_attrs[] = { &class_device_attr_unique_id, &class_device_attr_host_busy, &class_device_attr_cmd_per_lun, @@ -204,7 +204,7 @@ store_rescan_field (struct device *dev, const char *buf, size_t count) static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field) /* Default template for device attributes. May NOT be modified */ -struct device_attribute *scsi_sysfs_sdev_attrs[] = { +static struct device_attribute *scsi_sysfs_sdev_attrs[] = { &dev_attr_device_blocked, &dev_attr_queue_depth, &dev_attr_type, @@ -228,6 +228,42 @@ static void scsi_device_release(struct device *dev) scsi_free_sdev(sdev); } +static struct device_attribute *attr_overridden( + struct device_attribute **attrs, + struct device_attribute *attr) +{ + int i; + + if (!attrs) + return NULL; + for (i = 0; attrs[i]; i++) + if (!strcmp(attrs[i]->attr.name, attr->attr.name)) + return attrs[i]; + return NULL; +} + +static int attr_add(struct device *dev, struct device_attribute *attr) +{ + struct device_attribute *base_attr; + + /* + * Spare the caller from having to copy things it's not interested in. + */ + base_attr = attr_overridden(scsi_sysfs_sdev_attrs, attr); + if (base_attr) { + /* extend permissions */ + attr->attr.mode |= base_attr->attr.mode; + + /* override null show/store with default */ + if (!attr->show) + attr->show = base_attr->show; + if (!attr->store) + attr->store = base_attr->store; + } + + return device_create_file(dev, attr); +} + /** * scsi_device_register - register a scsi device with the scsi bus * @sdev: scsi_device to register @@ -264,12 +300,24 @@ int scsi_device_register(struct scsi_device *sdev) return error; } - for (i = 0; !error && sdev->host->hostt->sdev_attrs[i] != NULL; i++) - error = device_create_file(&sdev->sdev_gendev, - sdev->host->hostt->sdev_attrs[i]); - - if (error) - scsi_device_unregister(sdev); + if (sdev->host->hostt->sdev_attrs) { + for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) { + error = attr_add(&sdev->sdev_gendev, + sdev->host->hostt->sdev_attrs[i]); + if (error) + scsi_device_unregister(sdev); + } + } + + for (i = 0; scsi_sysfs_sdev_attrs[i]; i++) { + if (!attr_overridden(sdev->host->hostt->sdev_attrs, + scsi_sysfs_sdev_attrs[i])) { + error = device_create_file(&sdev->sdev_gendev, + scsi_sysfs_sdev_attrs[i]); + if (error) + scsi_device_unregister(sdev); + } + } return error; } @@ -280,10 +328,6 @@ int scsi_device_register(struct scsi_device *sdev) **/ void scsi_device_unregister(struct scsi_device *sdev) { - int i; - - for (i = 0; sdev->host->hostt->sdev_attrs[i] != NULL; i++) - device_remove_file(&sdev->sdev_gendev, sdev->host->hostt->sdev_attrs[i]); class_device_unregister(&sdev->sdev_classdev); device_unregister(&sdev->sdev_gendev); } @@ -329,6 +373,43 @@ void scsi_sysfs_init_host(struct Scsi_Host *shost) shost->host_no); } +static struct class_device_attribute *class_attr_overridden( + struct class_device_attribute **attrs, + struct class_device_attribute *attr) +{ + int i; + + if (!attrs) + return NULL; + for (i = 0; attrs[i]; i++) + if (!strcmp(attrs[i]->attr.name, attr->attr.name)) + return attrs[i]; + return NULL; +} + +static int class_attr_add(struct class_device *classdev, + struct class_device_attribute *attr) +{ + struct class_device_attribute *base_attr; + + /* + * Spare the caller from having to copy things it's not interested in. + */ + base_attr = class_attr_overridden(scsi_sysfs_shost_attrs, attr); + if (base_attr) { + /* extend permissions */ + attr->attr.mode |= base_attr->attr.mode; + + /* override null show/store with default */ + if (!attr->show) + attr->show = base_attr->show; + if (!attr->store) + attr->store = base_attr->store; + } + + return class_device_create_file(classdev, attr); +} + /** * scsi_sysfs_add_host - add scsi host to subsystem * @shost: scsi host struct to add to subsystem @@ -336,7 +417,7 @@ void scsi_sysfs_init_host(struct Scsi_Host *shost) **/ int scsi_sysfs_add_host(struct Scsi_Host *shost, struct device *dev) { - int i, error; + int error, i; if (!shost->shost_gendev.parent) shost->shost_gendev.parent = dev ? dev : &legacy_bus; @@ -349,11 +430,24 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost, struct device *dev) if (error) goto clean_device; - for (i = 0; !error && shost->hostt->shost_attrs[i] != NULL; i++) - error = class_device_create_file(&shost->shost_classdev, - shost->hostt->shost_attrs[i]); - if (error) - goto clean_class; + if (shost->hostt->shost_attrs) { + for (i = 0; shost->hostt->shost_attrs[i]; i++) { + error = class_attr_add(&shost->shost_classdev, + shost->hostt->shost_attrs[i]); + if (error) + goto clean_class; + } + } + + for (i = 0; scsi_sysfs_shost_attrs[i]; i++) { + if (!class_attr_overridden(shost->hostt->shost_attrs, + scsi_sysfs_shost_attrs[i])) { + error = class_device_create_file(&shost->shost_classdev, + scsi_sysfs_shost_attrs[i]); + if (error) + goto clean_class; + } + } return error; @@ -374,130 +468,3 @@ void scsi_sysfs_remove_host(struct Scsi_Host *shost) class_device_del(&shost->shost_classdev); device_del(&shost->shost_gendev); } - -/** scsi_sysfs_modify_shost_attribute - modify or add a host class attribute - * - * @class_attrs:host class attribute list to be added to or modified - * @attr: individual attribute to change or added - * - * returns zero if successful or error if not - **/ -int scsi_sysfs_modify_shost_attribute( - struct class_device_attribute ***class_attrs, - struct class_device_attribute *attr) -{ - int modify = -1; - int num_attrs; - - if(*class_attrs == NULL) - *class_attrs = scsi_sysfs_shost_attrs; - - for(num_attrs=0; (*class_attrs)[num_attrs] != NULL; num_attrs++) - if(strcmp((*class_attrs)[num_attrs]->attr.name, - attr->attr.name) == 0) - modify = num_attrs; - - if(*class_attrs == scsi_sysfs_shost_attrs || modify < 0) { - /* note: need space for null at the end as well */ - struct class_device_attribute **tmp_attrs = - kmalloc(sizeof(*tmp_attrs) * - (num_attrs + (modify >= 0 ? 1 : 2)), - GFP_KERNEL); - if(tmp_attrs == NULL) - return -ENOMEM; - memcpy(tmp_attrs, *class_attrs, sizeof(*tmp_attrs) * - (num_attrs + 1)); - if(*class_attrs != scsi_sysfs_shost_attrs) - kfree(*class_attrs); - *class_attrs = tmp_attrs; - } - if(modify >= 0) { - /* spare the caller from having to copy things it's - * not interested in */ - struct class_device_attribute *old_attr = - (*class_attrs)[modify]; - /* extend permissions */ - attr->attr.mode |= old_attr->attr.mode; - - /* override null show/store with default */ - if(attr->show == NULL) - attr->show = old_attr->show; - if(attr->store == NULL) - attr->store = old_attr->store; - (*class_attrs)[modify] = attr; - } else { - (*class_attrs)[num_attrs++] = attr; - (*class_attrs)[num_attrs] = NULL; - } - - return 0; -} -EXPORT_SYMBOL(scsi_sysfs_modify_shost_attribute); - -/** scsi_sysfs_modify_sdev_attribute - modify or add a host device attribute - * - * @dev_attrs: pointer to the attribute list to be added to or modified - * @attr: individual attribute to change or added - * - * returns zero if successful or error if not - **/ -int scsi_sysfs_modify_sdev_attribute(struct device_attribute ***dev_attrs, - struct device_attribute *attr) -{ - int modify = -1; - int num_attrs; - - if(*dev_attrs == NULL) - *dev_attrs = scsi_sysfs_sdev_attrs; - - for(num_attrs=0; (*dev_attrs)[num_attrs] != NULL; num_attrs++) - if(strcmp((*dev_attrs)[num_attrs]->attr.name, - attr->attr.name) == 0) - modify = num_attrs; - - if(*dev_attrs == scsi_sysfs_sdev_attrs || modify < 0) { - /* note: need space for null at the end as well */ - struct device_attribute **tmp_attrs = - kmalloc(sizeof(*tmp_attrs) * - (num_attrs + (modify >= 0 ? 1 : 2)), - GFP_KERNEL); - if(tmp_attrs == NULL) - return -ENOMEM; - memcpy(tmp_attrs, *dev_attrs, sizeof(*tmp_attrs) * - (num_attrs + 1)); - if(*dev_attrs != scsi_sysfs_sdev_attrs) - kfree(*dev_attrs); - *dev_attrs = tmp_attrs; - } - if(modify >= 0) { - /* spare the caller from having to copy things it's - * not interested in */ - struct device_attribute *old_attr = - (*dev_attrs)[modify]; - /* extend permissions */ - attr->attr.mode |= old_attr->attr.mode; - - /* override null show/store with default */ - if(attr->show == NULL) - attr->show = old_attr->show; - if(attr->store == NULL) - attr->store = old_attr->store; - (*dev_attrs)[modify] = attr; - } else { - (*dev_attrs)[num_attrs++] = attr; - (*dev_attrs)[num_attrs] = NULL; - } - - return 0; -} -EXPORT_SYMBOL(scsi_sysfs_modify_sdev_attribute); - -void scsi_sysfs_release_attributes(struct scsi_host_template *hostt) -{ - if(hostt->sdev_attrs != scsi_sysfs_sdev_attrs) - kfree(hostt->sdev_attrs); - - if(hostt->shost_attrs != scsi_sysfs_shost_attrs) - kfree(hostt->shost_attrs); -} -EXPORT_SYMBOL(scsi_sysfs_release_attributes); diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 327e58f4a7de..1b4ea934947f 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -329,12 +329,12 @@ struct scsi_host_template { #define SCSI_DEFAULT_HOST_BLOCKED 7 /* - * Pointer to the sysfs class properties for this host + * Pointer to the sysfs class properties for this host, NULL terminated. */ struct class_device_attribute **shost_attrs; /* - * Pointer to the SCSI device properties for this host + * Pointer to the SCSI device properties for this host, NULL terminated. */ struct device_attribute **sdev_attrs; @@ -500,8 +500,6 @@ static inline struct device *scsi_get_device(struct Scsi_Host *shost) return shost->shost_gendev.parent; } -extern void scsi_sysfs_release_attributes(struct scsi_host_template *); - extern void scsi_unblock_requests(struct Scsi_Host *); extern void scsi_block_requests(struct Scsi_Host *); -- cgit v1.2.3 From 892af51c10f839e3cfd5826b0f7049827fa35dea Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 8 Jul 2003 10:26:04 -0500 Subject: [PATCH] pull scsi_scan_host out of scsi_add_host As Douglas mentioned on this list a while ago there's hardware these days where we don't want to automatically perform an initial bus scan in scsi_add_host. Currently we only have ieee1394 in the tree but I can imagine more uses like iscsi or certain fc setups. This patch removes the call to scsi_scan_host from scsi_add_host and moves it into the drivers that want in. --- drivers/block/cciss_scsi.c | 3 ++- drivers/scsi/NCR_D700.c | 3 ++- drivers/scsi/NCR_Q720.c | 10 +++++++--- drivers/scsi/aha1740.c | 3 ++- drivers/scsi/aic7xxx/aic79xx_osm.c | 3 ++- drivers/scsi/aic7xxx/aic7xxx_osm.c | 3 ++- drivers/scsi/arm/acornscsi.c | 8 ++++++-- drivers/scsi/arm/cumana_1.c | 8 ++++++-- drivers/scsi/arm/ecoscsi.c | 3 ++- drivers/scsi/arm/fas216.c | 2 ++ drivers/scsi/arm/oak.c | 8 ++++++-- drivers/scsi/dc395x.c | 3 ++- drivers/scsi/hosts.c | 8 ++------ drivers/scsi/ide-scsi.c | 4 +++- drivers/scsi/ips.h | 2 +- drivers/scsi/lasi700.c | 3 ++- drivers/scsi/nsp32.c | 3 ++- drivers/scsi/pcmcia/aha152x_stub.c | 3 ++- drivers/scsi/pcmcia/fdomain_stub.c | 3 ++- drivers/scsi/pcmcia/nsp_cs.c | 3 ++- drivers/scsi/pcmcia/qlogic_stub.c | 3 ++- drivers/scsi/scsi_debug.c | 3 ++- drivers/scsi/scsi_module.c | 1 + drivers/scsi/scsi_priv.h | 1 - drivers/scsi/scsi_syms.c | 1 + drivers/scsi/sd.c | 29 +---------------------------- drivers/scsi/sim710.c | 3 ++- drivers/scsi/zalon.c | 13 ++++++++++--- drivers/usb/image/hpusbscsi.c | 3 ++- drivers/usb/image/microtek.c | 3 ++- drivers/usb/storage/usb.c | 2 ++ include/scsi/scsi_host.h | 1 + 32 files changed, 83 insertions(+), 66 deletions(-) (limited to 'include') diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 8ad5d01e4d42..6951231d4ed5 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -712,7 +712,8 @@ cciss_scsi_detect(int ctlr) sh->hostdata[0] = (unsigned long) hba[ctlr]; sh->irq = hba[ctlr]->intr; sh->unique_id = sh->irq; - scsi_add_host(sh, &hba[ctlr]->pdev->dev); + scsi_add_host(sh, &hba[ctlr]->pdev->dev); /* XXX handle failure */ + scsi_scan_host(sh); return 1; } diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c index 0d7a71abee9a..7bff5570b6a0 100644 --- a/drivers/scsi/NCR_D700.c +++ b/drivers/scsi/NCR_D700.c @@ -218,7 +218,8 @@ NCR_D700_probe_one(struct NCR_D700_private *p, int siop, goto irq_failed; } - scsi_add_host(host, p->dev); + scsi_add_host(host, p->dev); /* XXX handle failure */ + scsi_scan_host(host); p->hosts[siop] = host; hostdata->dev = p->dev; diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c index 5a3fcbeeed1a..b7d3b5264223 100644 --- a/drivers/scsi/NCR_Q720.c +++ b/drivers/scsi/NCR_Q720.c @@ -85,6 +85,7 @@ NCR_Q720_probe_one(struct NCR_Q720_private *p, int siop, __u8 scsr1 = readb(vaddr + NCR_Q720_SCSR_OFFSET + 1); __u8 differential = readb(vaddr + NCR_Q720_SCSR_OFFSET) & 0x20; __u8 version; + int error; scsi_id = scsr1 >> 4; /* enable burst length 16 (FIXME: should allow this) */ @@ -120,9 +121,12 @@ NCR_Q720_probe_one(struct NCR_Q720_private *p, int siop, scsr1 &= ~0x01; writeb(scsr1, vaddr + NCR_Q720_SCSR_OFFSET + 1); - scsi_add_host(p->hosts[siop], p->dev); - - return 0; + error = scsi_add_host(p->hosts[siop], p->dev); + if (error) + ncr53c8xx_release(p->hosts[siop]); + else + scsi_scan_host(p->hosts[siop]); + return error; fail: return -ENODEV; diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index 4c61b6a5a4f6..1c4cd5969f4c 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -636,7 +636,8 @@ static int aha1740_probe (struct device *dev) } eisa_set_drvdata (edev, shpnt); - scsi_add_host (shpnt, dev); + scsi_add_host (shpnt, dev); /* XXX handle failure */ + scsi_scan_host (shpnt) return 0; err_unmap: diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index c50c2bb46973..1b87b2aac104 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -2173,7 +2173,8 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template) ahd_unlock(ahd, &s); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - scsi_add_host(host, &ahd->dev_softc->dev); + scsi_add_host(host, &ahd->dev_softc->dev); /* XXX handle failure */ + scsi_scan_host(host); #endif return (0); } diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 9e1c586ffcdf..60f9f28c4c88 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -1811,7 +1811,8 @@ ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) ahc_unlock(ahc, &s); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - scsi_add_host(host, (ahc->dev_softc ? &ahc->dev_softc->dev : NULL)); + scsi_add_host(host, (ahc->dev_softc ? &ahc->dev_softc->dev : NULL)); /* XXX handle failure */ + scsi_scan_host(host); #endif return (0); } diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index ff23d71dd83a..6ced05fa9e9f 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -3043,9 +3043,13 @@ acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id) acornscsi_resetcard(ashost); ret = scsi_add_host(host, &ec->dev); - if (ret == 0) - goto out; + if (ret) + goto err_7; + + scsi_scan_host(host); + goto out; + err_7: free_irq(host->irq, ashost); err_6: release_region(host->io_port, 2048); diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c index b7c9f1365bf1..7fd1b3eff88a 100644 --- a/drivers/scsi/arm/cumana_1.c +++ b/drivers/scsi/arm/cumana_1.c @@ -297,9 +297,13 @@ cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id) printk("\n"); ret = scsi_add_host(host, &ec->dev); - if (ret == 0) - goto out; + if (ret) + goto out_free_irq; + + scsi_scan_host(host); + goto out; + out_free_irq: free_irq(host->irq, host); out_release: release_region(host->io_port, host->n_io_port); diff --git a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c index 9b88a2e6af59..1c957d2f594d 100644 --- a/drivers/scsi/arm/ecoscsi.c +++ b/drivers/scsi/arm/ecoscsi.c @@ -205,7 +205,8 @@ static int __init ecoscsi_init(void) NCR5380_print_options(host); printk("\n"); - scsi_add_host(host, NULL); + scsi_add_host(host, NULL); /* XXX handle failure */ + scsi_scan_host(host); return 0; release_reg: diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index 6ba029abf286..ef7188420277 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -2861,6 +2861,8 @@ int fas216_add(struct Scsi_Host *host, struct device *dev) ret = scsi_add_host(host, dev); if (ret) fas216_writeb(info, REG_CMD, CMD_RESETCHIP); + else + scsi_scan_host(host); return ret; } diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c index 7669085a2a64..5a605d779630 100644 --- a/drivers/scsi/arm/oak.c +++ b/drivers/scsi/arm/oak.c @@ -158,9 +158,13 @@ oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id) printk("\n"); ret = scsi_add_host(host, &ec->dev); - if (ret == 0) - goto out; + if (ret) + goto out_release; + + scsi_scan_host(host); + goto out; + out_release: release_region(host->io_port, host->n_io_port); unreg: scsi_host_put(host); diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index df684465956d..7a67c01d4c3c 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -6214,7 +6214,8 @@ int __devinit dc395x_init_one(struct pci_dev *pdev, pci_set_drvdata(pdev, scsi_host); /* get the scsi mid level to scan for new devices on the bus */ - scsi_add_host(scsi_host, &pdev->dev); + scsi_add_host(scsi_host, &pdev->dev); /* XXX handle failure */ + scsi_scan_host(scsi_host); return 0; } diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 969f8db554b2..f4f69bf1e148 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -81,19 +81,15 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev) printk(KERN_INFO "scsi%d : %s\n", shost->host_no, sht->info ? sht->info(shost) : sht->name); - error = scsi_sysfs_add_host(shost, dev); - if (!shost->can_queue) { printk(KERN_ERR "%s: can_queue = 0 no longer supported\n", sht->name); error = -EINVAL; } - if (!error) { + error = scsi_sysfs_add_host(shost, dev); + if (!error) scsi_proc_host_add(shost); - scsi_scan_host(shost); - } - return error; } diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index cfd1e581072c..84238c4de22a 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -978,8 +978,10 @@ static int idescsi_attach(ide_drive_t *drive) idescsi_setup (drive, idescsi); drive->disk->fops = &idescsi_ops; err = scsi_add_host(host, &idescsi_primary); - if (!err) + if (!err) { + scsi_scan_host(host); return 0; + } /* fall through on error */ ide_unregister_subdriver(drive); } diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h index 921d73f38f9d..0ad7adce9acf 100644 --- a/drivers/scsi/ips.h +++ b/drivers/scsi/ips.h @@ -111,7 +111,7 @@ #else #define IPS_REGISTER_HOSTS(SHT) (!ips_detect(SHT)) #define IPS_UNREGISTER_HOSTS(SHT) - #define IPS_ADD_HOST(shost,device) scsi_add_host(shost,device) + #define IPS_ADD_HOST(shost,device) do { scsi_add_host(shost,device); scsi_scan_host(shost); } while (0) #define IPS_REMOVE_HOST(shost) scsi_remove_host(shost) #define IPS_SCSI_SET_DEVICE(sh,ha) scsi_set_device(sh, &(ha)->pcidev->dev) #define IPS_PRINTK(level, pcidev, format, arg...) \ diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c index 5acab4b2124d..25cff061f4a1 100644 --- a/drivers/scsi/lasi700.c +++ b/drivers/scsi/lasi700.c @@ -128,7 +128,8 @@ lasi700_driver_callback(struct parisc_device *dev) } dev_set_drvdata(&dev->dev, host); - scsi_add_host(host, &dev->dev); + scsi_add_host(host, &dev->dev); /* XXX handle failure */ + scsi_scan_host(host); return 0; diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index 80021bc6e82f..355bd6fb5283 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -1820,7 +1820,8 @@ static int nsp32_detect(struct pci_dev *pdev) goto free_irq; } - scsi_add_host(host, &pdev->dev); + scsi_add_host(host, &pdev->dev); /* XXX handle failure */ + scsi_scan_host(host); pci_set_drvdata(pdev, host); return 0; diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index 03a2acaf3d47..b60b2b05aa2b 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -278,7 +278,8 @@ static void aha152x_config_cs(dev_link_t *link) goto cs_failed; } - scsi_add_host(host, NULL); + scsi_add_host(host, NULL); /* XXX handle failure */ + scsi_scan_host(host); sprintf(info->node.dev_name, "scsi%d", host->host_no); link->dev = &info->node; diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c index 4a428672adc1..e899790e42d2 100644 --- a/drivers/scsi/pcmcia/fdomain_stub.c +++ b/drivers/scsi/pcmcia/fdomain_stub.c @@ -254,7 +254,8 @@ static void fdomain_config(dev_link_t *link) goto cs_failed; } - scsi_add_host(host, NULL); + scsi_add_host(host, NULL); /* XXX handle failure */ + scsi_scan_host(host); sprintf(info->node.dev_name, "scsi%d", host->host_no); link->dev = &info->node; diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index ce52c02610fd..5c8999eebd8d 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1773,7 +1773,8 @@ static void nsp_cs_config(dev_link_t *link) req.Base+req.Size-1); printk("\n"); - scsi_add_host(host, NULL); + scsi_add_host(host, NULL); /* XXX handle failure */ + scsi_scan_host(host); link->state &= ~DEV_CONFIG_PENDING; return; diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index e22d0d6d965d..b5693378596a 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -270,7 +270,8 @@ static void qlogic_config(dev_link_t * link) link->dev = &info->node; info->host = host; - scsi_add_host(host, NULL); + scsi_add_host(host, NULL); /* XXX handle failure */ + scsi_scan_host(host); out: link->state &= ~DEV_CONFIG_PENDING; diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 59c2ae1eaa9e..5e730c4bb7d1 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1701,7 +1701,8 @@ static int sdebug_driver_probe(struct device * dev) printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__); error = -ENODEV; scsi_host_put(hpnt); - } + } else + scsi_scan_host(hpnt); return error; diff --git a/drivers/scsi/scsi_module.c b/drivers/scsi/scsi_module.c index 7803089da533..515a3e4b48fe 100644 --- a/drivers/scsi/scsi_module.c +++ b/drivers/scsi/scsi_module.c @@ -40,6 +40,7 @@ static int __init init_this_scsi_driver(void) error = scsi_add_host(shost, NULL); if (error) goto fail; + scsi_scan_host(shost); } return 0; fail: diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index e8f4d1ff6559..f17bdd42afe6 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -102,7 +102,6 @@ extern void scsi_exit_procfs(void); #endif /* CONFIG_PROC_FS */ /* scsi_scan.c */ -extern void scsi_scan_host(struct Scsi_Host *); extern void scsi_forget_host(struct Scsi_Host *); extern void scsi_free_sdev(struct scsi_device *); extern void scsi_free_shost(struct Scsi_Host *); diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c index a7fbd02b1513..df2d0c7e41cf 100644 --- a/drivers/scsi/scsi_syms.c +++ b/drivers/scsi/scsi_syms.c @@ -34,6 +34,7 @@ EXPORT_SYMBOL(scsi_register_driver); EXPORT_SYMBOL(scsi_register_interface); EXPORT_SYMBOL(scsi_host_alloc); EXPORT_SYMBOL(scsi_add_host); +EXPORT_SYMBOL(scsi_scan_host); EXPORT_SYMBOL(scsi_remove_host); EXPORT_SYMBOL(scsi_host_get); EXPORT_SYMBOL(scsi_host_put); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 892b98147816..bae8943f2666 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -606,35 +606,8 @@ not_present: static void sd_rescan(struct device *dev) { - struct scsi_device *sdp = to_scsi_device(dev); struct scsi_disk *sdkp = dev_get_drvdata(dev); - struct gendisk *gd; - struct scsi_request *SRpnt; - unsigned char *buffer; - - if (!sdkp || sdp->online == FALSE || !sdkp->media_present) - return; - - gd = sdkp->disk; - - SCSI_LOG_HLQUEUE(3, printk("sd_rescan: disk=%s\n", gd->disk_name)); - - SRpnt = scsi_allocate_request(sdp); - if (!SRpnt) { - printk(KERN_WARNING "(sd_rescan:) Request allocation " - "failure.\n"); - return; - } - - if (sdkp->device->host->unchecked_isa_dma) - buffer = kmalloc(512, GFP_DMA); - else - buffer = kmalloc(512, GFP_KERNEL); - - sd_read_capacity(sdkp, gd->disk_name, SRpnt, buffer); - set_capacity(gd, sdkp->capacity); - scsi_release_request(SRpnt); - kfree(buffer); + sd_revalidate_disk(sdkp->disk); } static struct block_device_operations sd_fops = { diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c index 9eea1210daaa..2e300ed55278 100644 --- a/drivers/scsi/sim710.c +++ b/drivers/scsi/sim710.c @@ -138,7 +138,8 @@ sim710_probe_common(struct device *dev, unsigned long base_addr, goto out_unregister; } - scsi_add_host(host, dev); + scsi_add_host(host, dev); /* XXX handle failure */ + scsi_scan_host(host); hostdata->dev = dev; return 0; diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c index 81aa5551fcb3..146160644935 100644 --- a/drivers/scsi/zalon.c +++ b/drivers/scsi/zalon.c @@ -85,7 +85,7 @@ zalon_scsi_callback(struct parisc_device *dev) { struct gsc_irq gsc_irq; u32 zalon_vers; - int irq; + int irq, error = -ENODEV; unsigned long zalon = dev->hpa; unsigned long io_port = zalon + GSC_SCSI_ZALON_OFFSET; static int unit = 0; @@ -147,11 +147,18 @@ zalon_scsi_callback(struct parisc_device *dev) dev_set_drvdata(&dev->dev, host); - scsi_add_host(host, &dev->dev); + error = scsi_add_host(host, &dev->dev); + if (error) + goto fail_free_irq; + scsi_scan_host(host); return 0; + + fail_free_irq: + free_irq(irq, host); fail: - return -ENODEV; + ncr53c8xx_release(host); + return error; } static struct parisc_device_id zalon_tbl[] = { diff --git a/drivers/usb/image/hpusbscsi.c b/drivers/usb/image/hpusbscsi.c index cb64dae50598..196153b944b0 100644 --- a/drivers/usb/image/hpusbscsi.c +++ b/drivers/usb/image/hpusbscsi.c @@ -109,7 +109,8 @@ hpusbscsi_usb_probe(struct usb_interface *intf, goto out_unlink_controlurb; new->host->hostdata[0] = (unsigned long)new; - scsi_add_host(new->host, &intf->dev); + scsi_add_host(new->host, &intf->dev); /* XXX handle failure */ + scsi_scan_host(new->host); new->sense_command[0] = REQUEST_SENSE; new->sense_command[4] = HPUSBSCSI_SENSE_LENGTH; diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index 6b0b070f73a6..6766f4ee735e 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -817,7 +817,8 @@ static int mts_usb_probe(struct usb_interface *intf, goto out_free_urb; new_desc->host->hostdata[0] = (unsigned long)new_desc; - scsi_add_host(new_desc->host, NULL); + scsi_add_host(new_desc->host, NULL); /* XXX handle failure */ + scsi_scan_host(new_desc->host); usb_set_intfdata(intf, new_desc); return 0; diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index ef495072850f..ee67b5340adc 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -958,6 +958,8 @@ static int storage_probe(struct usb_interface *intf, goto BadDevice; } + scsi_scan_host(us->host); + printk(KERN_DEBUG "WARNING: USB Mass Storage data integrity not assured\n"); printk(KERN_DEBUG diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 1b4ea934947f..3ef701078fef 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -477,6 +477,7 @@ struct Scsi_Host { extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int); extern int scsi_add_host(struct Scsi_Host *, struct device *); +extern void scsi_scan_host(struct Scsi_Host *); extern int scsi_remove_host(struct Scsi_Host *); extern void scsi_host_get(struct Scsi_Host *); extern void scsi_host_put(struct Scsi_Host *t); -- cgit v1.2.3 From bcf2227c6b8696fac54f1120af17a8d300920417 Mon Sep 17 00:00:00 2001 From: Patrick Mansfield Date: Tue, 8 Jul 2003 10:31:16 -0500 Subject: [PATCH] fix scsi_mode_data length result I have some Seagate drives that apparently return to much data when asked for 31 bytes for a MODE SENSE cache page, resulting in buffer overruns. Requests for 4 bytes work fine. Changing __scsi_mode_sense to correctly set the scsi_mode_data length per the following patch fixed the problem for me. --- drivers/scsi/scsi_lib.c | 4 ++-- include/scsi/scsi_request.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index e6d3cace3b11..edc37045a04f 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1426,14 +1426,14 @@ __scsi_mode_sense(struct scsi_request *sreq, int dbd, int modepage, if(scsi_status_is_good(sreq->sr_result)) { data->header_length = header_length; if(use_10_for_ms) { - data->length = buffer[0]*256 + buffer[1]; + data->length = buffer[0]*256 + buffer[1] + 2; data->medium_type = buffer[2]; data->device_specific = buffer[3]; data->longlba = buffer[4] & 0x01; data->block_descriptor_length = buffer[6]*256 + buffer[7]; } else { - data->length = buffer[0]; + data->length = buffer[0] + 1; data->medium_type = buffer[1]; data->device_specific = buffer[3]; data->block_descriptor_length = buffer[4]; diff --git a/include/scsi/scsi_request.h b/include/scsi/scsi_request.h index 90dcdaafe946..d591d365c983 100644 --- a/include/scsi/scsi_request.h +++ b/include/scsi/scsi_request.h @@ -56,7 +56,7 @@ extern void scsi_do_req(struct scsi_request *, const void *cmnd, int timeout, int retries); struct scsi_mode_data { - __u16 length; + __u32 length; __u16 block_descriptor_length; __u8 medium_type; __u8 device_specific; -- cgit v1.2.3 From ae625582ba438fdd84a3faaf225bb9aa2f2d7bb1 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 17 Jul 2003 02:01:19 -0400 Subject: [PATCH] Consolidate SCSI requeueing and add blk elevator hook This patch removes the scsi mid layer dependency on __elv_add_request and introduces a new blk_requeue_request() function so the block layer specificially knows a requeue is in progress. It also adds an elevator hook for elevators like AS which need to hook into the requeue for correct adjustment of internal counters. --- drivers/block/elevator.c | 13 +++++++++++++ drivers/block/ll_rw_blk.c | 18 ++++++++++++++++++ drivers/scsi/scsi_lib.c | 20 ++------------------ include/linux/blkdev.h | 1 + include/linux/elevator.h | 3 +++ 5 files changed, 37 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 00b56d022b0e..272bcb34195b 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -214,6 +214,18 @@ void elv_merge_requests(request_queue_t *q, struct request *rq, e->elevator_merge_req_fn(q, rq, next); } +void elv_requeue_request(request_queue_t *q, struct request *rq) +{ + /* + * if iosched has an explicit requeue hook, then use that. otherwise + * just put the request at the front of the queue + */ + if (q->elevator.elevator_requeue_req_fn) + q->elevator.elevator_requeue_req_fn(q, rq); + else + __elv_add_request(q, rq, 0, 0); +} + void __elv_add_request(request_queue_t *q, struct request *rq, int at_end, int plug) { @@ -405,6 +417,7 @@ EXPORT_SYMBOL(elevator_noop); EXPORT_SYMBOL(elv_add_request); EXPORT_SYMBOL(__elv_add_request); +EXPORT_SYMBOL(elv_requeue_request); EXPORT_SYMBOL(elv_next_request); EXPORT_SYMBOL(elv_remove_request); EXPORT_SYMBOL(elv_queue_empty); diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 0f11567e5277..db399409909d 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1355,6 +1355,23 @@ struct request *blk_get_request(request_queue_t *q, int rw, int gfp_mask) return rq; } +/** + * blk_requeue_request - put a request back on queue + * @q: request queue where request should be inserted + * @rq: request to be inserted + * + * Description: + * Drivers often keep queueing requests until the hardware cannot accept + * more, when that condition happens we need to put the request back + * on the queue. Must be called with queue lock held. + */ +void blk_requeue_request(request_queue_t *q, struct request *rq) +{ + if (blk_rq_tagged(rq)) + blk_queue_end_tag(q, rq); + + elv_requeue_request(q, rq); +} /** * blk_insert_request - insert a special request in to a request queue @@ -2339,6 +2356,7 @@ EXPORT_SYMBOL(blk_hw_contig_segment); EXPORT_SYMBOL(blk_get_request); EXPORT_SYMBOL(blk_put_request); EXPORT_SYMBOL(blk_insert_request); +EXPORT_SYMBOL(blk_requeue_request); EXPORT_SYMBOL(blk_queue_prep_rq); EXPORT_SYMBOL(blk_queue_merge_bvec); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 4abb228037bd..b462b20c5b3d 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -444,22 +444,8 @@ static void scsi_run_queue(struct request_queue *q) */ static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd) { - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - cmd->request->special = cmd; - if (blk_rq_tagged(cmd->request)) - blk_queue_end_tag(q, cmd->request); - - /* - * set REQ_SPECIAL - we have a command - * clear REQ_DONTPREP - we assume the sg table has been - * nuked so we need to set it up again. - */ - cmd->request->flags |= REQ_SPECIAL; cmd->request->flags &= ~REQ_DONTPREP; - __elv_add_request(q, cmd->request, 0, 0); - spin_unlock_irqrestore(q->queue_lock, flags); + blk_insert_request(q, cmd->request, 1, cmd); scsi_run_queue(q); } @@ -1213,9 +1199,7 @@ static void scsi_request_fn(struct request_queue *q) * later time. */ spin_lock_irq(q->queue_lock); - if (blk_rq_tagged(req)) - blk_queue_end_tag(q, req); - __elv_add_request(q, req, 0, 0); + blk_requeue_request(q, req); sdev->device_busy--; if(sdev->device_busy == 0) blk_plug_device(q); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 786ea3563752..b164fa5b40c6 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -405,6 +405,7 @@ extern void __blk_attempt_remerge(request_queue_t *, struct request *); extern struct request *blk_get_request(request_queue_t *, int, int); extern void blk_put_request(struct request *); extern void blk_insert_request(request_queue_t *, struct request *, int, void *); +extern void blk_requeue_request(request_queue_t *, struct request *); extern void blk_plug_device(request_queue_t *); extern int blk_remove_plug(request_queue_t *); extern void blk_recount_segments(request_queue_t *, struct bio *); diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 522e51609ef3..e1c7bafa4fbc 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -13,6 +13,7 @@ typedef struct request *(elevator_next_req_fn) (request_queue_t *); typedef void (elevator_add_req_fn) (request_queue_t *, struct request *, struct list_head *); typedef int (elevator_queue_empty_fn) (request_queue_t *); typedef void (elevator_remove_req_fn) (request_queue_t *, struct request *); +typedef void (elevator_requeue_req_fn) (request_queue_t *, struct request *); typedef struct request *(elevator_request_list_fn) (request_queue_t *, struct request *); typedef struct list_head *(elevator_get_sort_head_fn) (request_queue_t *, struct request *); typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, int); @@ -30,6 +31,7 @@ struct elevator_s elevator_next_req_fn *elevator_next_req_fn; elevator_add_req_fn *elevator_add_req_fn; elevator_remove_req_fn *elevator_remove_req_fn; + elevator_requeue_req_fn *elevator_requeue_req_fn; elevator_queue_empty_fn *elevator_queue_empty_fn; @@ -58,6 +60,7 @@ extern void elv_merge_requests(request_queue_t *, struct request *, struct request *); extern void elv_merged_request(request_queue_t *, struct request *); extern void elv_remove_request(request_queue_t *, struct request *); +extern void elv_requeue_request(request_queue_t *, struct request *); extern int elv_queue_empty(request_queue_t *); extern struct request *elv_next_request(struct request_queue *q); extern struct request *elv_former_request(request_queue_t *, struct request *); -- cgit v1.2.3 From 5acf32eeb3082c5ec89bbd9df2b8bda251ca1bc1 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 17 Jul 2003 19:25:07 -0700 Subject: [PATCH] misc fixes - i460-agp linkage fix ("Luck, Tony" ) - Don't reimplement offsetof() in hfs - NBD warning fix - Remove unneeded null-pointer test in journal_stop (Andreas Gruenbacher) - remove debug stuff in journal_dirty_metadata() - slab.c typo fixes (Lev Makhlis ) - In devfs_mk_cdev() error path, don't print `buf' until we've written something into it. (Reported by Gergely Nagy ) - Two ISA sound drivers had their kmalloc() args reversed (Spotted by Steve French) --- drivers/block/nbd.c | 3 ++- drivers/char/agp/i460-agp.c | 2 +- fs/jbd/transaction.c | 13 ------------- include/linux/hfs_sysdep.h | 3 --- mm/slab.c | 4 ++-- sound/isa/cmi8330.c | 2 +- sound/isa/es18xx.c | 2 +- 7 files changed, 7 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index cc9c34b09839..d57f3abf6e5e 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -258,7 +258,8 @@ void nbd_send_req(struct nbd_device *lo, struct request *req) dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%luB)\n", lo->disk->disk_name, req, nbdcmd_to_ascii(nbd_cmd(req)), - req->sector << 9, req->nr_sectors << 9); + (unsigned long long)req->sector << 9, + req->nr_sectors << 9); result = sock_xmit(sock, 1, &request, sizeof(request), (nbd_cmd(req) == NBD_CMD_WRITE)? MSG_MORE: 0); if (result <= 0) { diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index 263e7de4f115..23f5cece5634 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -608,7 +608,7 @@ static struct pci_driver agp_intel_i460_pci_driver = { .name = "agpgart-intel-i460", .id_table = agp_intel_i460_pci_table, .probe = agp_intel_i460_probe, - .remove = agp_intel_i460_remove, + .remove = __devexit_p(agp_intel_i460_remove), }; static int __init agp_intel_i460_init(void) diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 1423dadf3db9..2861ee44cb11 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -1106,16 +1106,6 @@ int journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) if (jh->b_transaction == handle->h_transaction && jh->b_jlist == BJ_Metadata) { JBUFFER_TRACE(jh, "fastpath"); - console_verbose(); - if (jh->b_transaction != journal->j_running_transaction) { - printk("jh->b_transaction=%p\n", jh->b_transaction); - printk("journal->j_running_transaction=%p\n", - journal->j_running_transaction); - printk("handle->h_transaction=%p\n", - handle->h_transaction); - printk("journal->j_committing_transaction=%p\n", - journal->j_committing_transaction); - } J_ASSERT_JH(jh, jh->b_transaction == journal->j_running_transaction); goto out_unlock_bh; @@ -1328,9 +1318,6 @@ int journal_stop(handle_t *handle) journal_t *journal = transaction->t_journal; int old_handle_count, err; - if (!handle) - return 0; - J_ASSERT(transaction->t_updates > 0); J_ASSERT(journal_current_handle() == handle); diff --git a/include/linux/hfs_sysdep.h b/include/linux/hfs_sysdep.h index 1468ef02e8b6..4c4e3eba0963 100644 --- a/include/linux/hfs_sysdep.h +++ b/include/linux/hfs_sysdep.h @@ -28,9 +28,6 @@ extern struct timezone sys_tz; -#undef offsetof -#define offsetof(TYPE, MEMB) ((size_t) &((TYPE *)0)->MEMB) - /* Typedefs for integer types by size and signedness */ typedef __u8 hfs_u8; typedef __u16 hfs_u16; diff --git a/mm/slab.c b/mm/slab.c index bee3dfdf8619..4576d24523c0 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2482,11 +2482,11 @@ static void *s_start(struct seq_file *m, loff_t *pos) seq_puts(m, "slabinfo - version: 2.0\n"); #endif seq_puts(m, "# name "); - seq_puts(m, " : tunables "); + seq_puts(m, " : tunables "); seq_puts(m, " : slabdata "); #if STATS seq_puts(m, " : globalstat "); - seq_puts(m, " : cpustat "); + seq_puts(m, " : cpustat "); #endif seq_putc(m, '\n'); } diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index 226ffd299f3c..f3f3d6b12aba 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -293,7 +293,7 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, const struct pnp_card_device_id *id) { struct pnp_dev *pdev; - struct pnp_resource_table * cfg = kmalloc(GFP_ATOMIC, sizeof(struct pnp_resource_table)); + struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_ATOMIC); int err; acard->cap = pnp_request_card_device(card, id->devs[0].id, NULL); diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index b52983f47a0c..5b3b49163071 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -1966,7 +1966,7 @@ static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, const struct pnp_card_device_id *id) { struct pnp_dev *pdev; - struct pnp_resource_table * cfg = kmalloc(GFP_ATOMIC, sizeof(struct pnp_resource_table)); + struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_ATOMIC); int err; if (!cfg) -- cgit v1.2.3 From eda597e240b1c8baa993f4ec2ec496aa7c789723 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 17 Jul 2003 19:25:31 -0700 Subject: [PATCH] Ext3 xattr credits fix for quotas From: Andreas Gruenbacher The xattr and acl code are not properly reserving credits for quotas. EXT3_DATA_TRANS_BLOCKS is an overestimate of the credits required including quotas. Make it a little more tight, and use it in the xattr and acl code to be quota safe. --- fs/ext3/acl.c | 4 ++-- fs/ext3/xattr.c | 2 +- include/linux/ext3_jbd.h | 7 ++++--- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index 2416e214280f..53051432b4bf 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -425,7 +425,7 @@ ext3_acl_chmod(struct inode *inode) if (!error) { handle_t *handle; - handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS); + handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS); if (IS_ERR(handle)) { error = PTR_ERR(handle); ext3_std_error(inode->i_sb, error); @@ -531,7 +531,7 @@ ext3_xattr_set_acl(struct inode *inode, int type, const void *value, } else acl = NULL; - handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS); + handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS); if (IS_ERR(handle)) return PTR_ERR(handle); error = ext3_set_acl(handle, inode, type, acl); diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index 66ed5a09a3e6..402e30ca81fd 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -875,7 +875,7 @@ ext3_xattr_set(struct inode *inode, int name_index, const char *name, handle_t *handle; int error, error2; - handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS); + handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS); if (IS_ERR(handle)) error = PTR_ERR(handle); else diff --git a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h index 27b21821ce74..50caf6875ba4 100644 --- a/include/linux/ext3_jbd.h +++ b/include/linux/ext3_jbd.h @@ -30,10 +30,11 @@ #define EXT3_SINGLEDATA_TRANS_BLOCKS 8U -/* Extended attributes may touch two data buffers, two bitmap buffers, - * and two group and summaries. */ +/* Extended attribute operations touch at most two data buffers, + * two bitmap buffers, and two group summaries, in addition to the inode + * and the superblock, which are already accounted for. */ -#define EXT3_XATTR_TRANS_BLOCKS 8 +#define EXT3_XATTR_TRANS_BLOCKS 6U /* Define the minimum size for a transaction which modifies data. This * needs to take into account the fact that we may end up modifying two -- cgit v1.2.3 From 5773262567608d397ec0aa41b250db1e3bb5e694 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 17 Jul 2003 19:25:46 -0700 Subject: [PATCH] pass regs into dump_fpu() in elf coredump From: Pete Zaitcev sparc32 needs the registers passed into dump_fpu(). --- arch/sparc/kernel/process.c | 12 ++++++++---- fs/binfmt_elf.c | 4 ++-- include/linux/elfcore.h | 4 ++-- 3 files changed, 12 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index f3fe5f6cad3b..d42c4a9ecb28 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c @@ -590,16 +590,20 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs) put_psr(get_psr() | PSR_EF); fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); - regs->psr &= ~(PSR_EF); - current->flags &= ~(PF_USEDFPU); + if (regs != NULL) { + regs->psr &= ~(PSR_EF); + current->flags &= ~(PF_USEDFPU); + } } #else if (current == last_task_used_math) { put_psr(get_psr() | PSR_EF); fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); - last_task_used_math = 0; - regs->psr &= ~(PSR_EF); + if (regs != NULL) { + regs->psr &= ~(PSR_EF); + last_task_used_math = 0; + } } #endif memcpy(&fpregs->pr_fr.pr_regs[0], diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index d808a9dfc9ec..53938f81c696 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1158,7 +1158,7 @@ static int elf_dump_thread_status(long signr, struct task_struct * p, struct lis t->num_notes++; sz += notesize(&t->notes[0]); - if ((t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, &t->fpu))) { + if ((t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL, &t->fpu))) { fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu), &(t->fpu)); t->num_notes++; sz += notesize(&t->notes[1]); @@ -1286,7 +1286,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) fill_note(notes +2, "CORE", NT_TASKSTRUCT, sizeof(*current), current); /* Try to dump the FPU. */ - if ((prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, fpu))) + if ((prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, fpu))) fill_note(notes +3, "CORE", NT_PRFPREG, sizeof(*fpu), fpu); else --numnote; diff --git a/include/linux/elfcore.h b/include/linux/elfcore.h index 089d67225207..dbd7bb4a33b7 100644 --- a/include/linux/elfcore.h +++ b/include/linux/elfcore.h @@ -107,12 +107,12 @@ static inline int elf_core_copy_task_regs(struct task_struct *t, elf_gregset_t* extern int dump_fpu (struct pt_regs *, elf_fpregset_t *); -static inline int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu) +static inline int elf_core_copy_task_fpregs(struct task_struct *t, struct pt_regs *regs, elf_fpregset_t *fpu) { #ifdef ELF_CORE_COPY_FPREGS return ELF_CORE_COPY_FPREGS(t, fpu); #else - return dump_fpu(NULL, fpu); + return dump_fpu(regs, fpu); #endif } -- cgit v1.2.3 From 37c2c764d06416ea650db7fab27b628308bab8f3 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 17 Jul 2003 19:26:08 -0700 Subject: [PATCH] use kmalloc for ia32 stacks From: William Lee Irwin III I've been slab allocating the stack on i386 for some time, and it has gone without incident in pgcl, -wli, -mjb (?), and so on. kmalloc() is fine; there isn't any particularly compelling reason for a dedicated slab as there's no preconstruction to do, though it can be arranged. Basically, it works, there's no obvious reason not to, and (even better) it's not totally invisible to the VM and even makes overhead reportable. --- include/asm-i386/thread_info.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h index a278e34aa158..1574d103074b 100644 --- a/include/asm-i386/thread_info.h +++ b/include/asm-i386/thread_info.h @@ -87,8 +87,8 @@ static inline struct thread_info *current_thread_info(void) /* thread information allocation */ #define THREAD_SIZE (2*PAGE_SIZE) -#define alloc_thread_info(tsk) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1)) -#define free_thread_info(ti) free_pages((unsigned long) (ti), 1) +#define alloc_thread_info(task) ((struct thread_info *)kmalloc(THREAD_SIZE, GFP_KERNEL)) +#define free_thread_info(info) kfree(info) #define get_thread_info(ti) get_task_struct((ti)->task) #define put_thread_info(ti) put_task_struct((ti)->task) -- cgit v1.2.3 From 16096694244311a9b2464d83b10b8a339ecedd56 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 17 Jul 2003 19:26:41 -0700 Subject: [PATCH] unline most of put_namespace() It has five callsites, and is big. --- fs/namespace.c | 10 ++++++++++ include/linux/namespace.h | 11 +++-------- 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/fs/namespace.c b/fs/namespace.c index 12a8c8146829..8a3552bd6660 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1158,3 +1158,13 @@ void __init mnt_init(unsigned long mempages) init_rootfs(); init_mount_tree(); } + +void __put_namespace(struct namespace *namespace) +{ + down_write(&namespace->sem); + spin_lock(&vfsmount_lock); + umount_tree(namespace->root); + spin_unlock(&vfsmount_lock); + up_write(&namespace->sem); + kfree(namespace); +} diff --git a/include/linux/namespace.h b/include/linux/namespace.h index b5699538afac..fdd8abb07386 100644 --- a/include/linux/namespace.h +++ b/include/linux/namespace.h @@ -14,17 +14,12 @@ struct namespace { extern void umount_tree(struct vfsmount *); extern int copy_namespace(int, struct task_struct *); +void __put_namespace(struct namespace *namespace); static inline void put_namespace(struct namespace *namespace) { - if (atomic_dec_and_test(&namespace->count)) { - down_write(&namespace->sem); - spin_lock(&vfsmount_lock); - umount_tree(namespace->root); - spin_unlock(&vfsmount_lock); - up_write(&namespace->sem); - kfree(namespace); - } + if (atomic_dec_and_test(&namespace->count)) + __put_namespace(namespace); } static inline void exit_namespace(struct task_struct *p) -- cgit v1.2.3 From b23202a671b69c38e03ac0d3d90cf548e5d8918c Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 17 Jul 2003 19:27:23 -0700 Subject: [PATCH] vesafb fix From: Gerd Knorr The patch below fixes some vesafb issues. Changes: * fixed struct screen_info in tty.h to use portable types. "unsigned long" for 32bit values doesn't work on hammer machines ... * limited the framebuffer memory used by vesafb to 16 MB. This avoids that vesafb's ioremap() eats plenty of kernel address space for no real benefit if the gfx card has very much memory (some have 128 MB or more, ia32 has 128 MB address space for vmalloc and ioremap ...). * mtrr is enabled by default. That should improve the vesafb performance a lot. Also added a option to disable mtrr. --- drivers/video/vesafb.c | 10 +++++++- include/linux/tty.h | 64 +++++++++++++++++++++++++------------------------- 2 files changed, 41 insertions(+), 33 deletions(-) (limited to 'include') diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index 24a207b98937..88571b368ddb 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -51,7 +51,7 @@ static struct fb_info fb_info; static u32 pseudo_palette[17]; static int inverse = 0; -static int mtrr = 0; +static int mtrr = 1; static int pmi_setpal = 0; /* pmi for palette changes ??? */ static int ypan = 0; /* 0..nothing, 1..ypan, 2..ywrap */ @@ -208,6 +208,8 @@ int __init vesafb_setup(char *options) pmi_setpal=1; else if (! strcmp(this_opt, "mtrr")) mtrr=1; + else if (! strcmp(this_opt, "nomtrr")) + mtrr=0; } return 0; } @@ -231,6 +233,12 @@ int __init vesafb_init(void) vesafb_fix.visual = (vesafb_defined.bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + /* limit framebuffer size to 16 MB. Otherwise we'll eat tons of + * kernel address space for nothing if the gfx card has alot of + * memory (>= 128 MB isn't uncommon these days ...) */ + if (vesafb_fix.smem_len > 16 * 1024 * 1024) + vesafb_fix.smem_len = 16 * 1024 * 1024; + #ifndef __i386__ screen_info.vesapm_seg = 0; #endif diff --git a/include/linux/tty.h b/include/linux/tty.h index ea8cd3a2779c..aa10cff1871c 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -57,40 +57,40 @@ */ struct screen_info { - unsigned char orig_x; /* 0x00 */ - unsigned char orig_y; /* 0x01 */ - unsigned short dontuse1; /* 0x02 -- EXT_MEM_K sits here */ - unsigned short orig_video_page; /* 0x04 */ - unsigned char orig_video_mode; /* 0x06 */ - unsigned char orig_video_cols; /* 0x07 */ - unsigned short unused2; /* 0x08 */ - unsigned short orig_video_ega_bx; /* 0x0a */ - unsigned short unused3; /* 0x0c */ - unsigned char orig_video_lines; /* 0x0e */ - unsigned char orig_video_isVGA; /* 0x0f */ - unsigned short orig_video_points; /* 0x10 */ + u8 orig_x; /* 0x00 */ + u8 orig_y; /* 0x01 */ + u16 dontuse1; /* 0x02 -- EXT_MEM_K sits here */ + u16 orig_video_page; /* 0x04 */ + u8 orig_video_mode; /* 0x06 */ + u8 orig_video_cols; /* 0x07 */ + u16 unused2; /* 0x08 */ + u16 orig_video_ega_bx; /* 0x0a */ + u16 unused3; /* 0x0c */ + u8 orig_video_lines; /* 0x0e */ + u8 orig_video_isVGA; /* 0x0f */ + u16 orig_video_points; /* 0x10 */ /* VESA graphic mode -- linear frame buffer */ - unsigned short lfb_width; /* 0x12 */ - unsigned short lfb_height; /* 0x14 */ - unsigned short lfb_depth; /* 0x16 */ - unsigned long lfb_base; /* 0x18 */ - unsigned long lfb_size; /* 0x1c */ - unsigned short dontuse2, dontuse3; /* 0x20 -- CL_MAGIC and CL_OFFSET here */ - unsigned short lfb_linelength; /* 0x24 */ - unsigned char red_size; /* 0x26 */ - unsigned char red_pos; /* 0x27 */ - unsigned char green_size; /* 0x28 */ - unsigned char green_pos; /* 0x29 */ - unsigned char blue_size; /* 0x2a */ - unsigned char blue_pos; /* 0x2b */ - unsigned char rsvd_size; /* 0x2c */ - unsigned char rsvd_pos; /* 0x2d */ - unsigned short vesapm_seg; /* 0x2e */ - unsigned short vesapm_off; /* 0x30 */ - unsigned short pages; /* 0x32 */ - unsigned short vesa_attributes; /* 0x34 */ - /* 0x36 -- 0x3f reserved for future expansion */ + u16 lfb_width; /* 0x12 */ + u16 lfb_height; /* 0x14 */ + u16 lfb_depth; /* 0x16 */ + u32 lfb_base; /* 0x18 */ + u32 lfb_size; /* 0x1c */ + u16 dontuse2, dontuse3; /* 0x20 -- CL_MAGIC and CL_OFFSET here */ + u16 lfb_linelength; /* 0x24 */ + u8 red_size; /* 0x26 */ + u8 red_pos; /* 0x27 */ + u8 green_size; /* 0x28 */ + u8 green_pos; /* 0x29 */ + u8 blue_size; /* 0x2a */ + u8 blue_pos; /* 0x2b */ + u8 rsvd_size; /* 0x2c */ + u8 rsvd_pos; /* 0x2d */ + u16 vesapm_seg; /* 0x2e */ + u16 vesapm_off; /* 0x30 */ + u16 pages; /* 0x32 */ + u16 vesa_attributes; /* 0x34 */ + /* 0x36 -- 0x3f reserved for future expansion */ }; extern struct screen_info screen_info; -- cgit v1.2.3 From 074127b5eb6578e95561061de60f7ecaaa592694 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 17 Jul 2003 19:27:39 -0700 Subject: [PATCH] CLONE_STOPPED From: Ulrich Drepper CLONE_STOPPED: start a thread in a stopped state. Required for NTPL. --- include/linux/sched.h | 1 + kernel/fork.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/sched.h b/include/linux/sched.h index 750f2a12cada..bf740af246c0 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -52,6 +52,7 @@ struct exec_domain; #define CLONE_DETACHED 0x00400000 /* parent wants no child-exit signal */ #define CLONE_UNTRACED 0x00800000 /* set if the tracing process can't force CLONE_PTRACE on this clone */ #define CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */ +#define CLONE_STOPPED 0x02000000 /* Start in stopped state */ /* * List of flags we want to share for kernel threads, diff --git a/kernel/fork.c b/kernel/fork.c index 24cba7f5f25d..7c4c94b1a968 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1076,7 +1076,7 @@ long do_fork(unsigned long clone_flags, init_completion(&vfork); } - if (p->ptrace & PT_PTRACED) { + if ((p->ptrace & PT_PTRACED) || (clone_flags & CLONE_STOPPED)) { /* * We'll start up with an immediate SIGSTOP. */ @@ -1084,7 +1084,9 @@ long do_fork(unsigned long clone_flags, set_tsk_thread_flag(p, TIF_SIGPENDING); } - wake_up_forked_process(p); /* do this last */ + p->state = TASK_STOPPED; + if (!(clone_flags & CLONE_STOPPED)) + wake_up_forked_process(p); /* do this last */ ++total_forks; if (unlikely (trace)) { -- cgit v1.2.3 From 77d7ccc836afdef54abf9117be587a15ce00be57 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 17 Jul 2003 19:27:54 -0700 Subject: [PATCH] dm: v4 ioctl interface From: Joe Thornber v4 of the ioctl interface. Note there never was a v2 or a v3 except in an unofficial EVMS way. This works correctly with the 64-bit dev_t patches in -mm kernels. There is now a config option to allow the user to select v1 or v4, it defaults to v1. dm-ioctl.[hc] just #includes dm-ioctl-v[14].[hc] depending on the config option. If you want to use v4 you will have to update your tools (libdevmapper/lvm). The latest tools at the time of writing are: dmsetup + libdevmapper + replacement kernel patches for 2.4.20 & 2.4.21: ftp://ftp.sistina.com/pub/LVM2/device-mapper/device-mapper-testing-new-version4-interface.tgz Updated LVM2 tools to work with the above: ftp://ftp.sistina.com/pub/LVM2/tools/LVM2.0-testing.tgz --- drivers/md/Kconfig | 7 + drivers/md/dm-ioctl-v1.c | 1160 +++++++++++++++++++++++++++++++++++++++ drivers/md/dm-ioctl-v4.c | 1252 +++++++++++++++++++++++++++++++++++++++++++ drivers/md/dm-ioctl.c | 1131 +------------------------------------- drivers/md/dm.c | 38 +- drivers/md/dm.h | 5 +- include/linux/dm-ioctl-v1.h | 149 +++++ include/linux/dm-ioctl-v4.h | 237 ++++++++ include/linux/dm-ioctl.h | 147 +---- 9 files changed, 2841 insertions(+), 1285 deletions(-) create mode 100644 drivers/md/dm-ioctl-v1.c create mode 100644 drivers/md/dm-ioctl-v4.c create mode 100644 include/linux/dm-ioctl-v1.h create mode 100644 include/linux/dm-ioctl-v4.h (limited to 'include') diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index c3aca579563c..afcd1a4549f0 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -145,5 +145,12 @@ config BLK_DEV_DM If unsure, say N. +config DM_IOCTL_V4 + bool "ioctl interface version 4" + depends on BLK_DEV_DM + ---help--- + Recent tools use a new version of the ioctl interface, only + select this option if you intend using such tools. + endmenu diff --git a/drivers/md/dm-ioctl-v1.c b/drivers/md/dm-ioctl-v1.c new file mode 100644 index 000000000000..19cea7db179f --- /dev/null +++ b/drivers/md/dm-ioctl-v1.c @@ -0,0 +1,1160 @@ +/* + * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include "dm.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DM_DRIVER_EMAIL "dm@uk.sistina.com" + +/*----------------------------------------------------------------- + * The ioctl interface needs to be able to look up devices by + * name or uuid. + *---------------------------------------------------------------*/ +struct hash_cell { + struct list_head name_list; + struct list_head uuid_list; + + char *name; + char *uuid; + struct mapped_device *md; +}; + +#define NUM_BUCKETS 64 +#define MASK_BUCKETS (NUM_BUCKETS - 1) +static struct list_head _name_buckets[NUM_BUCKETS]; +static struct list_head _uuid_buckets[NUM_BUCKETS]; + +void dm_hash_remove_all(void); + +/* + * Guards access to all three tables. + */ +static DECLARE_RWSEM(_hash_lock); + +static void init_buckets(struct list_head *buckets) +{ + unsigned int i; + + for (i = 0; i < NUM_BUCKETS; i++) + INIT_LIST_HEAD(buckets + i); +} + +int dm_hash_init(void) +{ + init_buckets(_name_buckets); + init_buckets(_uuid_buckets); + devfs_mk_dir(DM_DIR); + return 0; +} + +void dm_hash_exit(void) +{ + dm_hash_remove_all(); + devfs_remove(DM_DIR); +} + +/*----------------------------------------------------------------- + * Hash function: + * We're not really concerned with the str hash function being + * fast since it's only used by the ioctl interface. + *---------------------------------------------------------------*/ +static unsigned int hash_str(const char *str) +{ + const unsigned int hash_mult = 2654435387U; + unsigned int h = 0; + + while (*str) + h = (h + (unsigned int) *str++) * hash_mult; + + return h & MASK_BUCKETS; +} + +/*----------------------------------------------------------------- + * Code for looking up a device by name + *---------------------------------------------------------------*/ +static struct hash_cell *__get_name_cell(const char *str) +{ + struct list_head *tmp; + struct hash_cell *hc; + unsigned int h = hash_str(str); + + list_for_each (tmp, _name_buckets + h) { + hc = list_entry(tmp, struct hash_cell, name_list); + if (!strcmp(hc->name, str)) + return hc; + } + + return NULL; +} + +static struct hash_cell *__get_uuid_cell(const char *str) +{ + struct list_head *tmp; + struct hash_cell *hc; + unsigned int h = hash_str(str); + + list_for_each (tmp, _uuid_buckets + h) { + hc = list_entry(tmp, struct hash_cell, uuid_list); + if (!strcmp(hc->uuid, str)) + return hc; + } + + return NULL; +} + +/*----------------------------------------------------------------- + * Inserting, removing and renaming a device. + *---------------------------------------------------------------*/ +static inline char *kstrdup(const char *str) +{ + char *r = kmalloc(strlen(str) + 1, GFP_KERNEL); + if (r) + strcpy(r, str); + return r; +} + +static struct hash_cell *alloc_cell(const char *name, const char *uuid, + struct mapped_device *md) +{ + struct hash_cell *hc; + + hc = kmalloc(sizeof(*hc), GFP_KERNEL); + if (!hc) + return NULL; + + hc->name = kstrdup(name); + if (!hc->name) { + kfree(hc); + return NULL; + } + + if (!uuid) + hc->uuid = NULL; + + else { + hc->uuid = kstrdup(uuid); + if (!hc->uuid) { + kfree(hc->name); + kfree(hc); + return NULL; + } + } + + INIT_LIST_HEAD(&hc->name_list); + INIT_LIST_HEAD(&hc->uuid_list); + hc->md = md; + return hc; +} + +static void free_cell(struct hash_cell *hc) +{ + if (hc) { + kfree(hc->name); + kfree(hc->uuid); + kfree(hc); + } +} + +/* + * devfs stuff. + */ +static int register_with_devfs(struct hash_cell *hc) +{ + struct gendisk *disk = dm_disk(hc->md); + + devfs_mk_bdev(MKDEV(disk->major, disk->first_minor), + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + DM_DIR "/%s", hc->name); + return 0; +} + +static int unregister_with_devfs(struct hash_cell *hc) +{ + devfs_remove(DM_DIR"/%s", hc->name); + return 0; +} + +/* + * The kdev_t and uuid of a device can never change once it is + * initially inserted. + */ +int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md) +{ + struct hash_cell *cell; + + /* + * Allocate the new cells. + */ + cell = alloc_cell(name, uuid, md); + if (!cell) + return -ENOMEM; + + /* + * Insert the cell into all three hash tables. + */ + down_write(&_hash_lock); + if (__get_name_cell(name)) + goto bad; + + list_add(&cell->name_list, _name_buckets + hash_str(name)); + + if (uuid) { + if (__get_uuid_cell(uuid)) { + list_del(&cell->name_list); + goto bad; + } + list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); + } + register_with_devfs(cell); + dm_get(md); + up_write(&_hash_lock); + + return 0; + + bad: + up_write(&_hash_lock); + free_cell(cell); + return -EBUSY; +} + +void __hash_remove(struct hash_cell *hc) +{ + /* remove from the dev hash */ + list_del(&hc->uuid_list); + list_del(&hc->name_list); + unregister_with_devfs(hc); + dm_put(hc->md); + free_cell(hc); +} + +void dm_hash_remove_all(void) +{ + int i; + struct hash_cell *hc; + struct list_head *tmp, *n; + + down_write(&_hash_lock); + for (i = 0; i < NUM_BUCKETS; i++) { + list_for_each_safe (tmp, n, _name_buckets + i) { + hc = list_entry(tmp, struct hash_cell, name_list); + __hash_remove(hc); + } + } + up_write(&_hash_lock); +} + +int dm_hash_rename(const char *old, const char *new) +{ + char *new_name, *old_name; + struct hash_cell *hc; + + /* + * duplicate new. + */ + new_name = kstrdup(new); + if (!new_name) + return -ENOMEM; + + down_write(&_hash_lock); + + /* + * Is new free ? + */ + hc = __get_name_cell(new); + if (hc) { + DMWARN("asked to rename to an already existing name %s -> %s", + old, new); + up_write(&_hash_lock); + kfree(new_name); + return -EBUSY; + } + + /* + * Is there such a device as 'old' ? + */ + hc = __get_name_cell(old); + if (!hc) { + DMWARN("asked to rename a non existent device %s -> %s", + old, new); + up_write(&_hash_lock); + kfree(new_name); + return -ENXIO; + } + + /* + * rename and move the name cell. + */ + unregister_with_devfs(hc); + + list_del(&hc->name_list); + old_name = hc->name; + hc->name = new_name; + list_add(&hc->name_list, _name_buckets + hash_str(new_name)); + + /* rename the device node in devfs */ + register_with_devfs(hc); + + up_write(&_hash_lock); + kfree(old_name); + return 0; +} + + +/*----------------------------------------------------------------- + * Implementation of the ioctl commands + *---------------------------------------------------------------*/ + +/* + * All the ioctl commands get dispatched to functions with this + * prototype. + */ +typedef int (*ioctl_fn)(struct dm_ioctl *param, struct dm_ioctl *user); + +/* + * Check a string doesn't overrun the chunk of + * memory we copied from userland. + */ +static int valid_str(char *str, void *begin, void *end) +{ + while (((void *) str >= begin) && ((void *) str < end)) + if (!*str++) + return 0; + + return -EINVAL; +} + +static int next_target(struct dm_target_spec *last, uint32_t next, + void *begin, void *end, + struct dm_target_spec **spec, char **params) +{ + *spec = (struct dm_target_spec *) + ((unsigned char *) last + next); + *params = (char *) (*spec + 1); + + if (*spec < (last + 1) || ((void *) *spec > end)) + return -EINVAL; + + return valid_str(*params, begin, end); +} + +static int populate_table(struct dm_table *table, struct dm_ioctl *args) +{ + int r, first = 1; + unsigned int i = 0; + struct dm_target_spec *spec; + char *params; + void *begin, *end; + + if (!args->target_count) { + DMWARN("populate_table: no targets specified"); + return -EINVAL; + } + + begin = (void *) args; + end = begin + args->data_size; + + for (i = 0; i < args->target_count; i++) { + + if (first) + r = next_target((struct dm_target_spec *) args, + args->data_start, + begin, end, &spec, ¶ms); + else + r = next_target(spec, spec->next, begin, end, + &spec, ¶ms); + + if (r) { + DMWARN("unable to find target"); + return -EINVAL; + } + + r = dm_table_add_target(table, spec->target_type, + (sector_t) spec->sector_start, + (sector_t) spec->length, + params); + if (r) { + DMWARN("internal error adding target to table"); + return -EINVAL; + } + + first = 0; + } + + return dm_table_complete(table); +} + +/* + * Round up the ptr to the next 'align' boundary. Obviously + * 'align' must be a power of 2. + */ +static inline void *align_ptr(void *ptr, unsigned int align) +{ + align--; + return (void *) (((unsigned long) (ptr + align)) & ~align); +} + +/* + * Copies a dm_ioctl and an optional additional payload to + * userland. + */ +static int results_to_user(struct dm_ioctl *user, struct dm_ioctl *param, + void *data, uint32_t len) +{ + int r; + void *ptr = NULL; + + if (data) { + ptr = align_ptr(user + 1, sizeof(unsigned long)); + param->data_start = ptr - (void *) user; + } + + /* + * The version number has already been filled in, so we + * just copy later fields. + */ + r = copy_to_user(&user->data_size, ¶m->data_size, + sizeof(*param) - sizeof(param->version)); + if (r) + return -EFAULT; + + if (data) { + if (param->data_start + len > param->data_size) + return -ENOSPC; + + if (copy_to_user(ptr, data, len)) + r = -EFAULT; + } + + return r; +} + +/* + * Fills in a dm_ioctl structure, ready for sending back to + * userland. + */ +static int __info(struct mapped_device *md, struct dm_ioctl *param) +{ + struct dm_table *table; + struct block_device *bdev; + struct gendisk *disk = dm_disk(md); + + param->flags = DM_EXISTS_FLAG; + if (dm_suspended(md)) + param->flags |= DM_SUSPEND_FLAG; + + bdev = bdget_disk(disk, 0); + if (!bdev) + return -ENXIO; + + param->dev = bdev->bd_dev; + param->open_count = bdev->bd_openers; + bdput(bdev); + + if (disk->policy) + param->flags |= DM_READONLY_FLAG; + + table = dm_get_table(md); + param->target_count = dm_table_get_num_targets(table); + dm_table_put(table); + + return 0; +} + +/* + * Always use UUID for lookups if it's present, otherwise use name. + */ +static inline struct mapped_device *find_device(struct dm_ioctl *param) +{ + struct hash_cell *hc; + struct mapped_device *md = NULL; + + down_read(&_hash_lock); + hc = *param->uuid ? __get_uuid_cell(param->uuid) : + __get_name_cell(param->name); + if (hc) { + md = hc->md; + + /* + * Sneakily write in both the name and the uuid + * while we have the cell. + */ + strlcpy(param->name, hc->name, sizeof(param->name)); + if (hc->uuid) + strlcpy(param->uuid, hc->uuid, sizeof(param->uuid)); + else + param->uuid[0] = '\0'; + + dm_get(md); + } + up_read(&_hash_lock); + + return md; +} + +#define ALIGNMENT sizeof(int) +static void *_align(void *ptr, unsigned int a) +{ + register unsigned long align = --a; + + return (void *) (((unsigned long) ptr + align) & ~align); +} + +/* + * Copies device info back to user space, used by + * the create and info ioctls. + */ +static int info(struct dm_ioctl *param, struct dm_ioctl *user) +{ + struct mapped_device *md; + + param->flags = 0; + + md = find_device(param); + if (!md) + /* + * Device not found - returns cleared exists flag. + */ + goto out; + + __info(md, param); + dm_put(md); + + out: + return results_to_user(user, param, NULL, 0); +} + +static inline int get_mode(struct dm_ioctl *param) +{ + int mode = FMODE_READ | FMODE_WRITE; + + if (param->flags & DM_READONLY_FLAG) + mode = FMODE_READ; + + return mode; +} + +static int check_name(const char *name) +{ + if (name[0] == '/') { + DMWARN("invalid device name"); + return -EINVAL; + } + + return 0; +} + +static int create(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int r; + struct dm_table *t; + struct mapped_device *md; + + r = check_name(param->name); + if (r) + return r; + + r = dm_table_create(&t, get_mode(param)); + if (r) + return r; + + r = populate_table(t, param); + if (r) { + dm_table_put(t); + return r; + } + + if (param->flags & DM_PERSISTENT_DEV_FLAG) + r = dm_create_with_minor(minor(to_kdev_t(param->dev)), &md); + else + r = dm_create(&md); + + if (r) { + dm_table_put(t); + return r; + } + + /* suspend the device */ + r = dm_suspend(md); + if (r) { + DMWARN("suspend failed"); + dm_table_put(t); + dm_put(md); + return r; + } + /* swap in the table */ + r = dm_swap_table(md, t); + if (r) { + DMWARN("table swap failed"); + dm_table_put(t); + dm_put(md); + return r; + } + + /* resume the device */ + r = dm_resume(md); + if (r) { + DMWARN("resume failed"); + dm_table_put(t); + dm_put(md); + return r; + } + + dm_table_put(t); /* md will have grabbed its own reference */ + + set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0); + r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md); + dm_put(md); + + return r ? r : info(param, user); +} + +/* + * Build up the status struct for each target + */ +static int __status(struct mapped_device *md, struct dm_ioctl *param, + char *outbuf, size_t *len) +{ + unsigned int i, num_targets; + struct dm_target_spec *spec; + char *outptr; + status_type_t type; + struct dm_table *table = dm_get_table(md); + + if (param->flags & DM_STATUS_TABLE_FLAG) + type = STATUSTYPE_TABLE; + else + type = STATUSTYPE_INFO; + + outptr = outbuf; + + /* Get all the target info */ + num_targets = dm_table_get_num_targets(table); + for (i = 0; i < num_targets; i++) { + struct dm_target *ti = dm_table_get_target(table, i); + + if (outptr - outbuf + + sizeof(struct dm_target_spec) > param->data_size) { + dm_table_put(table); + return -ENOMEM; + } + + spec = (struct dm_target_spec *) outptr; + + spec->status = 0; + spec->sector_start = ti->begin; + spec->length = ti->len; + strlcpy(spec->target_type, ti->type->name, + sizeof(spec->target_type)); + + outptr += sizeof(struct dm_target_spec); + + /* Get the status/table string from the target driver */ + if (ti->type->status) + ti->type->status(ti, type, outptr, + outbuf + param->data_size - outptr); + else + outptr[0] = '\0'; + + outptr += strlen(outptr) + 1; + _align(outptr, ALIGNMENT); + spec->next = outptr - outbuf; + } + + param->target_count = num_targets; + *len = outptr - outbuf; + dm_table_put(table); + + return 0; +} + +/* + * Return the status of a device as a text string for each + * target. + */ +static int get_status(struct dm_ioctl *param, struct dm_ioctl *user) +{ + struct mapped_device *md; + size_t len = 0; + int ret; + char *outbuf = NULL; + + md = find_device(param); + if (!md) + /* + * Device not found - returns cleared exists flag. + */ + goto out; + + /* We haven't a clue how long the resultant data will be so + just allocate as much as userland has allowed us and make sure + we don't overun it */ + outbuf = kmalloc(param->data_size, GFP_KERNEL); + if (!outbuf) + goto out; + /* + * Get the status of all targets + */ + __status(md, param, outbuf, &len); + + /* + * Setup the basic dm_ioctl structure. + */ + __info(md, param); + + out: + if (md) + dm_put(md); + + ret = results_to_user(user, param, outbuf, len); + + if (outbuf) + kfree(outbuf); + + return ret; +} + +/* + * Wait for a device to report an event + */ +static int wait_device_event(struct dm_ioctl *param, struct dm_ioctl *user) +{ + struct mapped_device *md; + DECLARE_WAITQUEUE(wq, current); + + md = find_device(param); + if (!md) + /* + * Device not found - returns cleared exists flag. + */ + goto out; + + /* + * Setup the basic dm_ioctl structure. + */ + __info(md, param); + + /* + * Wait for a notification event + */ + set_current_state(TASK_INTERRUPTIBLE); + if (!dm_add_wait_queue(md, &wq, dm_get_event_nr(md))) { + schedule(); + dm_remove_wait_queue(md, &wq); + } + set_current_state(TASK_RUNNING); + dm_put(md); + + out: + return results_to_user(user, param, NULL, 0); +} + +/* + * Retrieves a list of devices used by a particular dm device. + */ +static int dep(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int r; + unsigned int count; + struct mapped_device *md; + struct list_head *tmp; + size_t len = 0; + struct dm_target_deps *deps = NULL; + struct dm_table *table; + + md = find_device(param); + if (!md) + goto out; + table = dm_get_table(md); + + /* + * Setup the basic dm_ioctl structure. + */ + __info(md, param); + + /* + * Count the devices. + */ + count = 0; + list_for_each(tmp, dm_table_get_devices(table)) + count++; + + /* + * Allocate a kernel space version of the dm_target_status + * struct. + */ + if (array_too_big(sizeof(*deps), sizeof(*deps->dev), count)) { + dm_table_put(table); + dm_put(md); + return -ENOMEM; + } + + len = sizeof(*deps) + (sizeof(*deps->dev) * count); + deps = kmalloc(len, GFP_KERNEL); + if (!deps) { + dm_table_put(table); + dm_put(md); + return -ENOMEM; + } + + /* + * Fill in the devices. + */ + deps->count = count; + count = 0; + list_for_each(tmp, dm_table_get_devices(table)) { + struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); + deps->dev[count++] = dd->bdev->bd_dev; + } + dm_table_put(table); + dm_put(md); + + out: + r = results_to_user(user, param, deps, len); + + kfree(deps); + return r; +} + +static int remove(struct dm_ioctl *param, struct dm_ioctl *user) +{ + struct hash_cell *hc; + + down_write(&_hash_lock); + hc = *param->uuid ? __get_uuid_cell(param->uuid) : + __get_name_cell(param->name); + if (!hc) { + DMWARN("device doesn't appear to be in the dev hash table."); + up_write(&_hash_lock); + return -EINVAL; + } + + /* + * You may ask the interface to drop its reference to an + * in use device. This is no different to unlinking a + * file that someone still has open. The device will not + * actually be destroyed until the last opener closes it. + * The name and uuid of the device (both are interface + * properties) will be available for reuse immediately. + * + * You don't want to drop a _suspended_ device from the + * interface, since that will leave you with no way of + * resuming it. + */ + if (dm_suspended(hc->md)) { + DMWARN("refusing to remove a suspended device."); + up_write(&_hash_lock); + return -EPERM; + } + + __hash_remove(hc); + up_write(&_hash_lock); + return 0; +} + +static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user) +{ + dm_hash_remove_all(); + return 0; +} + +static int suspend(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int r; + struct mapped_device *md; + + md = find_device(param); + if (!md) + return -ENXIO; + + if (param->flags & DM_SUSPEND_FLAG) + r = dm_suspend(md); + else + r = dm_resume(md); + + dm_put(md); + return r; +} + +static int reload(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int r; + struct mapped_device *md; + struct dm_table *t; + + r = dm_table_create(&t, get_mode(param)); + if (r) + return r; + + r = populate_table(t, param); + if (r) { + dm_table_put(t); + return r; + } + + md = find_device(param); + if (!md) { + dm_table_put(t); + return -ENXIO; + } + + r = dm_swap_table(md, t); + if (r) { + dm_put(md); + dm_table_put(t); + return r; + } + dm_table_put(t); /* md will have taken its own reference */ + + set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0); + dm_put(md); + + r = info(param, user); + return r; +} + +static int rename(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int r; + char *new_name = (char *) param + param->data_start; + + if (valid_str(new_name, (void *) param, + (void *) param + param->data_size)) { + DMWARN("Invalid new logical volume name supplied."); + return -EINVAL; + } + + r = check_name(new_name); + if (r) + return r; + + return dm_hash_rename(param->name, new_name); +} + + +/*----------------------------------------------------------------- + * Implementation of open/close/ioctl on the special char + * device. + *---------------------------------------------------------------*/ +static ioctl_fn lookup_ioctl(unsigned int cmd) +{ + static struct { + int cmd; + ioctl_fn fn; + } _ioctls[] = { + {DM_VERSION_CMD, NULL}, /* version is dealt with elsewhere */ + {DM_REMOVE_ALL_CMD, remove_all}, + {DM_DEV_CREATE_CMD, create}, + {DM_DEV_REMOVE_CMD, remove}, + {DM_DEV_RELOAD_CMD, reload}, + {DM_DEV_RENAME_CMD, rename}, + {DM_DEV_SUSPEND_CMD, suspend}, + {DM_DEV_DEPS_CMD, dep}, + {DM_DEV_STATUS_CMD, info}, + {DM_TARGET_STATUS_CMD, get_status}, + {DM_TARGET_WAIT_CMD, wait_device_event}, + }; + + return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; +} + +/* + * As well as checking the version compatibility this always + * copies the kernel interface version out. + */ +static int check_version(unsigned int cmd, struct dm_ioctl *user) +{ + uint32_t version[3]; + int r = 0; + + if (copy_from_user(version, user->version, sizeof(version))) + return -EFAULT; + + if ((DM_VERSION_MAJOR != version[0]) || + (DM_VERSION_MINOR < version[1])) { + DMWARN("ioctl interface mismatch: " + "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)", + DM_VERSION_MAJOR, DM_VERSION_MINOR, + DM_VERSION_PATCHLEVEL, + version[0], version[1], version[2], cmd); + r = -EINVAL; + } + + /* + * Fill in the kernel version. + */ + version[0] = DM_VERSION_MAJOR; + version[1] = DM_VERSION_MINOR; + version[2] = DM_VERSION_PATCHLEVEL; + if (copy_to_user(user->version, version, sizeof(version))) + return -EFAULT; + + return r; +} + +static void free_params(struct dm_ioctl *param) +{ + vfree(param); +} + +static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param) +{ + struct dm_ioctl tmp, *dmi; + + if (copy_from_user(&tmp, user, sizeof(tmp))) + return -EFAULT; + + if (tmp.data_size < sizeof(tmp)) + return -EINVAL; + + dmi = (struct dm_ioctl *) vmalloc(tmp.data_size); + if (!dmi) + return -ENOMEM; + + if (copy_from_user(dmi, user, tmp.data_size)) { + vfree(dmi); + return -EFAULT; + } + + *param = dmi; + return 0; +} + +static int validate_params(uint cmd, struct dm_ioctl *param) +{ + /* Ignores parameters */ + if (cmd == DM_REMOVE_ALL_CMD) + return 0; + + /* Unless creating, either name of uuid but not both */ + if (cmd != DM_DEV_CREATE_CMD) { + if ((!*param->uuid && !*param->name) || + (*param->uuid && *param->name)) { + DMWARN("one of name or uuid must be supplied"); + return -EINVAL; + } + } + + /* Ensure strings are terminated */ + param->name[DM_NAME_LEN - 1] = '\0'; + param->uuid[DM_UUID_LEN - 1] = '\0'; + + return 0; +} + +static int ctl_ioctl(struct inode *inode, struct file *file, + uint command, ulong u) +{ + int r = 0; + unsigned int cmd; + struct dm_ioctl *param; + struct dm_ioctl *user = (struct dm_ioctl *) u; + ioctl_fn fn = NULL; + + /* only root can play with this */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (_IOC_TYPE(command) != DM_IOCTL) + return -ENOTTY; + + cmd = _IOC_NR(command); + + /* + * Check the interface version passed in. This also + * writes out the kernels interface version. + */ + r = check_version(cmd, user); + if (r) + return r; + + /* + * Nothing more to do for the version command. + */ + if (cmd == DM_VERSION_CMD) + return 0; + + fn = lookup_ioctl(cmd); + if (!fn) { + DMWARN("dm_ctl_ioctl: unknown command 0x%x", command); + return -ENOTTY; + } + + /* + * Copy the parameters into kernel space. + */ + r = copy_params(user, ¶m); + if (r) + return r; + + r = validate_params(cmd, param); + if (r) { + free_params(param); + return r; + } + + r = fn(param, user); + free_params(param); + return r; +} + +static struct file_operations _ctl_fops = { + .ioctl = ctl_ioctl, + .owner = THIS_MODULE, +}; + +static struct miscdevice _dm_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = DM_NAME, + .devfs_name = "mapper/control", + .fops = &_ctl_fops +}; + +/* + * Create misc character device and link to DM_DIR/control. + */ +int __init dm_interface_init(void) +{ + int r; + + r = dm_hash_init(); + if (r) + return r; + + r = misc_register(&_dm_misc); + if (r) { + DMERR("misc_register failed for control device"); + dm_hash_exit(); + return r; + } + + DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR, + DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA, + DM_DRIVER_EMAIL); + return 0; + + if (misc_deregister(&_dm_misc) < 0) + DMERR("misc_deregister failed for control device"); + dm_hash_exit(); + return r; +} + +void dm_interface_exit(void) +{ + if (misc_deregister(&_dm_misc) < 0) + DMERR("misc_deregister failed for control device"); + dm_hash_exit(); +} diff --git a/drivers/md/dm-ioctl-v4.c b/drivers/md/dm-ioctl-v4.c new file mode 100644 index 000000000000..7360254999da --- /dev/null +++ b/drivers/md/dm-ioctl-v4.c @@ -0,0 +1,1252 @@ +/* + * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include "dm.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DM_DRIVER_EMAIL "dm@uk.sistina.com" + +/*----------------------------------------------------------------- + * The ioctl interface needs to be able to look up devices by + * name or uuid. + *---------------------------------------------------------------*/ +struct hash_cell { + struct list_head name_list; + struct list_head uuid_list; + + char *name; + char *uuid; + struct mapped_device *md; + struct dm_table *new_map; +}; + +#define NUM_BUCKETS 64 +#define MASK_BUCKETS (NUM_BUCKETS - 1) +static struct list_head _name_buckets[NUM_BUCKETS]; +static struct list_head _uuid_buckets[NUM_BUCKETS]; + +void dm_hash_remove_all(void); + +/* + * Guards access to both hash tables. + */ +static DECLARE_RWSEM(_hash_lock); + +static void init_buckets(struct list_head *buckets) +{ + unsigned int i; + + for (i = 0; i < NUM_BUCKETS; i++) + INIT_LIST_HEAD(buckets + i); +} + +int dm_hash_init(void) +{ + init_buckets(_name_buckets); + init_buckets(_uuid_buckets); + devfs_mk_dir(DM_DIR); + return 0; +} + +void dm_hash_exit(void) +{ + dm_hash_remove_all(); + devfs_remove(DM_DIR); +} + +/*----------------------------------------------------------------- + * Hash function: + * We're not really concerned with the str hash function being + * fast since it's only used by the ioctl interface. + *---------------------------------------------------------------*/ +static unsigned int hash_str(const char *str) +{ + const unsigned int hash_mult = 2654435387U; + unsigned int h = 0; + + while (*str) + h = (h + (unsigned int) *str++) * hash_mult; + + return h & MASK_BUCKETS; +} + +/*----------------------------------------------------------------- + * Code for looking up a device by name + *---------------------------------------------------------------*/ +static struct hash_cell *__get_name_cell(const char *str) +{ + struct list_head *tmp; + struct hash_cell *hc; + unsigned int h = hash_str(str); + + list_for_each (tmp, _name_buckets + h) { + hc = list_entry(tmp, struct hash_cell, name_list); + if (!strcmp(hc->name, str)) + return hc; + } + + return NULL; +} + +static struct hash_cell *__get_uuid_cell(const char *str) +{ + struct list_head *tmp; + struct hash_cell *hc; + unsigned int h = hash_str(str); + + list_for_each (tmp, _uuid_buckets + h) { + hc = list_entry(tmp, struct hash_cell, uuid_list); + if (!strcmp(hc->uuid, str)) + return hc; + } + + return NULL; +} + +/*----------------------------------------------------------------- + * Inserting, removing and renaming a device. + *---------------------------------------------------------------*/ +static inline char *kstrdup(const char *str) +{ + char *r = kmalloc(strlen(str) + 1, GFP_KERNEL); + if (r) + strcpy(r, str); + return r; +} + +static struct hash_cell *alloc_cell(const char *name, const char *uuid, + struct mapped_device *md) +{ + struct hash_cell *hc; + + hc = kmalloc(sizeof(*hc), GFP_KERNEL); + if (!hc) + return NULL; + + hc->name = kstrdup(name); + if (!hc->name) { + kfree(hc); + return NULL; + } + + if (!uuid) + hc->uuid = NULL; + + else { + hc->uuid = kstrdup(uuid); + if (!hc->uuid) { + kfree(hc->name); + kfree(hc); + return NULL; + } + } + + INIT_LIST_HEAD(&hc->name_list); + INIT_LIST_HEAD(&hc->uuid_list); + hc->md = md; + hc->new_map = NULL; + return hc; +} + +static void free_cell(struct hash_cell *hc) +{ + if (hc) { + kfree(hc->name); + kfree(hc->uuid); + kfree(hc); + } +} + +/* + * devfs stuff. + */ +static int register_with_devfs(struct hash_cell *hc) +{ + struct gendisk *disk = dm_disk(hc->md); + + devfs_mk_bdev(MKDEV(disk->major, disk->first_minor), + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + DM_DIR "/%s", hc->name); + return 0; +} + +static int unregister_with_devfs(struct hash_cell *hc) +{ + devfs_remove(DM_DIR"/%s", hc->name); + return 0; +} + +/* + * The kdev_t and uuid of a device can never change once it is + * initially inserted. + */ +int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md) +{ + struct hash_cell *cell; + + /* + * Allocate the new cells. + */ + cell = alloc_cell(name, uuid, md); + if (!cell) + return -ENOMEM; + + /* + * Insert the cell into both hash tables. + */ + down_write(&_hash_lock); + if (__get_name_cell(name)) + goto bad; + + list_add(&cell->name_list, _name_buckets + hash_str(name)); + + if (uuid) { + if (__get_uuid_cell(uuid)) { + list_del(&cell->name_list); + goto bad; + } + list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); + } + register_with_devfs(cell); + dm_get(md); + up_write(&_hash_lock); + + return 0; + + bad: + up_write(&_hash_lock); + free_cell(cell); + return -EBUSY; +} + +void __hash_remove(struct hash_cell *hc) +{ + /* remove from the dev hash */ + list_del(&hc->uuid_list); + list_del(&hc->name_list); + unregister_with_devfs(hc); + dm_put(hc->md); + if (hc->new_map) + dm_table_put(hc->new_map); + free_cell(hc); +} + +void dm_hash_remove_all(void) +{ + int i; + struct hash_cell *hc; + struct list_head *tmp, *n; + + down_write(&_hash_lock); + for (i = 0; i < NUM_BUCKETS; i++) { + list_for_each_safe (tmp, n, _name_buckets + i) { + hc = list_entry(tmp, struct hash_cell, name_list); + __hash_remove(hc); + } + } + up_write(&_hash_lock); +} + +int dm_hash_rename(const char *old, const char *new) +{ + char *new_name, *old_name; + struct hash_cell *hc; + + /* + * duplicate new. + */ + new_name = kstrdup(new); + if (!new_name) + return -ENOMEM; + + down_write(&_hash_lock); + + /* + * Is new free ? + */ + hc = __get_name_cell(new); + if (hc) { + DMWARN("asked to rename to an already existing name %s -> %s", + old, new); + up_write(&_hash_lock); + kfree(new_name); + return -EBUSY; + } + + /* + * Is there such a device as 'old' ? + */ + hc = __get_name_cell(old); + if (!hc) { + DMWARN("asked to rename a non existent device %s -> %s", + old, new); + up_write(&_hash_lock); + kfree(new_name); + return -ENXIO; + } + + /* + * rename and move the name cell. + */ + unregister_with_devfs(hc); + + list_del(&hc->name_list); + old_name = hc->name; + hc->name = new_name; + list_add(&hc->name_list, _name_buckets + hash_str(new_name)); + + /* rename the device node in devfs */ + register_with_devfs(hc); + + up_write(&_hash_lock); + kfree(old_name); + return 0; +} + +/*----------------------------------------------------------------- + * Implementation of the ioctl commands + *---------------------------------------------------------------*/ +/* + * All the ioctl commands get dispatched to functions with this + * prototype. + */ +typedef int (*ioctl_fn)(struct dm_ioctl *param, size_t param_size); + +static int remove_all(struct dm_ioctl *param, size_t param_size) +{ + dm_hash_remove_all(); + param->data_size = 0; + return 0; +} + +/* + * Round up the ptr to an 8-byte boundary. + */ +#define ALIGN_MASK 7 +static inline void *align_ptr(void *ptr) +{ + return (void *) (((size_t) (ptr + ALIGN_MASK)) & ~ALIGN_MASK); +} + +/* + * Retrieves the data payload buffer from an already allocated + * struct dm_ioctl. + */ +static void *get_result_buffer(struct dm_ioctl *param, size_t param_size, + size_t *len) +{ + param->data_start = align_ptr(param + 1) - (void *) param; + + if (param->data_start < param_size) + *len = param_size - param->data_start; + else + *len = 0; + + return ((void *) param) + param->data_start; +} + +static int list_devices(struct dm_ioctl *param, size_t param_size) +{ + unsigned int i; + struct hash_cell *hc; + size_t len, needed = 0; + struct gendisk *disk; + struct dm_name_list *nl, *old_nl = NULL; + + down_write(&_hash_lock); + + /* + * Loop through all the devices working out how much + * space we need. + */ + for (i = 0; i < NUM_BUCKETS; i++) { + list_for_each_entry (hc, _name_buckets + i, name_list) { + needed += sizeof(struct dm_name_list); + needed += strlen(hc->name); + needed += ALIGN_MASK; + } + } + + /* + * Grab our output buffer. + */ + nl = get_result_buffer(param, param_size, &len); + if (len < needed) { + param->flags |= DM_BUFFER_FULL_FLAG; + goto out; + } + param->data_size = param->data_start + needed; + + nl->dev = 0; /* Flags no data */ + + /* + * Now loop through filling out the names. + */ + for (i = 0; i < NUM_BUCKETS; i++) { + list_for_each_entry (hc, _name_buckets + i, name_list) { + if (old_nl) + old_nl->next = (uint32_t) ((void *) nl - + (void *) old_nl); + disk = dm_disk(hc->md); + nl->dev = MKDEV(disk->major, disk->first_minor); + nl->next = 0; + strcpy(nl->name, hc->name); + + old_nl = nl; + nl = align_ptr(((void *) ++nl) + strlen(hc->name) + 1); + } + } + + out: + up_write(&_hash_lock); + return 0; +} + +static int check_name(const char *name) +{ + if (strchr(name, '/')) { + DMWARN("invalid device name"); + return -EINVAL; + } + + return 0; +} + +/* + * Fills in a dm_ioctl structure, ready for sending back to + * userland. + */ +static int __dev_status(struct mapped_device *md, struct dm_ioctl *param) +{ + struct gendisk *disk = dm_disk(md); + struct dm_table *table; + struct block_device *bdev; + + param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG | + DM_ACTIVE_PRESENT_FLAG); + + if (dm_suspended(md)) + param->flags |= DM_SUSPEND_FLAG; + + bdev = bdget_disk(disk, 0); + if (!bdev) + return -ENXIO; + + param->dev = MKDEV(disk->major, disk->first_minor); + + /* + * Yes, this will be out of date by the time it gets back + * to userland, but it is still very useful ofr + * debugging. + */ + param->open_count = bdev->bd_openers; + bdput(bdev); + + if (disk->policy) + param->flags |= DM_READONLY_FLAG; + + param->event_nr = dm_get_event_nr(md); + + table = dm_get_table(md); + if (table) { + param->flags |= DM_ACTIVE_PRESENT_FLAG; + param->target_count = dm_table_get_num_targets(table); + dm_table_put(table); + } else + param->target_count = 0; + + return 0; +} + +static int dev_create(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct mapped_device *md; + + r = check_name(param->name); + if (r) + return r; + + if (param->flags & DM_PERSISTENT_DEV_FLAG) + r = dm_create_with_minor(minor(to_kdev_t(param->dev)), &md); + else + r = dm_create(&md); + + if (r) + return r; + + r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md); + if (r) { + dm_put(md); + return r; + } + + param->flags &= ~DM_INACTIVE_PRESENT_FLAG; + + r = __dev_status(md, param); + dm_put(md); + + return r; +} + +/* + * Always use UUID for lookups if it's present, otherwise use name. + */ +static inline struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param) +{ + return *param->uuid ? + __get_uuid_cell(param->uuid) : __get_name_cell(param->name); +} + +static inline struct mapped_device *find_device(struct dm_ioctl *param) +{ + struct hash_cell *hc; + struct mapped_device *md = NULL; + + down_read(&_hash_lock); + hc = __find_device_hash_cell(param); + if (hc) { + md = hc->md; + + /* + * Sneakily write in both the name and the uuid + * while we have the cell. + */ + strncpy(param->name, hc->name, sizeof(param->name)); + if (hc->uuid) + strncpy(param->uuid, hc->uuid, sizeof(param->uuid)-1); + else + param->uuid[0] = '\0'; + + if (hc->new_map) + param->flags |= DM_INACTIVE_PRESENT_FLAG; + else + param->flags &= ~DM_INACTIVE_PRESENT_FLAG; + + dm_get(md); + } + up_read(&_hash_lock); + + return md; +} + +static int dev_remove(struct dm_ioctl *param, size_t param_size) +{ + struct hash_cell *hc; + + down_write(&_hash_lock); + hc = __find_device_hash_cell(param); + + if (!hc) { + DMWARN("device doesn't appear to be in the dev hash table."); + up_write(&_hash_lock); + return -ENXIO; + } + + __hash_remove(hc); + up_write(&_hash_lock); + param->data_size = 0; + return 0; +} + +/* + * Check a string doesn't overrun the chunk of + * memory we copied from userland. + */ +static int invalid_str(char *str, void *end) +{ + while ((void *) str < end) + if (!*str++) + return 0; + + return -EINVAL; +} + +static int dev_rename(struct dm_ioctl *param, size_t param_size) +{ + int r; + char *new_name = (char *) param + param->data_start; + + if (new_name < (char *) (param + 1) || + invalid_str(new_name, (void *) param + param_size)) { + DMWARN("Invalid new logical volume name supplied."); + return -EINVAL; + } + + r = check_name(new_name); + if (r) + return r; + + param->data_size = 0; + return dm_hash_rename(param->name, new_name); +} + +static int suspend(struct dm_ioctl *param) +{ + int r = 0; + struct mapped_device *md; + + md = find_device(param); + if (!md) + return -ENXIO; + + if (!dm_suspended(md)) + r = dm_suspend(md); + + if (!r) + r = __dev_status(md, param); + + dm_put(md); + return r; +} + +static int resume(struct dm_ioctl *param) +{ + int r = 0; + struct hash_cell *hc; + struct mapped_device *md; + struct dm_table *new_map; + + down_write(&_hash_lock); + + hc = __find_device_hash_cell(param); + if (!hc) { + DMWARN("device doesn't appear to be in the dev hash table."); + up_write(&_hash_lock); + return -ENXIO; + } + + md = hc->md; + dm_get(md); + + new_map = hc->new_map; + hc->new_map = NULL; + param->flags &= ~DM_INACTIVE_PRESENT_FLAG; + + up_write(&_hash_lock); + + /* Do we need to load a new map ? */ + if (new_map) { + /* Suspend if it isn't already suspended */ + if (!dm_suspended(md)) + dm_suspend(md); + + r = dm_swap_table(md, new_map); + if (r) { + dm_put(md); + dm_table_put(new_map); + return r; + } + + if (dm_table_get_mode(new_map) & FMODE_WRITE) + set_disk_ro(dm_disk(md), 0); + else + set_disk_ro(dm_disk(md), 1); + + dm_table_put(new_map); + } + + if (dm_suspended(md)) + r = dm_resume(md); + + if (!r) + r = __dev_status(md, param); + + dm_put(md); + return r; +} + +/* + * Set or unset the suspension state of a device. + * If the device already is in the requested state we just return its status. + */ +static int dev_suspend(struct dm_ioctl *param, size_t param_size) +{ + if (param->flags & DM_SUSPEND_FLAG) + return suspend(param); + + return resume(param); +} + +/* + * Copies device info back to user space, used by + * the create and info ioctls. + */ +static int dev_status(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct mapped_device *md; + + md = find_device(param); + if (!md) + return -ENXIO; + + r = __dev_status(md, param); + dm_put(md); + return r; +} + +/* + * Wait for a device to report an event + */ +static int dev_wait(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct mapped_device *md; + DECLARE_WAITQUEUE(wq, current); + + md = find_device(param); + if (!md) + return -ENXIO; + + /* + * Wait for a notification event + */ + set_current_state(TASK_INTERRUPTIBLE); + if (!dm_add_wait_queue(md, &wq, param->event_nr)) { + schedule(); + dm_remove_wait_queue(md, &wq); + } + set_current_state(TASK_RUNNING); + + /* + * The userland program is going to want to know what + * changed to trigger the event, so we may as well tell + * him and save an ioctl. + */ + r = __dev_status(md, param); + + dm_put(md); + return r; +} + +static inline int get_mode(struct dm_ioctl *param) +{ + int mode = FMODE_READ | FMODE_WRITE; + + if (param->flags & DM_READONLY_FLAG) + mode = FMODE_READ; + + return mode; +} + +static int next_target(struct dm_target_spec *last, uint32_t next, void *end, + struct dm_target_spec **spec, char **target_params) +{ + *spec = (struct dm_target_spec *) ((unsigned char *) last + next); + *target_params = (char *) (*spec + 1); + + if (*spec < (last + 1)) + return -EINVAL; + + return invalid_str(*target_params, end); +} + +static int populate_table(struct dm_table *table, + struct dm_ioctl *param, size_t param_size) +{ + int r; + unsigned int i = 0; + struct dm_target_spec *spec = (struct dm_target_spec *) param; + uint32_t next = param->data_start; + void *end = (void *) param + param_size; + char *target_params; + + if (!param->target_count) { + DMWARN("populate_table: no targets specified"); + return -EINVAL; + } + + for (i = 0; i < param->target_count; i++) { + + r = next_target(spec, next, end, &spec, &target_params); + if (r) { + DMWARN("unable to find target"); + return r; + } + + r = dm_table_add_target(table, spec->target_type, + (sector_t) spec->sector_start, + (sector_t) spec->length, + target_params); + if (r) { + DMWARN("error adding target to table"); + return r; + } + + next = spec->next; + } + + return dm_table_complete(table); +} + +static int table_load(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct hash_cell *hc; + struct dm_table *t; + + r = dm_table_create(&t, get_mode(param)); + if (r) + return r; + + r = populate_table(t, param, param_size); + if (r) { + dm_table_put(t); + return r; + } + + down_write(&_hash_lock); + hc = __find_device_hash_cell(param); + if (!hc) { + DMWARN("device doesn't appear to be in the dev hash table."); + up_write(&_hash_lock); + return -ENXIO; + } + + hc->new_map = t; + param->flags |= DM_INACTIVE_PRESENT_FLAG; + + r = __dev_status(hc->md, param); + up_write(&_hash_lock); + return r; +} + +static int table_clear(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct hash_cell *hc; + + down_write(&_hash_lock); + + hc = __find_device_hash_cell(param); + if (!hc) { + DMWARN("device doesn't appear to be in the dev hash table."); + up_write(&_hash_lock); + return -ENXIO; + } + + if (hc->new_map) { + dm_table_put(hc->new_map); + hc->new_map = NULL; + } + + param->flags &= ~DM_INACTIVE_PRESENT_FLAG; + + r = __dev_status(hc->md, param); + up_write(&_hash_lock); + return r; +} + +/* + * Retrieves a list of devices used by a particular dm device. + */ +static void retrieve_deps(struct dm_table *table, + struct dm_ioctl *param, size_t param_size) +{ + unsigned int count = 0; + struct list_head *tmp; + size_t len, needed; + struct dm_target_deps *deps; + + deps = get_result_buffer(param, param_size, &len); + + /* + * Count the devices. + */ + list_for_each(tmp, dm_table_get_devices(table)) + count++; + + /* + * Check we have enough space. + */ + needed = sizeof(*deps) + (sizeof(*deps->dev) * count); + if (len < needed) { + param->flags |= DM_BUFFER_FULL_FLAG; + return; + } + + /* + * Fill in the devices. + */ + deps->count = count; + count = 0; + list_for_each(tmp, dm_table_get_devices(table)) { + struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); + deps->dev[count++] = dd->bdev->bd_dev; + } + + param->data_size = param->data_start + needed; +} + +static int table_deps(struct dm_ioctl *param, size_t param_size) +{ + int r = 0; + struct mapped_device *md; + struct dm_table *table; + + md = find_device(param); + if (!md) + return -ENXIO; + + r = __dev_status(md, param); + if (r) + goto out; + + table = dm_get_table(md); + if (table) { + retrieve_deps(table, param, param_size); + dm_table_put(table); + } + + out: + dm_put(md); + return r; +} + +/* + * Build up the status struct for each target + */ +static void retrieve_status(struct dm_table *table, + struct dm_ioctl *param, size_t param_size) +{ + unsigned int i, num_targets; + struct dm_target_spec *spec; + char *outbuf, *outptr; + status_type_t type; + size_t remaining, len, used = 0; + + outptr = outbuf = get_result_buffer(param, param_size, &len); + + if (param->flags & DM_STATUS_TABLE_FLAG) + type = STATUSTYPE_TABLE; + else + type = STATUSTYPE_INFO; + + /* Get all the target info */ + num_targets = dm_table_get_num_targets(table); + for (i = 0; i < num_targets; i++) { + struct dm_target *ti = dm_table_get_target(table, i); + + remaining = len - (outptr - outbuf); + if (remaining < sizeof(struct dm_target_spec)) { + param->flags |= DM_BUFFER_FULL_FLAG; + break; + } + + spec = (struct dm_target_spec *) outptr; + + spec->status = 0; + spec->sector_start = ti->begin; + spec->length = ti->len; + strncpy(spec->target_type, ti->type->name, + sizeof(spec->target_type)); + + outptr += sizeof(struct dm_target_spec); + remaining = len - (outptr - outbuf); + + /* Get the status/table string from the target driver */ + if (ti->type->status) { + if (ti->type->status(ti, type, outptr, remaining)) { + param->flags |= DM_BUFFER_FULL_FLAG; + break; + } + } else + outptr[0] = '\0'; + + outptr += strlen(outptr) + 1; + used = param->data_start + (outptr - outbuf); + + align_ptr(outptr); + spec->next = outptr - outbuf; + } + + if (used) + param->data_size = used; + + param->target_count = num_targets; +} + +/* + * Return the status of a device as a text string for each + * target. + */ +static int table_status(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct mapped_device *md; + struct dm_table *table; + + md = find_device(param); + if (!md) + return -ENXIO; + + r = __dev_status(md, param); + if (r) + goto out; + + table = dm_get_table(md); + if (table) { + retrieve_status(table, param, param_size); + dm_table_put(table); + } + + out: + dm_put(md); + return r; +} + +/*----------------------------------------------------------------- + * Implementation of open/close/ioctl on the special char + * device. + *---------------------------------------------------------------*/ +static ioctl_fn lookup_ioctl(unsigned int cmd) +{ + static struct { + int cmd; + ioctl_fn fn; + } _ioctls[] = { + {DM_VERSION_CMD, NULL}, /* version is dealt with elsewhere */ + {DM_REMOVE_ALL_CMD, remove_all}, + {DM_LIST_DEVICES_CMD, list_devices}, + + {DM_DEV_CREATE_CMD, dev_create}, + {DM_DEV_REMOVE_CMD, dev_remove}, + {DM_DEV_RENAME_CMD, dev_rename}, + {DM_DEV_SUSPEND_CMD, dev_suspend}, + {DM_DEV_STATUS_CMD, dev_status}, + {DM_DEV_WAIT_CMD, dev_wait}, + + {DM_TABLE_LOAD_CMD, table_load}, + {DM_TABLE_CLEAR_CMD, table_clear}, + {DM_TABLE_DEPS_CMD, table_deps}, + {DM_TABLE_STATUS_CMD, table_status} + }; + + return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; +} + +/* + * As well as checking the version compatibility this always + * copies the kernel interface version out. + */ +static int check_version(unsigned int cmd, struct dm_ioctl *user) +{ + uint32_t version[3]; + int r = 0; + + if (copy_from_user(version, user->version, sizeof(version))) + return -EFAULT; + + if ((DM_VERSION_MAJOR != version[0]) || + (DM_VERSION_MINOR < version[1])) { + DMWARN("ioctl interface mismatch: " + "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)", + DM_VERSION_MAJOR, DM_VERSION_MINOR, + DM_VERSION_PATCHLEVEL, + version[0], version[1], version[2], cmd); + r = -EINVAL; + } + + /* + * Fill in the kernel version. + */ + version[0] = DM_VERSION_MAJOR; + version[1] = DM_VERSION_MINOR; + version[2] = DM_VERSION_PATCHLEVEL; + if (copy_to_user(user->version, version, sizeof(version))) + return -EFAULT; + + return r; +} + +static void free_params(struct dm_ioctl *param) +{ + vfree(param); +} + +static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param) +{ + struct dm_ioctl tmp, *dmi; + + if (copy_from_user(&tmp, user, sizeof(tmp))) + return -EFAULT; + + if (tmp.data_size < sizeof(tmp)) + return -EINVAL; + + dmi = (struct dm_ioctl *) vmalloc(tmp.data_size); + if (!dmi) + return -ENOMEM; + + if (copy_from_user(dmi, user, tmp.data_size)) { + vfree(dmi); + return -EFAULT; + } + + *param = dmi; + return 0; +} + +static int validate_params(uint cmd, struct dm_ioctl *param) +{ + /* Always clear this flag */ + param->flags &= ~DM_BUFFER_FULL_FLAG; + + /* Ignores parameters */ + if (cmd == DM_REMOVE_ALL_CMD || cmd == DM_LIST_DEVICES_CMD) + return 0; + + /* Unless creating, either name or uuid but not both */ + if (cmd != DM_DEV_CREATE_CMD) { + if ((!*param->uuid && !*param->name) || + (*param->uuid && *param->name)) { + DMWARN("one of name or uuid must be supplied, cmd(%u)", + cmd); + return -EINVAL; + } + } + + /* Ensure strings are terminated */ + param->name[DM_NAME_LEN - 1] = '\0'; + param->uuid[DM_UUID_LEN - 1] = '\0'; + + return 0; +} + +static int ctl_ioctl(struct inode *inode, struct file *file, + uint command, ulong u) +{ + int r = 0; + unsigned int cmd; + struct dm_ioctl *param; + struct dm_ioctl *user = (struct dm_ioctl *) u; + ioctl_fn fn = NULL; + size_t param_size; + + /* only root can play with this */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (_IOC_TYPE(command) != DM_IOCTL) + return -ENOTTY; + + cmd = _IOC_NR(command); + + /* + * Check the interface version passed in. This also + * writes out the kernel's interface version. + */ + r = check_version(cmd, user); + if (r) + return r; + + /* + * Nothing more to do for the version command. + */ + if (cmd == DM_VERSION_CMD) + return 0; + + fn = lookup_ioctl(cmd); + if (!fn) { + DMWARN("dm_ctl_ioctl: unknown command 0x%x", command); + return -ENOTTY; + } + + /* + * Trying to avoid low memory issues when a device is + * suspended. + */ + current->flags |= PF_MEMALLOC; + + /* + * Copy the parameters into kernel space. + */ + r = copy_params(user, ¶m); + if (r) { + current->flags &= ~PF_MEMALLOC; + return r; + } + + /* + * FIXME: eventually we will remove the PF_MEMALLOC flag + * here. However the tools still do nasty things like + * 'load' while a device is suspended. + */ + + r = validate_params(cmd, param); + if (r) + goto out; + + param_size = param->data_size; + param->data_size = sizeof(*param); + r = fn(param, param_size); + + /* + * Copy the results back to userland. + */ + if (!r && copy_to_user(user, param, param->data_size)) + r = -EFAULT; + + out: + free_params(param); + current->flags &= ~PF_MEMALLOC; + return r; +} + +static struct file_operations _ctl_fops = { + .ioctl = ctl_ioctl, + .owner = THIS_MODULE, +}; + +static struct miscdevice _dm_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = DM_NAME, + .devfs_name = "mapper/control", + .fops = &_ctl_fops +}; + +/* + * Create misc character device and link to DM_DIR/control. + */ +int __init dm_interface_init(void) +{ + int r; + + r = dm_hash_init(); + if (r) + return r; + + r = misc_register(&_dm_misc); + if (r) { + DMERR("misc_register failed for control device"); + dm_hash_exit(); + return r; + } + + DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR, + DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA, + DM_DRIVER_EMAIL); + return 0; +} + +void dm_interface_exit(void) +{ + if (misc_deregister(&_dm_misc) < 0) + DMERR("misc_deregister failed for control device"); + + dm_hash_exit(); +} diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 82c5d8b94e30..9af8a5a9b1e8 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1,1132 +1,13 @@ /* - * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. + * Copyright (C) 2003 Sistina Software (UK) Limited. * * This file is released under the GPL. */ -#include "dm.h" - -#include -#include -#include #include -#include -#include -#include -#include - -#include - -#define DM_DRIVER_EMAIL "dm@uk.sistina.com" - -/*----------------------------------------------------------------- - * The ioctl interface needs to be able to look up devices by - * name or uuid. - *---------------------------------------------------------------*/ -struct hash_cell { - struct list_head name_list; - struct list_head uuid_list; - - char *name; - char *uuid; - struct mapped_device *md; -}; - -#define NUM_BUCKETS 64 -#define MASK_BUCKETS (NUM_BUCKETS - 1) -static struct list_head _name_buckets[NUM_BUCKETS]; -static struct list_head _uuid_buckets[NUM_BUCKETS]; - -void dm_hash_remove_all(void); - -/* - * Guards access to all three tables. - */ -static DECLARE_RWSEM(_hash_lock); - -static void init_buckets(struct list_head *buckets) -{ - unsigned int i; - - for (i = 0; i < NUM_BUCKETS; i++) - INIT_LIST_HEAD(buckets + i); -} - -int dm_hash_init(void) -{ - init_buckets(_name_buckets); - init_buckets(_uuid_buckets); - devfs_mk_dir(DM_DIR); - return 0; -} - -void dm_hash_exit(void) -{ - dm_hash_remove_all(); - devfs_remove(DM_DIR); -} - -/*----------------------------------------------------------------- - * Hash function: - * We're not really concerned with the str hash function being - * fast since it's only used by the ioctl interface. - *---------------------------------------------------------------*/ -static unsigned int hash_str(const char *str) -{ - const unsigned int hash_mult = 2654435387U; - unsigned int h = 0; - - while (*str) - h = (h + (unsigned int) *str++) * hash_mult; - - return h & MASK_BUCKETS; -} - -/*----------------------------------------------------------------- - * Code for looking up a device by name - *---------------------------------------------------------------*/ -static struct hash_cell *__get_name_cell(const char *str) -{ - struct list_head *tmp; - struct hash_cell *hc; - unsigned int h = hash_str(str); - - list_for_each (tmp, _name_buckets + h) { - hc = list_entry(tmp, struct hash_cell, name_list); - if (!strcmp(hc->name, str)) - return hc; - } - - return NULL; -} - -static struct hash_cell *__get_uuid_cell(const char *str) -{ - struct list_head *tmp; - struct hash_cell *hc; - unsigned int h = hash_str(str); - - list_for_each (tmp, _uuid_buckets + h) { - hc = list_entry(tmp, struct hash_cell, uuid_list); - if (!strcmp(hc->uuid, str)) - return hc; - } - - return NULL; -} - -/*----------------------------------------------------------------- - * Inserting, removing and renaming a device. - *---------------------------------------------------------------*/ -static inline char *kstrdup(const char *str) -{ - char *r = kmalloc(strlen(str) + 1, GFP_KERNEL); - if (r) - strcpy(r, str); - return r; -} - -static struct hash_cell *alloc_cell(const char *name, const char *uuid, - struct mapped_device *md) -{ - struct hash_cell *hc; - - hc = kmalloc(sizeof(*hc), GFP_KERNEL); - if (!hc) - return NULL; - - hc->name = kstrdup(name); - if (!hc->name) { - kfree(hc); - return NULL; - } - - if (!uuid) - hc->uuid = NULL; - - else { - hc->uuid = kstrdup(uuid); - if (!hc->uuid) { - kfree(hc->name); - kfree(hc); - return NULL; - } - } - - INIT_LIST_HEAD(&hc->name_list); - INIT_LIST_HEAD(&hc->uuid_list); - hc->md = md; - return hc; -} - -static void free_cell(struct hash_cell *hc) -{ - if (hc) { - kfree(hc->name); - kfree(hc->uuid); - kfree(hc); - } -} - -/* - * devfs stuff. - */ -static int register_with_devfs(struct hash_cell *hc) -{ - struct gendisk *disk = dm_disk(hc->md); - - devfs_mk_bdev(MKDEV(disk->major, disk->first_minor), - S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, - DM_DIR "/%s", hc->name); - return 0; -} - -static int unregister_with_devfs(struct hash_cell *hc) -{ - devfs_remove(DM_DIR"/%s", hc->name); - return 0; -} - -/* - * The kdev_t and uuid of a device can never change once it is - * initially inserted. - */ -int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md) -{ - struct hash_cell *cell; - - /* - * Allocate the new cells. - */ - cell = alloc_cell(name, uuid, md); - if (!cell) - return -ENOMEM; - - /* - * Insert the cell into all three hash tables. - */ - down_write(&_hash_lock); - if (__get_name_cell(name)) - goto bad; - - list_add(&cell->name_list, _name_buckets + hash_str(name)); - - if (uuid) { - if (__get_uuid_cell(uuid)) { - list_del(&cell->name_list); - goto bad; - } - list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); - } - register_with_devfs(cell); - dm_get(md); - up_write(&_hash_lock); - - return 0; - - bad: - up_write(&_hash_lock); - free_cell(cell); - return -EBUSY; -} - -void __hash_remove(struct hash_cell *hc) -{ - /* remove from the dev hash */ - list_del(&hc->uuid_list); - list_del(&hc->name_list); - unregister_with_devfs(hc); - dm_put(hc->md); - free_cell(hc); -} - -void dm_hash_remove_all(void) -{ - int i; - struct hash_cell *hc; - struct list_head *tmp, *n; - - down_write(&_hash_lock); - for (i = 0; i < NUM_BUCKETS; i++) { - list_for_each_safe (tmp, n, _name_buckets + i) { - hc = list_entry(tmp, struct hash_cell, name_list); - __hash_remove(hc); - } - } - up_write(&_hash_lock); -} - -int dm_hash_rename(const char *old, const char *new) -{ - char *new_name, *old_name; - struct hash_cell *hc; - - /* - * duplicate new. - */ - new_name = kstrdup(new); - if (!new_name) - return -ENOMEM; - - down_write(&_hash_lock); - - /* - * Is new free ? - */ - hc = __get_name_cell(new); - if (hc) { - DMWARN("asked to rename to an already existing name %s -> %s", - old, new); - up_write(&_hash_lock); - kfree(new_name); - return -EBUSY; - } - - /* - * Is there such a device as 'old' ? - */ - hc = __get_name_cell(old); - if (!hc) { - DMWARN("asked to rename a non existent device %s -> %s", - old, new); - up_write(&_hash_lock); - kfree(new_name); - return -ENXIO; - } - - /* - * rename and move the name cell. - */ - unregister_with_devfs(hc); - - list_del(&hc->name_list); - old_name = hc->name; - hc->name = new_name; - list_add(&hc->name_list, _name_buckets + hash_str(new_name)); - - /* rename the device node in devfs */ - register_with_devfs(hc); - - up_write(&_hash_lock); - kfree(old_name); - return 0; -} - - -/*----------------------------------------------------------------- - * Implementation of the ioctl commands - *---------------------------------------------------------------*/ - -/* - * All the ioctl commands get dispatched to functions with this - * prototype. - */ -typedef int (*ioctl_fn)(struct dm_ioctl *param, struct dm_ioctl *user); - -/* - * Check a string doesn't overrun the chunk of - * memory we copied from userland. - */ -static int valid_str(char *str, void *begin, void *end) -{ - while (((void *) str >= begin) && ((void *) str < end)) - if (!*str++) - return 0; - - return -EINVAL; -} - -static int next_target(struct dm_target_spec *last, uint32_t next, - void *begin, void *end, - struct dm_target_spec **spec, char **params) -{ - *spec = (struct dm_target_spec *) - ((unsigned char *) last + next); - *params = (char *) (*spec + 1); - - if (*spec < (last + 1) || ((void *) *spec > end)) - return -EINVAL; - - return valid_str(*params, begin, end); -} - -static int populate_table(struct dm_table *table, struct dm_ioctl *args) -{ - int r, first = 1; - unsigned int i = 0; - struct dm_target_spec *spec; - char *params; - void *begin, *end; - - if (!args->target_count) { - DMWARN("populate_table: no targets specified"); - return -EINVAL; - } - - begin = (void *) args; - end = begin + args->data_size; - - for (i = 0; i < args->target_count; i++) { - - if (first) - r = next_target((struct dm_target_spec *) args, - args->data_start, - begin, end, &spec, ¶ms); - else - r = next_target(spec, spec->next, begin, end, - &spec, ¶ms); - - if (r) { - DMWARN("unable to find target"); - return -EINVAL; - } - - r = dm_table_add_target(table, spec->target_type, - (sector_t) spec->sector_start, - (sector_t) spec->length, - params); - if (r) { - DMWARN("internal error adding target to table"); - return -EINVAL; - } - - first = 0; - } - - return dm_table_complete(table); -} - -/* - * Round up the ptr to the next 'align' boundary. Obviously - * 'align' must be a power of 2. - */ -static inline void *align_ptr(void *ptr, unsigned int align) -{ - align--; - return (void *) (((unsigned long) (ptr + align)) & ~align); -} - -/* - * Copies a dm_ioctl and an optional additional payload to - * userland. - */ -static int results_to_user(struct dm_ioctl *user, struct dm_ioctl *param, - void *data, uint32_t len) -{ - int r; - void *ptr = NULL; - - if (data) { - ptr = align_ptr(user + 1, sizeof(unsigned long)); - param->data_start = ptr - (void *) user; - } - - /* - * The version number has already been filled in, so we - * just copy later fields. - */ - r = copy_to_user(&user->data_size, ¶m->data_size, - sizeof(*param) - sizeof(param->version)); - if (r) - return -EFAULT; - - if (data) { - if (param->data_start + len > param->data_size) - return -ENOSPC; - - if (copy_to_user(ptr, data, len)) - r = -EFAULT; - } - - return r; -} - -/* - * Fills in a dm_ioctl structure, ready for sending back to - * userland. - */ -static int __info(struct mapped_device *md, struct dm_ioctl *param) -{ - struct dm_table *table; - struct block_device *bdev; - struct gendisk *disk = dm_disk(md); - - param->flags = DM_EXISTS_FLAG; - if (dm_suspended(md)) - param->flags |= DM_SUSPEND_FLAG; - - bdev = bdget_disk(disk, 0); - if (!bdev) - return -ENXIO; - - param->dev = bdev->bd_dev; - param->open_count = bdev->bd_openers; - bdput(bdev); - - if (disk->policy) - param->flags |= DM_READONLY_FLAG; - - table = dm_get_table(md); - param->target_count = dm_table_get_num_targets(table); - dm_table_put(table); - - return 0; -} - -/* - * Always use UUID for lookups if it's present, otherwise use name. - */ -static inline struct mapped_device *find_device(struct dm_ioctl *param) -{ - struct hash_cell *hc; - struct mapped_device *md = NULL; - - down_read(&_hash_lock); - hc = *param->uuid ? __get_uuid_cell(param->uuid) : - __get_name_cell(param->name); - if (hc) { - md = hc->md; - - /* - * Sneakily write in both the name and the uuid - * while we have the cell. - */ - strlcpy(param->name, hc->name, sizeof(param->name)); - if (hc->uuid) - strlcpy(param->uuid, hc->uuid, sizeof(param->uuid)); - else - param->uuid[0] = '\0'; - - dm_get(md); - } - up_read(&_hash_lock); - - return md; -} - -#define ALIGNMENT sizeof(int) -static void *_align(void *ptr, unsigned int a) -{ - register unsigned long align = --a; - - return (void *) (((unsigned long) ptr + align) & ~align); -} - -/* - * Copies device info back to user space, used by - * the create and info ioctls. - */ -static int info(struct dm_ioctl *param, struct dm_ioctl *user) -{ - struct mapped_device *md; - - param->flags = 0; - - md = find_device(param); - if (!md) - /* - * Device not found - returns cleared exists flag. - */ - goto out; - - __info(md, param); - dm_put(md); - - out: - return results_to_user(user, param, NULL, 0); -} - -static inline int get_mode(struct dm_ioctl *param) -{ - int mode = FMODE_READ | FMODE_WRITE; - - if (param->flags & DM_READONLY_FLAG) - mode = FMODE_READ; - - return mode; -} - -static int check_name(const char *name) -{ - if (name[0] == '/') { - DMWARN("invalid device name"); - return -EINVAL; - } - - return 0; -} - -static int create(struct dm_ioctl *param, struct dm_ioctl *user) -{ - int r; - struct dm_table *t; - struct mapped_device *md; - - r = check_name(param->name); - if (r) - return r; - - r = dm_table_create(&t, get_mode(param)); - if (r) - return r; - - r = populate_table(t, param); - if (r) { - dm_table_put(t); - return r; - } - - if (param->flags & DM_PERSISTENT_DEV_FLAG) - r = dm_create_with_minor(minor(to_kdev_t(param->dev)), t, &md); - else - r = dm_create(t, &md); - - if (r) { - dm_table_put(t); - return r; - } - dm_table_put(t); /* md will have grabbed its own reference */ - - set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0); - r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md); - dm_put(md); - - return r ? r : info(param, user); -} - -/* - * Build up the status struct for each target - */ -static int __status(struct mapped_device *md, struct dm_ioctl *param, - char *outbuf, size_t *len) -{ - unsigned int i, num_targets; - struct dm_target_spec *spec; - char *outptr; - status_type_t type; - struct dm_table *table = dm_get_table(md); - - if (param->flags & DM_STATUS_TABLE_FLAG) - type = STATUSTYPE_TABLE; - else - type = STATUSTYPE_INFO; - - outptr = outbuf; - - /* Get all the target info */ - num_targets = dm_table_get_num_targets(table); - for (i = 0; i < num_targets; i++) { - struct dm_target *ti = dm_table_get_target(table, i); - - if (outptr - outbuf + - sizeof(struct dm_target_spec) > param->data_size) { - dm_table_put(table); - return -ENOMEM; - } - - spec = (struct dm_target_spec *) outptr; - - spec->status = 0; - spec->sector_start = ti->begin; - spec->length = ti->len; - strlcpy(spec->target_type, ti->type->name, - sizeof(spec->target_type)); - - outptr += sizeof(struct dm_target_spec); - - /* Get the status/table string from the target driver */ - if (ti->type->status) - ti->type->status(ti, type, outptr, - outbuf + param->data_size - outptr); - else - outptr[0] = '\0'; - - outptr += strlen(outptr) + 1; - _align(outptr, ALIGNMENT); - spec->next = outptr - outbuf; - } - - param->target_count = num_targets; - *len = outptr - outbuf; - dm_table_put(table); - - return 0; -} - -/* - * Return the status of a device as a text string for each - * target. - */ -static int get_status(struct dm_ioctl *param, struct dm_ioctl *user) -{ - struct mapped_device *md; - size_t len = 0; - int ret; - char *outbuf = NULL; - - md = find_device(param); - if (!md) - /* - * Device not found - returns cleared exists flag. - */ - goto out; - - /* We haven't a clue how long the resultant data will be so - just allocate as much as userland has allowed us and make sure - we don't overun it */ - outbuf = kmalloc(param->data_size, GFP_KERNEL); - if (!outbuf) - goto out; - /* - * Get the status of all targets - */ - __status(md, param, outbuf, &len); - - /* - * Setup the basic dm_ioctl structure. - */ - __info(md, param); - - out: - if (md) - dm_put(md); - - ret = results_to_user(user, param, outbuf, len); - - if (outbuf) - kfree(outbuf); - - return ret; -} - -/* - * Wait for a device to report an event - */ -static int wait_device_event(struct dm_ioctl *param, struct dm_ioctl *user) -{ - struct mapped_device *md; - DECLARE_WAITQUEUE(wq, current); - - md = find_device(param); - if (!md) - /* - * Device not found - returns cleared exists flag. - */ - goto out; - - /* - * Setup the basic dm_ioctl structure. - */ - __info(md, param); - - /* - * Wait for a notification event - */ - set_current_state(TASK_INTERRUPTIBLE); - if (!dm_add_wait_queue(md, &wq, dm_get_event_nr(md))) { - schedule(); - dm_remove_wait_queue(md, &wq); - } - set_current_state(TASK_RUNNING); - dm_put(md); - - out: - return results_to_user(user, param, NULL, 0); -} - -/* - * Retrieves a list of devices used by a particular dm device. - */ -static int dep(struct dm_ioctl *param, struct dm_ioctl *user) -{ - int r; - unsigned int count; - struct mapped_device *md; - struct list_head *tmp; - size_t len = 0; - struct dm_target_deps *deps = NULL; - struct dm_table *table; - - md = find_device(param); - if (!md) - goto out; - table = dm_get_table(md); - - /* - * Setup the basic dm_ioctl structure. - */ - __info(md, param); - - /* - * Count the devices. - */ - count = 0; - list_for_each(tmp, dm_table_get_devices(table)) - count++; - - /* - * Allocate a kernel space version of the dm_target_status - * struct. - */ - if (array_too_big(sizeof(*deps), sizeof(*deps->dev), count)) { - dm_table_put(table); - dm_put(md); - return -ENOMEM; - } - - len = sizeof(*deps) + (sizeof(*deps->dev) * count); - deps = kmalloc(len, GFP_KERNEL); - if (!deps) { - dm_table_put(table); - dm_put(md); - return -ENOMEM; - } - - /* - * Fill in the devices. - */ - deps->count = count; - count = 0; - list_for_each(tmp, dm_table_get_devices(table)) { - struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); - deps->dev[count++] = dd->bdev->bd_dev; - } - dm_table_put(table); - dm_put(md); - - out: - r = results_to_user(user, param, deps, len); - - kfree(deps); - return r; -} - -static int remove(struct dm_ioctl *param, struct dm_ioctl *user) -{ - struct hash_cell *hc; - - down_write(&_hash_lock); - hc = *param->uuid ? __get_uuid_cell(param->uuid) : - __get_name_cell(param->name); - if (!hc) { - DMWARN("device doesn't appear to be in the dev hash table."); - up_write(&_hash_lock); - return -EINVAL; - } - - /* - * You may ask the interface to drop its reference to an - * in use device. This is no different to unlinking a - * file that someone still has open. The device will not - * actually be destroyed until the last opener closes it. - * The name and uuid of the device (both are interface - * properties) will be available for reuse immediately. - * - * You don't want to drop a _suspended_ device from the - * interface, since that will leave you with no way of - * resuming it. - */ - if (dm_suspended(hc->md)) { - DMWARN("refusing to remove a suspended device."); - up_write(&_hash_lock); - return -EPERM; - } - - __hash_remove(hc); - up_write(&_hash_lock); - return 0; -} - -static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user) -{ - dm_hash_remove_all(); - return 0; -} - -static int suspend(struct dm_ioctl *param, struct dm_ioctl *user) -{ - int r; - struct mapped_device *md; - - md = find_device(param); - if (!md) - return -ENXIO; - - if (param->flags & DM_SUSPEND_FLAG) - r = dm_suspend(md); - else - r = dm_resume(md); - - dm_put(md); - return r; -} - -static int reload(struct dm_ioctl *param, struct dm_ioctl *user) -{ - int r; - struct mapped_device *md; - struct dm_table *t; - - r = dm_table_create(&t, get_mode(param)); - if (r) - return r; - - r = populate_table(t, param); - if (r) { - dm_table_put(t); - return r; - } - - md = find_device(param); - if (!md) { - dm_table_put(t); - return -ENXIO; - } - - r = dm_swap_table(md, t); - if (r) { - dm_put(md); - dm_table_put(t); - return r; - } - dm_table_put(t); /* md will have taken its own reference */ - - set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0); - dm_put(md); - - r = info(param, user); - return r; -} - -static int rename(struct dm_ioctl *param, struct dm_ioctl *user) -{ - int r; - char *new_name = (char *) param + param->data_start; - - if (valid_str(new_name, (void *) param, - (void *) param + param->data_size)) { - DMWARN("Invalid new logical volume name supplied."); - return -EINVAL; - } - - r = check_name(new_name); - if (r) - return r; - - return dm_hash_rename(param->name, new_name); -} - - -/*----------------------------------------------------------------- - * Implementation of open/close/ioctl on the special char - * device. - *---------------------------------------------------------------*/ -static ioctl_fn lookup_ioctl(unsigned int cmd) -{ - static struct { - int cmd; - ioctl_fn fn; - } _ioctls[] = { - {DM_VERSION_CMD, NULL}, /* version is dealt with elsewhere */ - {DM_REMOVE_ALL_CMD, remove_all}, - {DM_DEV_CREATE_CMD, create}, - {DM_DEV_REMOVE_CMD, remove}, - {DM_DEV_RELOAD_CMD, reload}, - {DM_DEV_RENAME_CMD, rename}, - {DM_DEV_SUSPEND_CMD, suspend}, - {DM_DEV_DEPS_CMD, dep}, - {DM_DEV_STATUS_CMD, info}, - {DM_TARGET_STATUS_CMD, get_status}, - {DM_TARGET_WAIT_CMD, wait_device_event}, - }; - - return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; -} - -/* - * As well as checking the version compatibility this always - * copies the kernel interface version out. - */ -static int check_version(unsigned int cmd, struct dm_ioctl *user) -{ - uint32_t version[3]; - int r = 0; - - if (copy_from_user(version, user->version, sizeof(version))) - return -EFAULT; - - if ((DM_VERSION_MAJOR != version[0]) || - (DM_VERSION_MINOR < version[1])) { - DMWARN("ioctl interface mismatch: " - "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)", - DM_VERSION_MAJOR, DM_VERSION_MINOR, - DM_VERSION_PATCHLEVEL, - version[0], version[1], version[2], cmd); - r = -EINVAL; - } - - /* - * Fill in the kernel version. - */ - version[0] = DM_VERSION_MAJOR; - version[1] = DM_VERSION_MINOR; - version[2] = DM_VERSION_PATCHLEVEL; - if (copy_to_user(user->version, version, sizeof(version))) - return -EFAULT; - - return r; -} - -static void free_params(struct dm_ioctl *param) -{ - vfree(param); -} - -static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param) -{ - struct dm_ioctl tmp, *dmi; - - if (copy_from_user(&tmp, user, sizeof(tmp))) - return -EFAULT; - - if (tmp.data_size < sizeof(tmp)) - return -EINVAL; - - dmi = (struct dm_ioctl *) vmalloc(tmp.data_size); - if (!dmi) - return -ENOMEM; - - if (copy_from_user(dmi, user, tmp.data_size)) { - vfree(dmi); - return -EFAULT; - } - - *param = dmi; - return 0; -} - -static int validate_params(uint cmd, struct dm_ioctl *param) -{ - /* Ignores parameters */ - if (cmd == DM_REMOVE_ALL_CMD) - return 0; - - /* Unless creating, either name of uuid but not both */ - if (cmd != DM_DEV_CREATE_CMD) { - if ((!*param->uuid && !*param->name) || - (*param->uuid && *param->name)) { - DMWARN("one of name or uuid must be supplied"); - return -EINVAL; - } - } - - /* Ensure strings are terminated */ - param->name[DM_NAME_LEN - 1] = '\0'; - param->uuid[DM_UUID_LEN - 1] = '\0'; - - return 0; -} - -static int ctl_ioctl(struct inode *inode, struct file *file, - uint command, ulong u) -{ - int r = 0; - unsigned int cmd; - struct dm_ioctl *param; - struct dm_ioctl *user = (struct dm_ioctl *) u; - ioctl_fn fn = NULL; - - /* only root can play with this */ - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (_IOC_TYPE(command) != DM_IOCTL) - return -ENOTTY; - - cmd = _IOC_NR(command); - - /* - * Check the interface version passed in. This also - * writes out the kernels interface version. - */ - r = check_version(cmd, user); - if (r) - return r; - - /* - * Nothing more to do for the version command. - */ - if (cmd == DM_VERSION_CMD) - return 0; - - fn = lookup_ioctl(cmd); - if (!fn) { - DMWARN("dm_ctl_ioctl: unknown command 0x%x", command); - return -ENOTTY; - } - - /* - * Copy the parameters into kernel space. - */ - r = copy_params(user, ¶m); - if (r) - return r; - - r = validate_params(cmd, param); - if (r) { - free_params(param); - return r; - } - - r = fn(param, user); - free_params(param); - return r; -} - -static struct file_operations _ctl_fops = { - .ioctl = ctl_ioctl, - .owner = THIS_MODULE, -}; - -static struct miscdevice _dm_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = DM_NAME, - .devfs_name = "mapper/control", - .fops = &_ctl_fops -}; - -/* - * Create misc character device and link to DM_DIR/control. - */ -int __init dm_interface_init(void) -{ - int r; - - r = dm_hash_init(); - if (r) - return r; - - r = misc_register(&_dm_misc); - if (r) { - DMERR("misc_register failed for control device"); - dm_hash_exit(); - return r; - } - - DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR, - DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA, - DM_DRIVER_EMAIL); - return 0; - - if (misc_deregister(&_dm_misc) < 0) - DMERR("misc_deregister failed for control device"); - dm_hash_exit(); - return r; -} -void dm_interface_exit(void) -{ - if (misc_deregister(&_dm_misc) < 0) - DMERR("misc_deregister failed for control device"); - dm_hash_exit(); -} +#ifdef CONFIG_DM_IOCTL_V4 +#include "dm-ioctl-v4.c" +#else +#include "dm-ioctl-v1.c" +#endif diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 5e08918890ee..9933e9b71a90 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -515,6 +515,11 @@ static int dm_request(request_queue_t *q, struct bio *bio) down_read(&md->lock); } + if (!md->map) { + bio_io_error(bio, bio->bi_size); + return 0; + } + __split_bio(md, bio); up_read(&md->lock); return 0; @@ -671,6 +676,9 @@ static int __bind(struct mapped_device *md, struct dm_table *t) static void __unbind(struct mapped_device *md) { + if (!md->map) + return; + dm_table_event_callback(md->map, NULL, NULL); dm_table_put(md->map); md->map = NULL; @@ -681,35 +689,26 @@ static void __unbind(struct mapped_device *md) * Constructor for a new device. */ static int create_aux(unsigned int minor, int persistent, - struct dm_table *table, struct mapped_device **result) + struct mapped_device **result) { - int r; struct mapped_device *md; md = alloc_dev(minor, persistent); if (!md) return -ENXIO; - r = __bind(md, table); - if (r) { - free_dev(md); - return r; - } - dm_table_resume_targets(md->map); - *result = md; return 0; } -int dm_create(struct dm_table *table, struct mapped_device **result) +int dm_create(struct mapped_device **result) { - return create_aux(0, 0, table, result); + return create_aux(0, 0, result); } -int dm_create_with_minor(unsigned int minor, - struct dm_table *table, struct mapped_device **result) +int dm_create_with_minor(unsigned int minor, struct mapped_device **result) { - return create_aux(minor, 1, table, result); + return create_aux(minor, 1, result); } void dm_get(struct mapped_device *md) @@ -720,7 +719,7 @@ void dm_get(struct mapped_device *md) void dm_put(struct mapped_device *md) { if (atomic_dec_and_test(&md->holders)) { - if (!test_bit(DMF_SUSPENDED, &md->flags)) + if (!test_bit(DMF_SUSPENDED, &md->flags) && md->map) dm_table_suspend_targets(md->map); __unbind(md); free_dev(md); @@ -810,7 +809,8 @@ int dm_suspend(struct mapped_device *md) down_write(&md->lock); remove_wait_queue(&md->wait, &wait); set_bit(DMF_SUSPENDED, &md->flags); - dm_table_suspend_targets(md->map); + if (md->map) + dm_table_suspend_targets(md->map); up_write(&md->lock); return 0; @@ -821,7 +821,8 @@ int dm_resume(struct mapped_device *md) struct deferred_io *def; down_write(&md->lock); - if (!test_bit(DMF_SUSPENDED, &md->flags) || + if (!md->map || + !test_bit(DMF_SUSPENDED, &md->flags) || !dm_table_get_size(md->map)) { up_write(&md->lock); return -EINVAL; @@ -891,7 +892,8 @@ struct dm_table *dm_get_table(struct mapped_device *md) down_read(&md->lock); t = md->map; - dm_table_get(t); + if (t) + dm_table_get(t); up_read(&md->lock); return t; diff --git a/drivers/md/dm.h b/drivers/md/dm.h index 320c1da00570..d5deaf13fd80 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -51,9 +51,8 @@ struct mapped_device; * Functions for manipulating a struct mapped_device. * Drop the reference with dm_put when you finish with the object. *---------------------------------------------------------------*/ -int dm_create(struct dm_table *table, struct mapped_device **md); -int dm_create_with_minor(unsigned int minor, struct dm_table *table, - struct mapped_device **md); +int dm_create(struct mapped_device **md); +int dm_create_with_minor(unsigned int minor, struct mapped_device **md); /* * Reference counting for md. diff --git a/include/linux/dm-ioctl-v1.h b/include/linux/dm-ioctl-v1.h new file mode 100644 index 000000000000..21bef9ec14b0 --- /dev/null +++ b/include/linux/dm-ioctl-v1.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the LGPL. + */ + +#ifndef _LINUX_DM_IOCTL_V1_H +#define _LINUX_DM_IOCTL_V1_H + +#include + +#define DM_DIR "mapper" /* Slashes not supported */ +#define DM_MAX_TYPE_NAME 16 +#define DM_NAME_LEN 128 +#define DM_UUID_LEN 129 + +/* + * Implements a traditional ioctl interface to the device mapper. + */ + +/* + * All ioctl arguments consist of a single chunk of memory, with + * this structure at the start. If a uuid is specified any + * lookup (eg. for a DM_INFO) will be done on that, *not* the + * name. + */ +struct dm_ioctl { + /* + * The version number is made up of three parts: + * major - no backward or forward compatibility, + * minor - only backwards compatible, + * patch - both backwards and forwards compatible. + * + * All clients of the ioctl interface should fill in the + * version number of the interface that they were + * compiled with. + * + * All recognised ioctl commands (ie. those that don't + * return -ENOTTY) fill out this field, even if the + * command failed. + */ + uint32_t version[3]; /* in/out */ + uint32_t data_size; /* total size of data passed in + * including this struct */ + + uint32_t data_start; /* offset to start of data + * relative to start of this struct */ + + uint32_t target_count; /* in/out */ + uint32_t open_count; /* out */ + uint32_t flags; /* in/out */ + + __kernel_dev_t dev; /* in/out */ + + char name[DM_NAME_LEN]; /* device name */ + char uuid[DM_UUID_LEN]; /* unique identifier for + * the block device */ +}; + +/* + * Used to specify tables. These structures appear after the + * dm_ioctl. + */ +struct dm_target_spec { + int32_t status; /* used when reading from kernel only */ + uint64_t sector_start; + uint32_t length; + + /* + * Offset in bytes (from the start of this struct) to + * next target_spec. + */ + uint32_t next; + + char target_type[DM_MAX_TYPE_NAME]; + + /* + * Parameter string starts immediately after this object. + * Be careful to add padding after string to ensure correct + * alignment of subsequent dm_target_spec. + */ +}; + +/* + * Used to retrieve the target dependencies. + */ +struct dm_target_deps { + uint32_t count; + + __kernel_dev_t dev[0]; /* out */ +}; + +/* + * If you change this make sure you make the corresponding change + * to dm-ioctl.c:lookup_ioctl() + */ +enum { + /* Top level cmds */ + DM_VERSION_CMD = 0, + DM_REMOVE_ALL_CMD, + + /* device level cmds */ + DM_DEV_CREATE_CMD, + DM_DEV_REMOVE_CMD, + DM_DEV_RELOAD_CMD, + DM_DEV_RENAME_CMD, + DM_DEV_SUSPEND_CMD, + DM_DEV_DEPS_CMD, + DM_DEV_STATUS_CMD, + + /* target level cmds */ + DM_TARGET_STATUS_CMD, + DM_TARGET_WAIT_CMD +}; + +#define DM_IOCTL 0xfd + +#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl) +#define DM_REMOVE_ALL _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl) + +#define DM_DEV_CREATE _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl) +#define DM_DEV_REMOVE _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl) +#define DM_DEV_RELOAD _IOWR(DM_IOCTL, DM_DEV_RELOAD_CMD, struct dm_ioctl) +#define DM_DEV_SUSPEND _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl) +#define DM_DEV_RENAME _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl) +#define DM_DEV_DEPS _IOWR(DM_IOCTL, DM_DEV_DEPS_CMD, struct dm_ioctl) +#define DM_DEV_STATUS _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl) + +#define DM_TARGET_STATUS _IOWR(DM_IOCTL, DM_TARGET_STATUS_CMD, struct dm_ioctl) +#define DM_TARGET_WAIT _IOWR(DM_IOCTL, DM_TARGET_WAIT_CMD, struct dm_ioctl) + +#define DM_VERSION_MAJOR 1 +#define DM_VERSION_MINOR 0 +#define DM_VERSION_PATCHLEVEL 6 +#define DM_VERSION_EXTRA "-ioctl (2002-10-15)" + +/* Status bits */ +#define DM_READONLY_FLAG 0x00000001 +#define DM_SUSPEND_FLAG 0x00000002 +#define DM_EXISTS_FLAG 0x00000004 +#define DM_PERSISTENT_DEV_FLAG 0x00000008 + +/* + * Flag passed into ioctl STATUS command to get table information + * rather than current status. + */ +#define DM_STATUS_TABLE_FLAG 0x00000010 + +#endif /* _LINUX_DM_IOCTL_H */ diff --git a/include/linux/dm-ioctl-v4.h b/include/linux/dm-ioctl-v4.h new file mode 100644 index 000000000000..74a8d14b885d --- /dev/null +++ b/include/linux/dm-ioctl-v4.h @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2001 - 2003 Sistina Software (UK) Limited. + * + * This file is released under the LGPL. + */ + +#ifndef _LINUX_DM_IOCTL_V4_H +#define _LINUX_DM_IOCTL_V4_H + +#include + +#define DM_DIR "mapper" /* Slashes not supported */ +#define DM_MAX_TYPE_NAME 16 +#define DM_NAME_LEN 128 +#define DM_UUID_LEN 129 + +/* + * A traditional ioctl interface for the device mapper. + * + * Each device can have two tables associated with it, an + * 'active' table which is the one currently used by io passing + * through the device, and an 'inactive' one which is a table + * that is being prepared as a replacement for the 'active' one. + * + * DM_VERSION: + * Just get the version information for the ioctl interface. + * + * DM_REMOVE_ALL: + * Remove all dm devices, destroy all tables. Only really used + * for debug. + * + * DM_LIST_DEVICES: + * Get a list of all the dm device names. + * + * DM_DEV_CREATE: + * Create a new device, neither the 'active' or 'inactive' table + * slots will be filled. The device will be in suspended state + * after creation, however any io to the device will get errored + * since it will be out-of-bounds. + * + * DM_DEV_REMOVE: + * Remove a device, destroy any tables. + * + * DM_DEV_RENAME: + * Rename a device. + * + * DM_SUSPEND: + * This performs both suspend and resume, depending which flag is + * passed in. + * Suspend: This command will not return until all pending io to + * the device has completed. Further io will be deferred until + * the device is resumed. + * Resume: It is no longer an error to issue this command on an + * unsuspended device. If a table is present in the 'inactive' + * slot, it will be moved to the active slot, then the old table + * from the active slot will be _destroyed_. Finally the device + * is resumed. + * + * DM_DEV_STATUS: + * Retrieves the status for the table in the 'active' slot. + * + * DM_DEV_WAIT: + * Wait for a significant event to occur to the device. This + * could either be caused by an event triggered by one of the + * targets of the table in the 'active' slot, or a table change. + * + * DM_TABLE_LOAD: + * Load a table into the 'inactive' slot for the device. The + * device does _not_ need to be suspended prior to this command. + * + * DM_TABLE_CLEAR: + * Destroy any table in the 'inactive' slot (ie. abort). + * + * DM_TABLE_DEPS: + * Return a set of device dependencies for the 'active' table. + * + * DM_TABLE_STATUS: + * Return the targets status for the 'active' table. + */ + +/* + * All ioctl arguments consist of a single chunk of memory, with + * this structure at the start. If a uuid is specified any + * lookup (eg. for a DM_INFO) will be done on that, *not* the + * name. + */ +struct dm_ioctl { + /* + * The version number is made up of three parts: + * major - no backward or forward compatibility, + * minor - only backwards compatible, + * patch - both backwards and forwards compatible. + * + * All clients of the ioctl interface should fill in the + * version number of the interface that they were + * compiled with. + * + * All recognised ioctl commands (ie. those that don't + * return -ENOTTY) fill out this field, even if the + * command failed. + */ + uint32_t version[3]; /* in/out */ + uint32_t data_size; /* total size of data passed in + * including this struct */ + + uint32_t data_start; /* offset to start of data + * relative to start of this struct */ + + uint32_t target_count; /* in/out */ + int32_t open_count; /* out */ + uint32_t flags; /* in/out */ + uint32_t event_nr; /* in/out */ + uint32_t padding; + + uint64_t dev; /* in/out */ + + char name[DM_NAME_LEN]; /* device name */ + char uuid[DM_UUID_LEN]; /* unique identifier for + * the block device */ +}; + +/* + * Used to specify tables. These structures appear after the + * dm_ioctl. + */ +struct dm_target_spec { + uint64_t sector_start; + uint64_t length; + int32_t status; /* used when reading from kernel only */ + + /* + * Offset in bytes (from the start of this struct) to + * next target_spec. + */ + uint32_t next; + + char target_type[DM_MAX_TYPE_NAME]; + + /* + * Parameter string starts immediately after this object. + * Be careful to add padding after string to ensure correct + * alignment of subsequent dm_target_spec. + */ +}; + +/* + * Used to retrieve the target dependencies. + */ +struct dm_target_deps { + uint32_t count; /* Array size */ + uint32_t padding; /* unused */ + uint64_t dev[0]; /* out */ +}; + +/* + * Used to get a list of all dm devices. + */ +struct dm_name_list { + uint64_t dev; + uint32_t next; /* offset to the next record from + the _start_ of this */ + char name[0]; +}; + +/* + * If you change this make sure you make the corresponding change + * to dm-ioctl.c:lookup_ioctl() + */ +enum { + /* Top level cmds */ + DM_VERSION_CMD = 0, + DM_REMOVE_ALL_CMD, + DM_LIST_DEVICES_CMD, + + /* device level cmds */ + DM_DEV_CREATE_CMD, + DM_DEV_REMOVE_CMD, + DM_DEV_RENAME_CMD, + DM_DEV_SUSPEND_CMD, + DM_DEV_STATUS_CMD, + DM_DEV_WAIT_CMD, + + /* Table level cmds */ + DM_TABLE_LOAD_CMD, + DM_TABLE_CLEAR_CMD, + DM_TABLE_DEPS_CMD, + DM_TABLE_STATUS_CMD, +}; + +#define DM_IOCTL 0xfd + +#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl) +#define DM_REMOVE_ALL _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl) +#define DM_LIST_DEVICES _IOWR(DM_IOCTL, DM_LIST_DEVICES_CMD, struct dm_ioctl) + +#define DM_DEV_CREATE _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl) +#define DM_DEV_REMOVE _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl) +#define DM_DEV_RENAME _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl) +#define DM_DEV_SUSPEND _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl) +#define DM_DEV_STATUS _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl) +#define DM_DEV_WAIT _IOWR(DM_IOCTL, DM_DEV_WAIT_CMD, struct dm_ioctl) + +#define DM_TABLE_LOAD _IOWR(DM_IOCTL, DM_TABLE_LOAD_CMD, struct dm_ioctl) +#define DM_TABLE_CLEAR _IOWR(DM_IOCTL, DM_TABLE_CLEAR_CMD, struct dm_ioctl) +#define DM_TABLE_DEPS _IOWR(DM_IOCTL, DM_TABLE_DEPS_CMD, struct dm_ioctl) +#define DM_TABLE_STATUS _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, struct dm_ioctl) + +#define DM_VERSION_MAJOR 4 +#define DM_VERSION_MINOR 0 +#define DM_VERSION_PATCHLEVEL 0 +#define DM_VERSION_EXTRA "-ioctl (2003-06-04)" + +/* Status bits */ +#define DM_READONLY_FLAG (1 << 0) /* In/Out */ +#define DM_SUSPEND_FLAG (1 << 1) /* In/Out */ +#define DM_PERSISTENT_DEV_FLAG (1 << 3) /* In */ + +/* + * Flag passed into ioctl STATUS command to get table information + * rather than current status. + */ +#define DM_STATUS_TABLE_FLAG (1 << 4) /* In */ + +/* + * Flags that indicate whether a table is present in either of + * the two table slots that a device has. + */ +#define DM_ACTIVE_PRESENT_FLAG (1 << 5) /* Out */ +#define DM_INACTIVE_PRESENT_FLAG (1 << 6) /* Out */ + +/* + * Indicates that the buffer passed in wasn't big enough for the + * results. + */ +#define DM_BUFFER_FULL_FLAG (1 << 8) /* Out */ + +#endif /* _LINUX_DM_IOCTL_H */ diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h index 72edd5e19e62..dddbfd9c3cf7 100644 --- a/include/linux/dm-ioctl.h +++ b/include/linux/dm-ioctl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 Sistina Software (UK) Limited. + * Copyright (C) 2003 Sistina Software (UK) Limited. * * This file is released under the LGPL. */ @@ -7,143 +7,12 @@ #ifndef _LINUX_DM_IOCTL_H #define _LINUX_DM_IOCTL_H -#include +#include -#define DM_DIR "mapper" /* Slashes not supported */ -#define DM_MAX_TYPE_NAME 16 -#define DM_NAME_LEN 128 -#define DM_UUID_LEN 129 +#ifdef CONFIG_DM_IOCTL_V4 +#include "dm-ioctl-v4.h" +#else +#include "dm-ioctl-v1.h" +#endif -/* - * Implements a traditional ioctl interface to the device mapper. - */ - -/* - * All ioctl arguments consist of a single chunk of memory, with - * this structure at the start. If a uuid is specified any - * lookup (eg. for a DM_INFO) will be done on that, *not* the - * name. - */ -struct dm_ioctl { - /* - * The version number is made up of three parts: - * major - no backward or forward compatibility, - * minor - only backwards compatible, - * patch - both backwards and forwards compatible. - * - * All clients of the ioctl interface should fill in the - * version number of the interface that they were - * compiled with. - * - * All recognised ioctl commands (ie. those that don't - * return -ENOTTY) fill out this field, even if the - * command failed. - */ - uint32_t version[3]; /* in/out */ - uint32_t data_size; /* total size of data passed in - * including this struct */ - - uint32_t data_start; /* offset to start of data - * relative to start of this struct */ - - uint32_t target_count; /* in/out */ - uint32_t open_count; /* out */ - uint32_t flags; /* in/out */ - - __kernel_dev_t dev; /* in/out */ - - char name[DM_NAME_LEN]; /* device name */ - char uuid[DM_UUID_LEN]; /* unique identifier for - * the block device */ -}; - -/* - * Used to specify tables. These structures appear after the - * dm_ioctl. - */ -struct dm_target_spec { - int32_t status; /* used when reading from kernel only */ - uint64_t sector_start; - uint32_t length; - - /* - * Offset in bytes (from the start of this struct) to - * next target_spec. - */ - uint32_t next; - - char target_type[DM_MAX_TYPE_NAME]; - - /* - * Parameter string starts immediately after this object. - * Be careful to add padding after string to ensure correct - * alignment of subsequent dm_target_spec. - */ -}; - -/* - * Used to retrieve the target dependencies. - */ -struct dm_target_deps { - uint32_t count; - - __kernel_dev_t dev[0]; /* out */ -}; - -/* - * If you change this make sure you make the corresponding change - * to dm-ioctl.c:lookup_ioctl() - */ -enum { - /* Top level cmds */ - DM_VERSION_CMD = 0, - DM_REMOVE_ALL_CMD, - - /* device level cmds */ - DM_DEV_CREATE_CMD, - DM_DEV_REMOVE_CMD, - DM_DEV_RELOAD_CMD, - DM_DEV_RENAME_CMD, - DM_DEV_SUSPEND_CMD, - DM_DEV_DEPS_CMD, - DM_DEV_STATUS_CMD, - - /* target level cmds */ - DM_TARGET_STATUS_CMD, - DM_TARGET_WAIT_CMD -}; - -#define DM_IOCTL 0xfd - -#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl) -#define DM_REMOVE_ALL _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl) - -#define DM_DEV_CREATE _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl) -#define DM_DEV_REMOVE _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl) -#define DM_DEV_RELOAD _IOWR(DM_IOCTL, DM_DEV_RELOAD_CMD, struct dm_ioctl) -#define DM_DEV_SUSPEND _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl) -#define DM_DEV_RENAME _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl) -#define DM_DEV_DEPS _IOWR(DM_IOCTL, DM_DEV_DEPS_CMD, struct dm_ioctl) -#define DM_DEV_STATUS _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl) - -#define DM_TARGET_STATUS _IOWR(DM_IOCTL, DM_TARGET_STATUS_CMD, struct dm_ioctl) -#define DM_TARGET_WAIT _IOWR(DM_IOCTL, DM_TARGET_WAIT_CMD, struct dm_ioctl) - -#define DM_VERSION_MAJOR 1 -#define DM_VERSION_MINOR 0 -#define DM_VERSION_PATCHLEVEL 6 -#define DM_VERSION_EXTRA "-ioctl (2002-10-15)" - -/* Status bits */ -#define DM_READONLY_FLAG 0x00000001 -#define DM_SUSPEND_FLAG 0x00000002 -#define DM_EXISTS_FLAG 0x00000004 -#define DM_PERSISTENT_DEV_FLAG 0x00000008 - -/* - * Flag passed into ioctl STATUS command to get table information - * rather than current status. - */ -#define DM_STATUS_TABLE_FLAG 0x00000010 - -#endif /* _LINUX_DM_IOCTL_H */ +#endif -- cgit v1.2.3 From c56671f74801b1ec75dc80198936426e7d917919 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 17 Jul 2003 19:28:16 -0700 Subject: [PATCH] fix as-iosched do_div() For CONFIG_LBD=n case it was passing a u32 into do_div(). --- drivers/block/as-iosched.c | 7 ++++--- include/linux/blkdev.h | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c index 1482512ff24e..cbe94be0f7b2 100644 --- a/drivers/block/as-iosched.c +++ b/drivers/block/as-iosched.c @@ -833,10 +833,11 @@ static void as_update_iohist(struct as_io_context *aic, struct request *rq) + 2*1024*64); aic->seek_samples += 256; - aic->seek_total += 256*seek_dist; + aic->seek_total += (u64)256*seek_dist; if (aic->seek_samples) { - aic->seek_mean = aic->seek_total + 128; - sector_div(aic->seek_mean, aic->seek_samples); + u64 total = aic->seek_total + (aic->seek_samples>>1); + do_div(total, aic->seek_samples); + aic->seek_mean = (sector_t)total; } aic->seek_samples = (aic->seek_samples>>1) + (aic->seek_samples>>2); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 2e7f92aa1dc2..49e9f9dc00d6 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -44,9 +44,9 @@ struct as_io_context { unsigned long ttime_samples; unsigned long ttime_mean; /* Layout pattern */ - long seek_samples; + unsigned int seek_samples; sector_t last_request_pos; - sector_t seek_total; + u64 seek_total; sector_t seek_mean; }; -- cgit v1.2.3 From 4d33d4eb3bf10be402ce8e021fd098356bf42584 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 17 Jul 2003 19:44:45 -0700 Subject: [PATCH] forward port 2.4 Zoom video support Also apply the right fix to the yenta hang problem --- drivers/pcmcia/ricoh.h | 33 ++++++++++++++++ drivers/pcmcia/ti113x.h | 90 ++++++++++++++++++++++++++++++++++++++++--- drivers/pcmcia/yenta_socket.c | 2 + include/pcmcia/ss.h | 5 +++ 4 files changed, 125 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/pcmcia/ricoh.h b/drivers/pcmcia/ricoh.h index dcfcbd4328b3..9f9c688d20eb 100644 --- a/drivers/pcmcia/ricoh.h +++ b/drivers/pcmcia/ricoh.h @@ -116,6 +116,8 @@ #define RL5C4XX_CMD_SHIFT 4 #define RL5C4XX_HOLD_MASK 0x1c00 #define RL5C4XX_HOLD_SHIFT 10 +#define RL5C4XX_MISC_CONTROL 0x2F /* 8 bit */ +#define RL5C4XX_ZV_ENABLE 0x08 #ifdef __YENTA_H @@ -125,10 +127,41 @@ #define rl_mem(socket) ((socket)->private[3]) #define rl_config(socket) ((socket)->private[4]) +static void ricoh_zoom_video(struct pcmcia_socket *sock, int onoff) +{ + u8 reg; + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + + reg = config_readb(socket, RL5C4XX_MISC_CONTROL); + if (onoff) + /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */ + reg |= RL5C4XX_ZV_ENABLE; + else + reg &= ~RL5C4XX_ZV_ENABLE; + + config_writeb(socket, RL5C4XX_MISC_CONTROL, reg); +} + +static void ricoh_set_zv(struct pcmcia_socket *sock) +{ + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + if(socket->dev->vendor == PCI_VENDOR_ID_RICOH) + { + switch(socket->dev->device) + { + /* There may be more .. */ + case PCI_DEVICE_ID_RICOH_RL5C478: + sock->zoom_video = ricoh_zoom_video; + break; + } + } +} + static int ricoh_init(struct pcmcia_socket *sock) { struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); yenta_init(sock); + ricoh_set_zv(sock); config_writew(socket, RL5C4XX_MISC, rl_misc(socket)); config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket)); diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h index 2cdb46d4eb3c..4a0099518a76 100644 --- a/drivers/pcmcia/ti113x.h +++ b/drivers/pcmcia/ti113x.h @@ -148,14 +148,96 @@ static int ti_intctl(struct yenta_socket *socket) return 0; } +/* + * Zoom video control for TI122x/113x chips + */ + +static void ti_zoom_video(struct pcmcia_socket *sock, int onoff) +{ + u8 reg; + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + + /* If we don't have a Zoom Video switch this is harmless, + we just tristate the unused (ZV) lines */ + reg = config_readb(socket, TI113X_CARD_CONTROL); + if (onoff) + /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */ + reg |= TI113X_CCR_ZVENABLE; + else + reg &= ~TI113X_CCR_ZVENABLE; + config_writeb(socket, TI113X_CARD_CONTROL, reg); +} + +/* + * The 145x series can also use this. They have an additional + * ZV autodetect mode we don't use but don't actually need. + * FIXME: manual says its in func0 and func1 but disagrees with + * itself about this - do we need to force func0, if so we need + * to know a lot more about socket pairings in pcmcia_socket than + * we do now.. uggh. + */ + +static void ti1250_zoom_video(struct pcmcia_socket *sock, int onoff) +{ + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + int shift = 0; + u8 reg; + + ti_zoom_video(sock, onoff); + + reg = config_readb(socket, 0x84); + reg |= (1<<7); /* ZV bus enable */ + + if(PCI_FUNC(socket->dev->devfn)==1) + shift = 1; + + if(onoff) + { + reg &= ~(1<<6); /* Clear select bit */ + reg |= shift<<6; /* Favour our socket */ + reg |= 1<dev->vendor == PCI_VENDOR_ID_TI) + { + switch(socket->dev->device) + { + /* There may be more .. */ + case PCI_DEVICE_ID_TI_1220: + case PCI_DEVICE_ID_TI_1221: + case PCI_DEVICE_ID_TI_1225: + sock->zoom_video = ti_zoom_video; + break; + case PCI_DEVICE_ID_TI_1250: + case PCI_DEVICE_ID_TI_1251A: + case PCI_DEVICE_ID_TI_1251B: + case PCI_DEVICE_ID_TI_1450: + sock->zoom_video = ti1250_zoom_video; + } + } +} static int ti_init(struct pcmcia_socket *sock) { struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); yenta_init(sock); + ti_set_zv(sock); ti_intctl(socket); return 0; } + /* * Generic TI init - TI has an extension for the * INTCTL register that sets the PCI CSC interrupt. @@ -176,9 +258,6 @@ static int ti_override(struct yenta_socket *socket) if (new != reg) exca_writeb(socket, I365_INTCTL, new); -#if 0 - /* THIS CAUSES HANGS! Disabled for now, do not know why */ - /* * If ISA interrupts don't work, then fall back to routing card * interrupts to the PCI interrupt of the socket. @@ -190,7 +269,7 @@ static int ti_override(struct yenta_socket *socket) u8 irqmux, devctl; devctl = config_readb(socket, TI113X_DEVICE_CONTROL); - if (devctl & TI113X_DCR_IMODE_MASK != TI12XX_DCR_IMODE_ALL_SERIAL) { + if ((devctl & TI113X_DCR_IMODE_MASK) != TI12XX_DCR_IMODE_ALL_SERIAL) { printk (KERN_INFO "ti113x: Routing card interrupts to PCI\n"); devctl &= ~TI113X_DCR_IMODE_MASK; @@ -203,7 +282,6 @@ static int ti_override(struct yenta_socket *socket) config_writeb(socket, TI113X_DEVICE_CONTROL, devctl); } } -#endif socket->socket.ops->init = ti_init; return 0; @@ -220,6 +298,7 @@ static int ti113x_init(struct pcmcia_socket *sock) { struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); yenta_init(sock); + ti_set_zv(sock); config_writel(socket, TI113X_SYSTEM_CONTROL, ti_sysctl(socket)); config_writeb(socket, TI113X_CARD_CONTROL, ti_cardctl(socket)); @@ -248,6 +327,7 @@ static int ti1250_init(struct pcmcia_socket *sock) struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); yenta_init(sock); ti113x_init(sock); + ti_set_zv(sock); ti_irqmux(socket) = config_readl(socket, TI122X_IRQMUX); ti_irqmux(socket) = (ti_irqmux(socket) & ~0x0f) | 0x02; /* route INTA */ if (!(ti_sysctl(socket) & TI122X_SCR_INTRTIE)) diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 707cb7297fc5..5056a66e3ff1 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -297,6 +297,8 @@ static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state) } exca_writeb(socket, I365_CSCINT, reg); exca_readb(socket, I365_CSC); + if(sock->zoom_video) + sock->zoom_video(sock, state->flags & SS_ZVCARD); } config_writew(socket, CB_BRIDGE_CONTROL, bridge); /* Socket event mask: get card insert/remove events.. */ diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 24cb380be518..08169885af48 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -51,6 +51,7 @@ #define SS_3VCARD 0x1000 #define SS_XVCARD 0x2000 #define SS_PENDING 0x4000 +#define SS_ZVCARD 0x8000 /* InquireSocket capabilities */ #define SS_CAP_PAGE_REGS 0x0001 @@ -209,6 +210,10 @@ struct pcmcia_socket { /* socket operations */ struct pccard_operations * ops; + /* Zoom video behaviour is so chip specific its not worth adding + this to _ops */ + void (*zoom_video)(struct pcmcia_socket *, int); + /* state thread */ struct semaphore skt_sem; /* protects socket h/w state */ -- cgit v1.2.3 From 15d7359a36fd9aa2717416421c216db8c5f371df Mon Sep 17 00:00:00 2001 From: Miles Bader Date: Thu, 17 Jul 2003 20:10:05 -0700 Subject: [PATCH] Rename `nb85e' to `v850e' on v850 The term `nb85e' is incorrect (caused by my confusion when starting the v850 port), so this renames all occurances to `v850e'. Because this change renames some files too, it contains a number of whole-file add/removes. --- arch/v850/kernel/anna.c | 14 ++--- arch/v850/kernel/as85ep1.c | 16 ++--- arch/v850/kernel/fpga85e2c.c | 8 +-- arch/v850/kernel/gbus_int.c | 4 +- arch/v850/kernel/highres_timer.c | 26 ++++---- arch/v850/kernel/ma.c | 8 +-- arch/v850/kernel/nb85e_intc.c | 104 ------------------------------ arch/v850/kernel/nb85e_timer_d.c | 54 ---------------- arch/v850/kernel/nb85e_utils.c | 65 ------------------- arch/v850/kernel/rte_cb.c | 6 +- arch/v850/kernel/rte_ma1_cb.c | 8 +-- arch/v850/kernel/rte_nb85e_cb.c | 4 +- arch/v850/kernel/teg.c | 8 +-- arch/v850/kernel/v850e_intc.c | 104 ++++++++++++++++++++++++++++++ arch/v850/kernel/v850e_timer_d.c | 54 ++++++++++++++++ arch/v850/kernel/v850e_utils.c | 62 ++++++++++++++++++ include/asm-v850/anna.h | 14 ++--- include/asm-v850/as85ep1.h | 18 +++--- include/asm-v850/fpga85e2c.h | 4 +- include/asm-v850/highres_timer.h | 6 +- include/asm-v850/ma.h | 21 +++---- include/asm-v850/nb85e.h | 21 ------- include/asm-v850/nb85e_intc.h | 133 --------------------------------------- include/asm-v850/nb85e_timer_c.h | 48 -------------- include/asm-v850/nb85e_timer_d.h | 62 ------------------ include/asm-v850/nb85e_utils.h | 35 ----------- include/asm-v850/rte_nb85e_cb.h | 31 ++++----- include/asm-v850/teg.h | 18 +++--- include/asm-v850/v850e.h | 21 +++++++ include/asm-v850/v850e_intc.h | 133 +++++++++++++++++++++++++++++++++++++++ include/asm-v850/v850e_timer_c.h | 48 ++++++++++++++ include/asm-v850/v850e_timer_d.h | 62 ++++++++++++++++++ include/asm-v850/v850e_utils.h | 35 +++++++++++ 33 files changed, 628 insertions(+), 627 deletions(-) delete mode 100644 arch/v850/kernel/nb85e_intc.c delete mode 100644 arch/v850/kernel/nb85e_timer_d.c delete mode 100644 arch/v850/kernel/nb85e_utils.c create mode 100644 arch/v850/kernel/v850e_intc.c create mode 100644 arch/v850/kernel/v850e_timer_d.c create mode 100644 arch/v850/kernel/v850e_utils.c delete mode 100644 include/asm-v850/nb85e.h delete mode 100644 include/asm-v850/nb85e_intc.h delete mode 100644 include/asm-v850/nb85e_timer_c.h delete mode 100644 include/asm-v850/nb85e_timer_d.h delete mode 100644 include/asm-v850/nb85e_utils.h create mode 100644 include/asm-v850/v850e.h create mode 100644 include/asm-v850/v850e_intc.h create mode 100644 include/asm-v850/v850e_timer_c.h create mode 100644 include/asm-v850/v850e_timer_d.h create mode 100644 include/asm-v850/v850e_utils.h (limited to 'include') diff --git a/arch/v850/kernel/anna.c b/arch/v850/kernel/anna.c index d364e775f5f2..b47c42dc4175 100644 --- a/arch/v850/kernel/anna.c +++ b/arch/v850/kernel/anna.c @@ -1,8 +1,8 @@ /* * arch/v850/kernel/anna.c -- Anna V850E2 evaluation chip/board * - * Copyright (C) 2002 NEC Corporation - * Copyright (C) 2002 Miles Bader + * Copyright (C) 2002,03 NEC Electronics Corporation + * Copyright (C) 2002,03 Miles Bader * * 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 @@ -21,8 +21,8 @@ #include #include #include -#include -#include +#include +#include #include "mach.h" @@ -95,12 +95,12 @@ void mach_gettimeofday (struct timespec *tv) void __init mach_sched_init (struct irqaction *timer_action) { /* Start hardware timer. */ - nb85e_timer_d_configure (0, HZ); + v850e_timer_d_configure (0, HZ); /* Install timer interrupt handler. */ setup_irq (IRQ_INTCMD(0), timer_action); } -static struct nb85e_intc_irq_init irq_inits[] = { +static struct v850e_intc_irq_init irq_inits[] = { { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, { "PIN", IRQ_INTP(0), IRQ_INTP_NUM, 1, 4 }, { "CCC", IRQ_INTCCC(0), IRQ_INTCCC_NUM, 1, 5 }, @@ -118,7 +118,7 @@ static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; void __init mach_init_irqs (void) { - nb85e_intc_init_irq_types (irq_inits, hw_itypes); + v850e_intc_init_irq_types (irq_inits, hw_itypes); } void machine_restart (char *__unused) diff --git a/arch/v850/kernel/as85ep1.c b/arch/v850/kernel/as85ep1.c index d6dfac9d52d0..9699d76acbbb 100644 --- a/arch/v850/kernel/as85ep1.c +++ b/arch/v850/kernel/as85ep1.c @@ -1,8 +1,8 @@ /* * arch/v850/kernel/as85ep1.c -- AS85EP1 V850E evaluation chip/board * - * Copyright (C) 2002 NEC Corporation - * Copyright (C) 2002 Miles Bader + * Copyright (C) 2002,03 NEC Electronics Corporation + * Copyright (C) 2002,03 Miles Bader * * 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 @@ -21,8 +21,8 @@ #include #include #include -#include -#include +#include +#include #include "mach.h" @@ -90,7 +90,7 @@ void __init mach_early_init (void) AS85EP1_IRAMM = 0x0; /* $BFbB"L?Na(BRAM$B$O!V(Bread-mode$B!W$K$J$j$^$9(B */ #endif /* !CONFIG_ROM_KERNEL */ - nb85e_intc_disable_irqs (); + v850e_intc_disable_irqs (); } void __init mach_setup (char **cmdline) @@ -146,12 +146,12 @@ void mach_gettimeofday (struct timeval *tv) void __init mach_sched_init (struct irqaction *timer_action) { /* Start hardware timer. */ - nb85e_timer_d_configure (0, HZ); + v850e_timer_d_configure (0, HZ); /* Install timer interrupt handler. */ setup_irq (IRQ_INTCMD(0), timer_action); } -static struct nb85e_intc_irq_init irq_inits[] = { +static struct v850e_intc_irq_init irq_inits[] = { { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, { "CCC", IRQ_INTCCC(0), IRQ_INTCCC_NUM, 1, 5 }, { "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 5 }, @@ -166,7 +166,7 @@ static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; void __init mach_init_irqs (void) { - nb85e_intc_init_irq_types (irq_inits, hw_itypes); + v850e_intc_init_irq_types (irq_inits, hw_itypes); } void machine_restart (char *__unused) diff --git a/arch/v850/kernel/fpga85e2c.c b/arch/v850/kernel/fpga85e2c.c index 6c65321bbff6..3f6aad39ed77 100644 --- a/arch/v850/kernel/fpga85e2c.c +++ b/arch/v850/kernel/fpga85e2c.c @@ -2,8 +2,8 @@ * arch/v850/kernel/fpga85e2c.h -- Machine-dependent defs for * FPGA implementation of V850E2/NA85E2C * - * Copyright (C) 2002 NEC Corporation - * Copyright (C) 2002 Miles Bader + * Copyright (C) 2002,03 NEC Electronics Corporation + * Copyright (C) 2002,03 Miles Bader * * 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 @@ -134,7 +134,7 @@ void machine_power_off (void) /* Interrupts */ -struct nb85e_intc_irq_init irq_inits[] = { +struct v850e_intc_irq_init irq_inits[] = { { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, { "RPU", IRQ_RPU(0), IRQ_RPU_NUM, 1, 6 }, { 0 } @@ -146,7 +146,7 @@ struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; /* Initialize interrupts. */ void __init mach_init_irqs (void) { - nb85e_intc_init_irq_types (irq_inits, hw_itypes); + v850e_intc_init_irq_types (irq_inits, hw_itypes); } diff --git a/arch/v850/kernel/gbus_int.c b/arch/v850/kernel/gbus_int.c index cf96abc13889..76533e757589 100644 --- a/arch/v850/kernel/gbus_int.c +++ b/arch/v850/kernel/gbus_int.c @@ -247,7 +247,7 @@ void __init gbus_int_init_irqs (void) /* First initialize the shared gint interrupts. */ for (i = 0; i < NUM_USED_GINTS; i++) { unsigned gint = used_gint[i].gint; - struct nb85e_intc_irq_init gint_irq_init[2]; + struct v850e_intc_irq_init gint_irq_init[2]; /* We initialize one GINT interrupt at a time. */ gint_irq_init[0].name = "GINT"; @@ -258,7 +258,7 @@ void __init gbus_int_init_irqs (void) gint_irq_init[1].name = 0; /* Terminate the vector. */ - nb85e_intc_init_irq_types (gint_irq_init, gint_hw_itypes); + v850e_intc_init_irq_types (gint_irq_init, gint_hw_itypes); } /* Then the GBUS interrupts. */ diff --git a/arch/v850/kernel/highres_timer.c b/arch/v850/kernel/highres_timer.c index 2bf0d2d943ef..b16ad1eaf966 100644 --- a/arch/v850/kernel/highres_timer.c +++ b/arch/v850/kernel/highres_timer.c @@ -1,8 +1,8 @@ /* * arch/v850/kernel/highres_timer.c -- High resolution timing routines * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader * * 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 @@ -12,7 +12,7 @@ */ #include -#include +#include #include #define HIGHRES_TIMER_USEC_SHIFT 12 @@ -42,7 +42,7 @@ void highres_timer_slow_tick_irq (void) void highres_timer_reset (void) { - NB85E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT) = 0; + V850E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT) = 0; HIGHRES_TIMER_SLOW_TICKS = 0; } @@ -51,12 +51,12 @@ void highres_timer_start (void) u32 fast_tick_rate; /* Start hardware timer. */ - nb85e_timer_d_configure (HIGHRES_TIMER_TIMER_D_UNIT, + v850e_timer_d_configure (HIGHRES_TIMER_TIMER_D_UNIT, HIGHRES_TIMER_SLOW_TICK_RATE); fast_tick_rate = - (NB85E_TIMER_D_BASE_FREQ - >> NB85E_TIMER_D_DIVLOG2 (HIGHRES_TIMER_TIMER_D_UNIT)); + (V850E_TIMER_D_BASE_FREQ + >> V850E_TIMER_D_DIVLOG2 (HIGHRES_TIMER_TIMER_D_UNIT)); /* The obvious way of calculating microseconds from fast ticks is to do: @@ -77,16 +77,16 @@ void highres_timer_start (void) /* Enable the interrupt (which is hardwired to this use), and give it the highest priority. */ - NB85E_INTC_IC (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)) = 0; + V850E_INTC_IC (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)) = 0; } void highres_timer_stop (void) { /* Stop the timer. */ - NB85E_TIMER_D_TMCD (HIGHRES_TIMER_TIMER_D_UNIT) = - NB85E_TIMER_D_TMCD_CAE; + V850E_TIMER_D_TMCD (HIGHRES_TIMER_TIMER_D_UNIT) = + V850E_TIMER_D_TMCD_CAE; /* Disable its interrupt, just in case. */ - nb85e_intc_disable_irq (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)); + v850e_intc_disable_irq (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)); } inline void highres_timer_read_ticks (u32 *slow_ticks, u32 *fast_ticks) @@ -95,9 +95,9 @@ inline void highres_timer_read_ticks (u32 *slow_ticks, u32 *fast_ticks) u32 fast_ticks_1, fast_ticks_2, _slow_ticks; local_irq_save (flags); - fast_ticks_1 = NB85E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT); + fast_ticks_1 = V850E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT); _slow_ticks = HIGHRES_TIMER_SLOW_TICKS; - fast_ticks_2 = NB85E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT); + fast_ticks_2 = V850E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT); local_irq_restore (flags); if (fast_ticks_2 < fast_ticks_1) diff --git a/arch/v850/kernel/ma.c b/arch/v850/kernel/ma.c index 05b82f61c04d..b3dfbc5d2f40 100644 --- a/arch/v850/kernel/ma.c +++ b/arch/v850/kernel/ma.c @@ -22,19 +22,19 @@ #include #include #include -#include +#include #include "mach.h" void __init mach_sched_init (struct irqaction *timer_action) { /* Start hardware timer. */ - nb85e_timer_d_configure (0, HZ); + v850e_timer_d_configure (0, HZ); /* Install timer interrupt handler. */ setup_irq (IRQ_INTCMD(0), timer_action); } -static struct nb85e_intc_irq_init irq_inits[] = { +static struct v850e_intc_irq_init irq_inits[] = { { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, { "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 5 }, { "DMA", IRQ_INTDMA(0), IRQ_INTDMA_NUM, 1, 2 }, @@ -51,7 +51,7 @@ static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; /* Initialize MA chip interrupts. */ void __init ma_init_irqs (void) { - nb85e_intc_init_irq_types (irq_inits, hw_itypes); + v850e_intc_init_irq_types (irq_inits, hw_itypes); } /* Called before configuring an on-chip UART. */ diff --git a/arch/v850/kernel/nb85e_intc.c b/arch/v850/kernel/nb85e_intc.c deleted file mode 100644 index 7e562195e8d9..000000000000 --- a/arch/v850/kernel/nb85e_intc.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * arch/v850/kernel/nb85e_intc.c -- NB85E cpu core interrupt controller (INTC) - * - * Copyright (C) 2001,02,03 NEC Electronics Corporation - * Copyright (C) 2001,02,03 Miles Bader - * - * 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. - * - * Written by Miles Bader - */ - -#include -#include -#include - -#include - -static void irq_nop (unsigned irq) { } - -static unsigned nb85e_intc_irq_startup (unsigned irq) -{ - nb85e_intc_clear_pending_irq (irq); - nb85e_intc_enable_irq (irq); - return 0; -} - -static void nb85e_intc_end_irq (unsigned irq) -{ - unsigned long psw, temp; - - /* Clear the highest-level bit in the In-service priority register - (ISPR), to allow this interrupt (or another of the same or - lesser priority) to happen again. - - The `reti' instruction normally does this automatically when the - PSW bits EP and NP are zero, but we can't always rely on reti - being used consistently to return after an interrupt (another - process can be scheduled, for instance, which can delay the - associated reti for a long time, or this process may be being - single-stepped, which uses the `dbret' instruction to return - from the kernel). - - We also set the PSW EP bit, which prevents reti from also - trying to modify the ISPR itself. */ - - /* Get PSW and disable interrupts. */ - asm volatile ("stsr psw, %0; di" : "=r" (psw)); - /* We don't want to do anything for NMIs (they don't use the ISPR). */ - if (! (psw & 0xC0)) { - /* Transition to `trap' state, so that an eventual real - reti instruction won't modify the ISPR. */ - psw |= 0x40; - /* Fake an interrupt return, which automatically clears the - appropriate bit in the ISPR. */ - asm volatile ("mov hilo(1f), %0;" - "ldsr %0, eipc; ldsr %1, eipsw;" - "reti;" - "1:" - : "=&r" (temp) : "r" (psw)); - } -} - -/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array - INITS (which is terminated by an entry with the name field == 0). */ -void __init nb85e_intc_init_irq_types (struct nb85e_intc_irq_init *inits, - struct hw_interrupt_type *hw_irq_types) -{ - struct nb85e_intc_irq_init *init; - for (init = inits; init->name; init++) { - unsigned i; - struct hw_interrupt_type *hwit = hw_irq_types++; - - hwit->typename = init->name; - - hwit->startup = nb85e_intc_irq_startup; - hwit->shutdown = nb85e_intc_disable_irq; - hwit->enable = nb85e_intc_enable_irq; - hwit->disable = nb85e_intc_disable_irq; - hwit->ack = irq_nop; - hwit->end = nb85e_intc_end_irq; - - /* Initialize kernel IRQ infrastructure for this interrupt. */ - init_irq_handlers(init->base, init->num, init->interval, hwit); - - /* Set the interrupt priorities. */ - for (i = 0; i < init->num; i++) { - unsigned irq = init->base + i * init->interval; - - /* If the interrupt is currently enabled (all - interrupts are initially disabled), then - assume whoever enabled it has set things up - properly, and avoid messing with it. */ - if (! nb85e_intc_irq_enabled (irq)) - /* This write also (1) disables the - interrupt, and (2) clears any pending - interrupts. */ - NB85E_INTC_IC (irq) - = (NB85E_INTC_IC_PR (init->priority) - | NB85E_INTC_IC_MK); - } - } -} diff --git a/arch/v850/kernel/nb85e_timer_d.c b/arch/v850/kernel/nb85e_timer_d.c deleted file mode 100644 index 356675fcbbd5..000000000000 --- a/arch/v850/kernel/nb85e_timer_d.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * include/asm-v850/nb85e_timer_d.c -- `Timer D' component often used - * with the NB85E cpu core - * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader - * - * 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. - * - * Written by Miles Bader - */ - -#include - -#include -#include - -/* Start interval timer TIMER (0-3). The timer will issue the - corresponding INTCMD interrupt RATE times per second. - This function does not enable the interrupt. */ -void nb85e_timer_d_configure (unsigned timer, unsigned rate) -{ - unsigned divlog2, count; - - /* Calculate params for timer. */ - if (! calc_counter_params ( - NB85E_TIMER_D_BASE_FREQ, rate, - NB85E_TIMER_D_TMCD_CS_MIN, NB85E_TIMER_D_TMCD_CS_MAX, 16, - &divlog2, &count)) - printk (KERN_WARNING - "Cannot find interval timer %d setting suitable" - " for rate of %dHz.\n" - "Using rate of %dHz instead.\n", - timer, rate, - (NB85E_TIMER_D_BASE_FREQ >> divlog2) >> 16); - - /* Do the actual hardware timer initialization: */ - - /* Enable timer. */ - NB85E_TIMER_D_TMCD(timer) = NB85E_TIMER_D_TMCD_CAE; - /* Set clock divider. */ - NB85E_TIMER_D_TMCD(timer) - = NB85E_TIMER_D_TMCD_CAE - | NB85E_TIMER_D_TMCD_CS(divlog2); - /* Set timer compare register. */ - NB85E_TIMER_D_CMD(timer) = count; - /* Start counting. */ - NB85E_TIMER_D_TMCD(timer) - = NB85E_TIMER_D_TMCD_CAE - | NB85E_TIMER_D_TMCD_CS(divlog2) - | NB85E_TIMER_D_TMCD_CE; -} diff --git a/arch/v850/kernel/nb85e_utils.c b/arch/v850/kernel/nb85e_utils.c deleted file mode 100644 index e826cb76d177..000000000000 --- a/arch/v850/kernel/nb85e_utils.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * include/asm-v850/nb85e_utils.h -- Utility functions associated with - * the NB85E cpu core - * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader - * - * 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. - * - * Written by Miles Bader - */ - -/* Note: these functions are often associated with the N85E cpu core, - but not always, which is why they're not in `nb85e.c'. */ - -#include - -/* Calculate counter clock-divider and count values to attain the - desired frequency RATE from the base frequency BASE_FREQ. The - counter is expected to have a clock-divider, which can divide the - system cpu clock by a power of two value from MIN_DIVLOG2 to - MAX_DIV_LOG2, and a word-size of COUNTER_SIZE bits (the counter - counts up and resets whenever it's equal to the compare register, - generating an interrupt or whatever when it does so). The returned - values are: *DIVLOG2 -- log2 of the desired clock divider and *COUNT - -- the counter compare value to use. Returns true if it was possible - to find a reasonable value, otherwise false (and the other return - values will be set to be as good as possible). */ -int calc_counter_params (unsigned long base_freq, - unsigned long rate, - unsigned min_divlog2, unsigned max_divlog2, - unsigned counter_size, - unsigned *divlog2, unsigned *count) -{ - unsigned _divlog2; - int ok = 0; - - /* Find the lowest clock divider setting that can represent RATE. */ - for (_divlog2 = min_divlog2; _divlog2 <= max_divlog2; _divlog2++) { - /* Minimum interrupt rate possible using this divider. */ - unsigned min_int_rate - = (base_freq >> _divlog2) >> counter_size; - - if (min_int_rate <= rate) { - /* This setting is the highest resolution - setting that's slow enough enough to attain - RATE interrupts per second, so use it. */ - ok = 1; - break; - } - } - - if (_divlog2 > max_divlog2) - /* Can't find correct setting. */ - _divlog2 = max_divlog2; - - if (divlog2) - *divlog2 = _divlog2; - if (count) - *count = ((base_freq >> _divlog2) + rate/2) / rate; - - return ok; -} diff --git a/arch/v850/kernel/rte_cb.c b/arch/v850/kernel/rte_cb.c index 234ebeb3fd28..cdc819886ae6 100644 --- a/arch/v850/kernel/rte_cb.c +++ b/arch/v850/kernel/rte_cb.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include "mach.h" @@ -34,7 +34,7 @@ extern void multi_init (void); void __init rte_cb_early_init (void) { - nb85e_intc_disable_irqs (); + v850e_intc_disable_irqs (); #ifdef CONFIG_RTE_CB_MULTI multi_init (); @@ -43,6 +43,7 @@ void __init rte_cb_early_init (void) void __init mach_setup (char **cmdline) { +#ifdef CONFIG_RTE_MB_A_PCI /* Probe for Mother-A, and print a message if we find it. */ *(volatile unsigned long *)MB_A_SRAM_ADDR = 0xDEADBEEF; if (*(volatile unsigned long *)MB_A_SRAM_ADDR == 0xDEADBEEF) { @@ -194,6 +195,7 @@ static struct hw_interrupt_type gbus_hw_itypes[NUM_GBUS_IRQ_INITS]; #endif /* CONFIG_RTE_GBUS_INT */ + void __init rte_cb_init_irqs (void) { #ifdef CONFIG_RTE_GBUS_INT diff --git a/arch/v850/kernel/rte_ma1_cb.c b/arch/v850/kernel/rte_ma1_cb.c index 8df4a894622b..3873e276392f 100644 --- a/arch/v850/kernel/rte_ma1_cb.c +++ b/arch/v850/kernel/rte_ma1_cb.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include "mach.h" @@ -89,14 +89,14 @@ void __init mach_init_irqs (void) rte_cb_init_irqs (); /* Use falling-edge-sensitivity for interrupts . */ - NB85E_TIMER_C_SESC (0) &= ~0xC; - NB85E_TIMER_C_SESC (1) &= ~0xF; + V850E_TIMER_C_SESC (0) &= ~0xC; + V850E_TIMER_C_SESC (1) &= ~0xF; /* INTP000-INTP011 are shared with `Timer C', so we have to set up Timer C to pass them through as raw interrupts. */ for (tc = 0; tc < 2; tc++) /* Turn on the timer. */ - NB85E_TIMER_C_TMCC0 (tc) |= NB85E_TIMER_C_TMCC0_CAE; + V850E_TIMER_C_TMCC0 (tc) |= V850E_TIMER_C_TMCC0_CAE; /* Make sure the relevant port0/port1 pins are assigned interrupt duty. We used INTP001-INTP011 (don't screw with diff --git a/arch/v850/kernel/rte_nb85e_cb.c b/arch/v850/kernel/rte_nb85e_cb.c index 0fcf233b7083..74074fb3a2f4 100644 --- a/arch/v850/kernel/rte_nb85e_cb.c +++ b/arch/v850/kernel/rte_nb85e_cb.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include "mach.h" @@ -41,7 +41,7 @@ void __init mach_early_init (void) Unfortunately, the dcache seems to be buggy, so we only use the icache for now. */ - nb85e_cache_enable (0x0040 /* BHC */, 0x0000 /* DCC */); + v850e_cache_enable (0x0040 /*BHC*/, 0x0003 /*ICC*/, 0x0000 /*DCC*/); rte_cb_early_init (); } diff --git a/arch/v850/kernel/teg.c b/arch/v850/kernel/teg.c index af87b1c72ffc..495cf8f37bcb 100644 --- a/arch/v850/kernel/teg.c +++ b/arch/v850/kernel/teg.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include "mach.h" @@ -31,12 +31,12 @@ void __init mach_sched_init (struct irqaction *timer_action) /* Select timer interrupt instead of external pin. */ TEG_ISS |= 0x1; /* Start hardware timer. */ - nb85e_timer_d_configure (0, HZ); + v850e_timer_d_configure (0, HZ); /* Install timer interrupt handler. */ setup_irq (IRQ_INTCMD(0), timer_action); } -static struct nb85e_intc_irq_init irq_inits[] = { +static struct v850e_intc_irq_init irq_inits[] = { { "IRQ", 0, NUM_CPU_IRQS, 1, 7 }, { "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 5 }, { "SER", IRQ_INTSER(0), IRQ_INTSER_NUM, 1, 3 }, @@ -51,7 +51,7 @@ static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; /* Initialize MA chip interrupts. */ void __init teg_init_irqs (void) { - nb85e_intc_init_irq_types (irq_inits, hw_itypes); + v850e_intc_init_irq_types (irq_inits, hw_itypes); } /* Called before configuring an on-chip UART. */ diff --git a/arch/v850/kernel/v850e_intc.c b/arch/v850/kernel/v850e_intc.c new file mode 100644 index 000000000000..8d39a52ee6d1 --- /dev/null +++ b/arch/v850/kernel/v850e_intc.c @@ -0,0 +1,104 @@ +/* + * arch/v850/kernel/v850e_intc.c -- V850E interrupt controller (INTC) + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#include +#include +#include + +#include + +static void irq_nop (unsigned irq) { } + +static unsigned v850e_intc_irq_startup (unsigned irq) +{ + v850e_intc_clear_pending_irq (irq); + v850e_intc_enable_irq (irq); + return 0; +} + +static void v850e_intc_end_irq (unsigned irq) +{ + unsigned long psw, temp; + + /* Clear the highest-level bit in the In-service priority register + (ISPR), to allow this interrupt (or another of the same or + lesser priority) to happen again. + + The `reti' instruction normally does this automatically when the + PSW bits EP and NP are zero, but we can't always rely on reti + being used consistently to return after an interrupt (another + process can be scheduled, for instance, which can delay the + associated reti for a long time, or this process may be being + single-stepped, which uses the `dbret' instruction to return + from the kernel). + + We also set the PSW EP bit, which prevents reti from also + trying to modify the ISPR itself. */ + + /* Get PSW and disable interrupts. */ + asm volatile ("stsr psw, %0; di" : "=r" (psw)); + /* We don't want to do anything for NMIs (they don't use the ISPR). */ + if (! (psw & 0xC0)) { + /* Transition to `trap' state, so that an eventual real + reti instruction won't modify the ISPR. */ + psw |= 0x40; + /* Fake an interrupt return, which automatically clears the + appropriate bit in the ISPR. */ + asm volatile ("mov hilo(1f), %0;" + "ldsr %0, eipc; ldsr %1, eipsw;" + "reti;" + "1:" + : "=&r" (temp) : "r" (psw)); + } +} + +/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array + INITS (which is terminated by an entry with the name field == 0). */ +void __init v850e_intc_init_irq_types (struct v850e_intc_irq_init *inits, + struct hw_interrupt_type *hw_irq_types) +{ + struct v850e_intc_irq_init *init; + for (init = inits; init->name; init++) { + unsigned i; + struct hw_interrupt_type *hwit = hw_irq_types++; + + hwit->typename = init->name; + + hwit->startup = v850e_intc_irq_startup; + hwit->shutdown = v850e_intc_disable_irq; + hwit->enable = v850e_intc_enable_irq; + hwit->disable = v850e_intc_disable_irq; + hwit->ack = irq_nop; + hwit->end = v850e_intc_end_irq; + + /* Initialize kernel IRQ infrastructure for this interrupt. */ + init_irq_handlers(init->base, init->num, init->interval, hwit); + + /* Set the interrupt priorities. */ + for (i = 0; i < init->num; i++) { + unsigned irq = init->base + i * init->interval; + + /* If the interrupt is currently enabled (all + interrupts are initially disabled), then + assume whoever enabled it has set things up + properly, and avoid messing with it. */ + if (! v850e_intc_irq_enabled (irq)) + /* This write also (1) disables the + interrupt, and (2) clears any pending + interrupts. */ + V850E_INTC_IC (irq) + = (V850E_INTC_IC_PR (init->priority) + | V850E_INTC_IC_MK); + } + } +} diff --git a/arch/v850/kernel/v850e_timer_d.c b/arch/v850/kernel/v850e_timer_d.c new file mode 100644 index 000000000000..d2a4ece2574c --- /dev/null +++ b/arch/v850/kernel/v850e_timer_d.c @@ -0,0 +1,54 @@ +/* + * include/asm-v850/v850e_timer_d.c -- `Timer D' component often used + * with V850E CPUs + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#include + +#include +#include + +/* Start interval timer TIMER (0-3). The timer will issue the + corresponding INTCMD interrupt RATE times per second. + This function does not enable the interrupt. */ +void v850e_timer_d_configure (unsigned timer, unsigned rate) +{ + unsigned divlog2, count; + + /* Calculate params for timer. */ + if (! calc_counter_params ( + V850E_TIMER_D_BASE_FREQ, rate, + V850E_TIMER_D_TMCD_CS_MIN, V850E_TIMER_D_TMCD_CS_MAX, 16, + &divlog2, &count)) + printk (KERN_WARNING + "Cannot find interval timer %d setting suitable" + " for rate of %dHz.\n" + "Using rate of %dHz instead.\n", + timer, rate, + (V850E_TIMER_D_BASE_FREQ >> divlog2) >> 16); + + /* Do the actual hardware timer initialization: */ + + /* Enable timer. */ + V850E_TIMER_D_TMCD(timer) = V850E_TIMER_D_TMCD_CAE; + /* Set clock divider. */ + V850E_TIMER_D_TMCD(timer) + = V850E_TIMER_D_TMCD_CAE + | V850E_TIMER_D_TMCD_CS(divlog2); + /* Set timer compare register. */ + V850E_TIMER_D_CMD(timer) = count; + /* Start counting. */ + V850E_TIMER_D_TMCD(timer) + = V850E_TIMER_D_TMCD_CAE + | V850E_TIMER_D_TMCD_CS(divlog2) + | V850E_TIMER_D_TMCD_CE; +} diff --git a/arch/v850/kernel/v850e_utils.c b/arch/v850/kernel/v850e_utils.c new file mode 100644 index 000000000000..e6807ef8dee6 --- /dev/null +++ b/arch/v850/kernel/v850e_utils.c @@ -0,0 +1,62 @@ +/* + * include/asm-v850/v850e_utils.h -- Utility functions associated with + * V850E CPUs + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#include + +/* Calculate counter clock-divider and count values to attain the + desired frequency RATE from the base frequency BASE_FREQ. The + counter is expected to have a clock-divider, which can divide the + system cpu clock by a power of two value from MIN_DIVLOG2 to + MAX_DIV_LOG2, and a word-size of COUNTER_SIZE bits (the counter + counts up and resets whenever it's equal to the compare register, + generating an interrupt or whatever when it does so). The returned + values are: *DIVLOG2 -- log2 of the desired clock divider and *COUNT + -- the counter compare value to use. Returns true if it was possible + to find a reasonable value, otherwise false (and the other return + values will be set to be as good as possible). */ +int calc_counter_params (unsigned long base_freq, + unsigned long rate, + unsigned min_divlog2, unsigned max_divlog2, + unsigned counter_size, + unsigned *divlog2, unsigned *count) +{ + unsigned _divlog2; + int ok = 0; + + /* Find the lowest clock divider setting that can represent RATE. */ + for (_divlog2 = min_divlog2; _divlog2 <= max_divlog2; _divlog2++) { + /* Minimum interrupt rate possible using this divider. */ + unsigned min_int_rate + = (base_freq >> _divlog2) >> counter_size; + + if (min_int_rate <= rate) { + /* This setting is the highest resolution + setting that's slow enough enough to attain + RATE interrupts per second, so use it. */ + ok = 1; + break; + } + } + + if (_divlog2 > max_divlog2) + /* Can't find correct setting. */ + _divlog2 = max_divlog2; + + if (divlog2) + *divlog2 = _divlog2; + if (count) + *count = ((base_freq >> _divlog2) + rate/2) / rate; + + return ok; +} diff --git a/include/asm-v850/anna.h b/include/asm-v850/anna.h index df5caefdc157..44d261afa82a 100644 --- a/include/asm-v850/anna.h +++ b/include/asm-v850/anna.h @@ -145,16 +145,16 @@ extern void anna_uart_pre_configure (unsigned chan, /* Timer C details. */ -#define NB85E_TIMER_C_BASE_ADDR 0xFFFFF600 +#define V850E_TIMER_C_BASE_ADDR 0xFFFFF600 /* Timer D details (the Anna actually has 5 of these; should change later). */ -#define NB85E_TIMER_D_BASE_ADDR 0xFFFFF540 -#define NB85E_TIMER_D_TMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x0) -#define NB85E_TIMER_D_CMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x2) -#define NB85E_TIMER_D_TMCD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x4) +#define V850E_TIMER_D_BASE_ADDR 0xFFFFF540 +#define V850E_TIMER_D_TMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x0) +#define V850E_TIMER_D_CMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x2) +#define V850E_TIMER_D_TMCD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x4) -#define NB85E_TIMER_D_BASE_FREQ SYS_CLOCK_FREQ -#define NB85E_TIMER_D_TMCD_CS_MIN 1 /* min 2^1 divider */ +#define V850E_TIMER_D_BASE_FREQ SYS_CLOCK_FREQ +#define V850E_TIMER_D_TMCD_CS_MIN 1 /* min 2^1 divider */ /* For */ diff --git a/include/asm-v850/as85ep1.h b/include/asm-v850/as85ep1.h index 4216309005b6..707d40da101a 100644 --- a/include/asm-v850/as85ep1.h +++ b/include/asm-v850/as85ep1.h @@ -1,8 +1,8 @@ /* * include/asm-v850/as85ep1.h -- AS85EP1 evaluation CPU chip/board * - * Copyright (C) 2001,2002 NEC Corporation - * Copyright (C) 2001,2002 Miles Bader + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader * * 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 @@ -139,16 +139,16 @@ extern void as85ep1_uart_pre_configure (unsigned chan, /* Timer C details. */ -#define NB85E_TIMER_C_BASE_ADDR 0xFFFFF600 +#define V850E_TIMER_C_BASE_ADDR 0xFFFFF600 /* Timer D details (the AS85EP1 actually has 5 of these; should change later). */ -#define NB85E_TIMER_D_BASE_ADDR 0xFFFFF540 -#define NB85E_TIMER_D_TMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x0) -#define NB85E_TIMER_D_CMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x2) -#define NB85E_TIMER_D_TMCD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x4) +#define V850E_TIMER_D_BASE_ADDR 0xFFFFF540 +#define V850E_TIMER_D_TMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x0) +#define V850E_TIMER_D_CMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x2) +#define V850E_TIMER_D_TMCD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x4) -#define NB85E_TIMER_D_BASE_FREQ SYS_CLOCK_FREQ -#define NB85E_TIMER_D_TMCD_CS_MIN 2 /* min 2^2 divider */ +#define V850E_TIMER_D_BASE_FREQ SYS_CLOCK_FREQ +#define V850E_TIMER_D_TMCD_CS_MIN 2 /* min 2^2 divider */ /* For */ diff --git a/include/asm-v850/fpga85e2c.h b/include/asm-v850/fpga85e2c.h index 54343b18e650..77d7d22e5ee5 100644 --- a/include/asm-v850/fpga85e2c.h +++ b/include/asm-v850/fpga85e2c.h @@ -2,8 +2,8 @@ * include/asm-v850/fpga85e2c.h -- Machine-dependent defs for * FPGA implementation of V850E2/NA85E2C * - * Copyright (C) 2002 NEC Corporation - * Copyright (C) 2002 Miles Bader + * Copyright (C) 2002,03 NEC Electronics Corporation + * Copyright (C) 2002,03 Miles Bader * * 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 diff --git a/include/asm-v850/highres_timer.h b/include/asm-v850/highres_timer.h index c63b8cd1bff4..486fb49ceab6 100644 --- a/include/asm-v850/highres_timer.h +++ b/include/asm-v850/highres_timer.h @@ -1,8 +1,8 @@ /* * include/asm-v850/highres_timer.h -- High resolution timing routines * - * Copyright (C) 2001 NEC Corporation - * Copyright (C) 2001 Miles Bader + * Copyright (C) 2001,03 NEC Electronics Corporation + * Copyright (C) 2001,03 Miles Bader * * 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 @@ -25,7 +25,7 @@ counter overflows). */ #define HIGHRES_TIMER_SLOW_TICK_RATE 25 -/* Which timer in the nb85e `Timer D' we use. */ +/* Which timer in the V850E `Timer D' we use. */ #define HIGHRES_TIMER_TIMER_D_UNIT 3 diff --git a/include/asm-v850/ma.h b/include/asm-v850/ma.h index ed153b642360..991a9c343ef1 100644 --- a/include/asm-v850/ma.h +++ b/include/asm-v850/ma.h @@ -1,8 +1,8 @@ /* * include/asm-v850/ma.h -- V850E/MA series of cpu chips * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader * * 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 @@ -14,9 +14,8 @@ #ifndef __V850_MA_H__ #define __V850_MA_H__ - -/* The MA series uses the NB85E cpu core. */ -#include +/* The MA series uses the V850E cpu core. */ +#include /* For */ @@ -39,16 +38,16 @@ extern void ma_uart_pre_configure (unsigned chan, /* MA series timer C details. */ -#define NB85E_TIMER_C_BASE_ADDR 0xFFFFF600 +#define V850E_TIMER_C_BASE_ADDR 0xFFFFF600 /* MA series timer D details. */ -#define NB85E_TIMER_D_BASE_ADDR 0xFFFFF540 -#define NB85E_TIMER_D_TMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x0) -#define NB85E_TIMER_D_CMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x2) -#define NB85E_TIMER_D_TMCD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x4) +#define V850E_TIMER_D_BASE_ADDR 0xFFFFF540 +#define V850E_TIMER_D_TMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x0) +#define V850E_TIMER_D_CMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x2) +#define V850E_TIMER_D_TMCD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x4) -#define NB85E_TIMER_D_BASE_FREQ CPU_CLOCK_FREQ +#define V850E_TIMER_D_BASE_FREQ CPU_CLOCK_FREQ /* Port 0 */ diff --git a/include/asm-v850/nb85e.h b/include/asm-v850/nb85e.h deleted file mode 100644 index bdfa136d85d1..000000000000 --- a/include/asm-v850/nb85e.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * include/asm-v850/nb85e.h -- NB85E cpu core - * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader - * - * 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. - * - * Written by Miles Bader - */ - -#ifndef __V850_NB85E_H__ -#define __V850_NB85E_H__ - -#include - -#define CPU_ARCH "v850e" - -#endif /* __V850_NB85E_H__ */ diff --git a/include/asm-v850/nb85e_intc.h b/include/asm-v850/nb85e_intc.h deleted file mode 100644 index d81b777363cc..000000000000 --- a/include/asm-v850/nb85e_intc.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * include/asm-v850/nb85e_intc.h -- NB85E cpu core interrupt controller (INTC) - * - * Copyright (C) 2001,02,03 NEC Electronics Corporation - * Copyright (C) 2001,02,03 Miles Bader - * - * 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. - * - * Written by Miles Bader - */ - -#ifndef __V850_NB85E_INTC_H__ -#define __V850_NB85E_INTC_H__ - - -/* There are 4 16-bit `Interrupt Mask Registers' located contiguously - starting from this base. Each interrupt uses a single bit to - indicated enabled/disabled status. */ -#define NB85E_INTC_IMR_BASE_ADDR 0xFFFFF100 -#define NB85E_INTC_IMR_ADDR(irq) (NB85E_INTC_IMR_BASE_ADDR + ((irq) >> 3)) -#define NB85E_INTC_IMR_BIT(irq) ((irq) & 0x7) - -/* Each maskable interrupt has a single-byte control register at this - address. */ -#define NB85E_INTC_IC_BASE_ADDR 0xFFFFF110 -#define NB85E_INTC_IC_ADDR(irq) (NB85E_INTC_IC_BASE_ADDR + ((irq) << 1)) -#define NB85E_INTC_IC(irq) (*(volatile u8 *)NB85E_INTC_IC_ADDR(irq)) -/* Encode priority PR for storing in an interrupt control register. */ -#define NB85E_INTC_IC_PR(pr) (pr) -/* Interrupt disable bit in an interrupt control register. */ -#define NB85E_INTC_IC_MK_BIT 6 -#define NB85E_INTC_IC_MK (1 << NB85E_INTC_IC_MK_BIT) -/* Interrupt pending flag in an interrupt control register. */ -#define NB85E_INTC_IC_IF_BIT 7 -#define NB85E_INTC_IC_IF (1 << NB85E_INTC_IC_IF_BIT) - -/* The ISPR (In-service priority register) contains one bit for each interrupt - priority level, which is set to one when that level is currently being - serviced (and thus blocking any interrupts of equal or lesser level). */ -#define NB85E_INTC_ISPR_ADDR 0xFFFFF1FA -#define NB85E_INTC_ISPR (*(volatile u8 *)NB85E_INTC_ISPR_ADDR) - - -#ifndef __ASSEMBLY__ - -/* Enable interrupt handling for interrupt IRQ. */ -static inline void nb85e_intc_enable_irq (unsigned irq) -{ - __asm__ __volatile__ ("clr1 %0, [%1]" - :: "r" (NB85E_INTC_IMR_BIT (irq)), - "r" (NB85E_INTC_IMR_ADDR (irq)) - : "memory"); -} - -/* Disable interrupt handling for interrupt IRQ. Note that any - interrupts received while disabled will be delivered once the - interrupt is enabled again, unless they are explicitly cleared using - `nb85e_intc_clear_pending_irq'. */ -static inline void nb85e_intc_disable_irq (unsigned irq) -{ - __asm__ __volatile__ ("set1 %0, [%1]" - :: "r" (NB85E_INTC_IMR_BIT (irq)), - "r" (NB85E_INTC_IMR_ADDR (irq)) - : "memory"); -} - -/* Return true if interrupt handling for interrupt IRQ is enabled. */ -static inline int nb85e_intc_irq_enabled (unsigned irq) -{ - int rval; - __asm__ __volatile__ ("tst1 %1, [%2]; setf z, %0" - : "=r" (rval) - : "r" (NB85E_INTC_IMR_BIT (irq)), - "r" (NB85E_INTC_IMR_ADDR (irq))); - return rval; -} - -/* Disable irqs from 0 until LIMIT. LIMIT must be a multiple of 8. */ -static inline void _nb85e_intc_disable_irqs (unsigned limit) -{ - unsigned long addr; - for (addr = NB85E_INTC_IMR_BASE_ADDR; limit >= 8; addr++, limit -= 8) - *(char *)addr = 0xFF; -} - -/* Disable all irqs. This is purposely a macro, because NUM_MACH_IRQS - will be only be defined later. */ -#define nb85e_intc_disable_irqs() _nb85e_intc_disable_irqs (NUM_MACH_IRQS) - -/* Clear any pending interrupts for IRQ. */ -static inline void nb85e_intc_clear_pending_irq (unsigned irq) -{ - __asm__ __volatile__ ("clr1 %0, 0[%1]" - :: "i" (NB85E_INTC_IC_IF_BIT), - "r" (NB85E_INTC_IC_ADDR (irq)) - : "memory"); -} - -/* Return true if interrupt IRQ is pending (but disabled). */ -static inline int nb85e_intc_irq_pending (unsigned irq) -{ - int rval; - __asm__ __volatile__ ("tst1 %1, 0[%2]; setf nz, %0" - : "=r" (rval) - : "i" (NB85E_INTC_IC_IF_BIT), - "r" (NB85E_INTC_IC_ADDR (irq))); - return rval; -} - - -struct nb85e_intc_irq_init { - const char *name; /* name of interrupt type */ - - /* Range of kernel irq numbers for this type: - BASE, BASE+INTERVAL, ..., BASE+INTERVAL*NUM */ - unsigned base, num, interval; - - unsigned priority; /* interrupt priority to assign */ -}; -struct hw_interrupt_type; /* fwd decl */ - -/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array - INITS (which is terminated by an entry with the name field == 0). */ -extern void nb85e_intc_init_irq_types (struct nb85e_intc_irq_init *inits, - struct hw_interrupt_type *hw_irq_types); - - -#endif /* !__ASSEMBLY__ */ - - -#endif /* __V850_NB85E_INTC_H__ */ diff --git a/include/asm-v850/nb85e_timer_c.h b/include/asm-v850/nb85e_timer_c.h deleted file mode 100644 index 069513b6de33..000000000000 --- a/include/asm-v850/nb85e_timer_c.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * include/asm-v850/nb85e_timer_c.h -- `Timer C' component often used - * with the NB85E cpu core - * - * Copyright (C) 2001 NEC Corporation - * Copyright (C) 2001 Miles Bader - * - * 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. - * - * Written by Miles Bader - */ - -/* NOTE: this include file currently contains only enough to allow us to - use timer C as an interrupt pass-through. */ - -#ifndef __V850_NB85E_TIMER_C_H__ -#define __V850_NB85E_TIMER_C_H__ - -#include -#include /* Pick up chip-specific defs. */ - - -/* Timer C (16-bit interval timers). */ - -/* Control register 0 for timer C. */ -#define NB85E_TIMER_C_TMCC0_ADDR(n) (NB85E_TIMER_C_BASE_ADDR + 0x6 + 0x10 *(n)) -#define NB85E_TIMER_C_TMCC0(n) (*(volatile u8 *)NB85E_TIMER_C_TMCC0_ADDR(n)) -#define NB85E_TIMER_C_TMCC0_CAE 0x01 /* clock action enable */ -#define NB85E_TIMER_C_TMCC0_CE 0x02 /* count enable */ -/* ... */ - -/* Control register 1 for timer C. */ -#define NB85E_TIMER_C_TMCC1_ADDR(n) (NB85E_TIMER_C_BASE_ADDR + 0x8 + 0x10 *(n)) -#define NB85E_TIMER_C_TMCC1(n) (*(volatile u8 *)NB85E_TIMER_C_TMCC1_ADDR(n)) -#define NB85E_TIMER_C_TMCC1_CMS0 0x01 /* capture/compare mode select (ccc0) */ -#define NB85E_TIMER_C_TMCC1_CMS1 0x02 /* capture/compare mode select (ccc1) */ -/* ... */ - -/* Interrupt edge-sensitivity control for timer C. */ -#define NB85E_TIMER_C_SESC_ADDR(n) (NB85E_TIMER_C_BASE_ADDR + 0x9 + 0x10 *(n)) -#define NB85E_TIMER_C_SESC(n) (*(volatile u8 *)NB85E_TIMER_C_SESC_ADDR(n)) - -/* ...etc... */ - - -#endif /* __V850_NB85E_TIMER_C_H__ */ diff --git a/include/asm-v850/nb85e_timer_d.h b/include/asm-v850/nb85e_timer_d.h deleted file mode 100644 index 2243bc1732c8..000000000000 --- a/include/asm-v850/nb85e_timer_d.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * include/asm-v850/nb85e_timer_d.h -- `Timer D' component often used - * with the NB85E cpu core - * - * Copyright (C) 2001,02,03 NEC Electronics Corporation - * Copyright (C) 2001,02,03 Miles Bader - * - * 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. - * - * Written by Miles Bader - */ - -#ifndef __V850_NB85E_TIMER_D_H__ -#define __V850_NB85E_TIMER_D_H__ - -#include -#include /* Pick up chip-specific defs. */ - - -/* Timer D (16-bit interval timers). */ - -/* Count registers for timer D. */ -#define NB85E_TIMER_D_TMD_ADDR(n) (NB85E_TIMER_D_TMD_BASE_ADDR + 0x10 * (n)) -#define NB85E_TIMER_D_TMD(n) (*(volatile u16 *)NB85E_TIMER_D_TMD_ADDR(n)) - -/* Count compare registers for timer D. */ -#define NB85E_TIMER_D_CMD_ADDR(n) (NB85E_TIMER_D_CMD_BASE_ADDR + 0x10 * (n)) -#define NB85E_TIMER_D_CMD(n) (*(volatile u16 *)NB85E_TIMER_D_CMD_ADDR(n)) - -/* Control registers for timer D. */ -#define NB85E_TIMER_D_TMCD_ADDR(n) (NB85E_TIMER_D_TMCD_BASE_ADDR + 0x10 * (n)) -#define NB85E_TIMER_D_TMCD(n) (*(volatile u8 *)NB85E_TIMER_D_TMCD_ADDR(n)) -/* Control bits for timer D. */ -#define NB85E_TIMER_D_TMCD_CE 0x2 /* count enable */ -#define NB85E_TIMER_D_TMCD_CAE 0x1 /* clock action enable */ -/* Clock divider setting (log2). */ -#define NB85E_TIMER_D_TMCD_CS(divlog2) (((divlog2) - NB85E_TIMER_D_TMCD_CS_MIN) << 4) -/* Minimum clock divider setting (log2). */ -#ifndef NB85E_TIMER_D_TMCD_CS_MIN /* Can be overridden by mach-specific hdrs */ -#define NB85E_TIMER_D_TMCD_CS_MIN 2 /* Default is correct for the v850e/ma1 */ -#endif -/* Maximum clock divider setting (log2). */ -#define NB85E_TIMER_D_TMCD_CS_MAX (NB85E_TIMER_D_TMCD_CS_MIN + 7) - -/* Return the clock-divider (log2) of timer D unit N. */ -#define NB85E_TIMER_D_DIVLOG2(n) \ - (((NB85E_TIMER_D_TMCD(n) >> 4) & 0x7) + NB85E_TIMER_D_TMCD_CS_MIN) - - -#ifndef __ASSEMBLY__ - -/* Start interval timer TIMER (0-3). The timer will issue the - corresponding INTCMD interrupt RATE times per second. This function - does not enable the interrupt. */ -extern void nb85e_timer_d_configure (unsigned timer, unsigned rate); - -#endif /* !__ASSEMBLY__ */ - - -#endif /* __V850_NB85E_TIMER_D_H__ */ diff --git a/include/asm-v850/nb85e_utils.h b/include/asm-v850/nb85e_utils.h deleted file mode 100644 index 56314a2e070a..000000000000 --- a/include/asm-v850/nb85e_utils.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * include/asm-v850/nb85e_utils.h -- Utility functions associated with - * the NB85E cpu core - * - * Copyright (C) 2001 NEC Corporation - * Copyright (C) 2001 Miles Bader - * - * 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. - * - * Written by Miles Bader - */ - -#ifndef __V850_NB85E_UTILS_H__ -#define __V850_NB85E_UTILS_H__ - -/* Calculate counter clock-divider and count values to attain the - desired frequency RATE from the base frequency BASE_FREQ. The - counter is expected to have a clock-divider, which can divide the - system cpu clock by a power of two value from MIN_DIVLOG2 to - MAX_DIV_LOG2, and a word-size of COUNTER_SIZE bits (the counter - counts up and resets whenever it's equal to the compare register, - generating an interrupt or whatever when it does so). The returned - values are: *DIVLOG2 -- log2 of the desired clock divider and *COUNT - -- the counter compare value to use. Returns true if it was possible - to find a reasonable value, otherwise false (and the other return - values will be set to be as good as possible). */ -extern int calc_counter_params (unsigned long base_freq, - unsigned long rate, - unsigned min_divlog2, unsigned max_divlog2, - unsigned counter_size, - unsigned *divlog2, unsigned *count); - -#endif /* __V850_NB85E_UTILS_H__ */ diff --git a/include/asm-v850/rte_nb85e_cb.h b/include/asm-v850/rte_nb85e_cb.h index e3799a1ec831..77aa72f8cc81 100644 --- a/include/asm-v850/rte_nb85e_cb.h +++ b/include/asm-v850/rte_nb85e_cb.h @@ -17,6 +17,21 @@ #include /* Common defs for Midas RTE-CB boards. */ +#define PLATFORM "rte-v850e/nb85e-cb" +#define PLATFORM_LONG "Midas lab RTE-V850E/NB85E-CB" + +#define CPU_CLOCK_FREQ 50000000 /* 50MHz */ + +/* 1MB of onboard SRAM. Note that the monitor ROM uses parts of this + for its own purposes, so care must be taken. */ +#define SRAM_ADDR 0x03C00000 +#define SRAM_SIZE 0x00100000 /* 1MB */ + +/* 16MB of onbard SDRAM. */ +#define SDRAM_ADDR 0x01000000 +#define SDRAM_SIZE 0x01000000 /* 16MB */ + + /* CPU addresses of GBUS memory spaces. */ #define GCS0_ADDR 0x00400000 /* GCS0 - Common SRAM (2MB) */ #define GCS0_SIZE 0x00400000 /* 4MB */ @@ -39,20 +54,8 @@ #define IRQ_GINT(n) (10 + (n)) #define IRQ_GINT_NUM 3 - -#define PLATFORM "rte-v850e/nb85e-cb" -#define PLATFORM_LONG "Midas lab RTE-V850E/NB85E-CB" - -#define CPU_CLOCK_FREQ 50000000 /* 50MHz */ - -/* 1MB of onboard SRAM. Note that the monitor ROM uses parts of this - for its own purposes, so care must be taken. */ -#define SRAM_ADDR 0x03C00000 -#define SRAM_SIZE 0x00100000 /* 1MB */ - -/* 16MB of onbard SDRAM. */ -#define SDRAM_ADDR 0x01000000 -#define SDRAM_SIZE 0x01000000 /* 16MB */ +/* Used by to derive NUM_MACH_IRQS. */ +#define NUM_RTE_CB_IRQS NUM_CPU_IRQS #ifdef CONFIG_ROM_KERNEL diff --git a/include/asm-v850/teg.h b/include/asm-v850/teg.h index caeac99dd611..0f641a4e6eb9 100644 --- a/include/asm-v850/teg.h +++ b/include/asm-v850/teg.h @@ -15,9 +15,9 @@ #define __V850_TEG_H__ -/* The TEG uses the NB85E cpu core. */ -#include -#include +/* The TEG uses the V850E cpu core. */ +#include +#include #define CPU_MODEL "v850e/nb85e-teg" @@ -70,15 +70,15 @@ extern void teg_uart_pre_configure (unsigned chan, /* The TEG RTPU. */ -#define NB85E_RTPU_BASE_ADDR 0xFFFFF210 +#define V850E_RTPU_BASE_ADDR 0xFFFFF210 /* TEG series timer D details. */ -#define NB85E_TIMER_D_BASE_ADDR 0xFFFFF210 -#define NB85E_TIMER_D_TMCD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x0) -#define NB85E_TIMER_D_TMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x4) -#define NB85E_TIMER_D_CMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x8) -#define NB85E_TIMER_D_BASE_FREQ CPU_CLOCK_FREQ +#define V850E_TIMER_D_BASE_ADDR 0xFFFFF210 +#define V850E_TIMER_D_TMCD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x0) +#define V850E_TIMER_D_TMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x4) +#define V850E_TIMER_D_CMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x8) +#define V850E_TIMER_D_BASE_FREQ CPU_CLOCK_FREQ /* `Interrupt Source Select' control register. */ diff --git a/include/asm-v850/v850e.h b/include/asm-v850/v850e.h new file mode 100644 index 000000000000..5a222eb5117f --- /dev/null +++ b/include/asm-v850/v850e.h @@ -0,0 +1,21 @@ +/* + * include/asm-v850/v850e.h -- V850E CPU + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#ifndef __V850_V850E_H__ +#define __V850_V850E_H__ + +#include + +#define CPU_ARCH "v850e" + +#endif /* __V850_V850E_H__ */ diff --git a/include/asm-v850/v850e_intc.h b/include/asm-v850/v850e_intc.h new file mode 100644 index 000000000000..6fdf95708317 --- /dev/null +++ b/include/asm-v850/v850e_intc.h @@ -0,0 +1,133 @@ +/* + * include/asm-v850/v850e_intc.h -- V850E CPU interrupt controller (INTC) + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#ifndef __V850_V850E_INTC_H__ +#define __V850_V850E_INTC_H__ + + +/* There are 4 16-bit `Interrupt Mask Registers' located contiguously + starting from this base. Each interrupt uses a single bit to + indicated enabled/disabled status. */ +#define V850E_INTC_IMR_BASE_ADDR 0xFFFFF100 +#define V850E_INTC_IMR_ADDR(irq) (V850E_INTC_IMR_BASE_ADDR + ((irq) >> 3)) +#define V850E_INTC_IMR_BIT(irq) ((irq) & 0x7) + +/* Each maskable interrupt has a single-byte control register at this + address. */ +#define V850E_INTC_IC_BASE_ADDR 0xFFFFF110 +#define V850E_INTC_IC_ADDR(irq) (V850E_INTC_IC_BASE_ADDR + ((irq) << 1)) +#define V850E_INTC_IC(irq) (*(volatile u8 *)V850E_INTC_IC_ADDR(irq)) +/* Encode priority PR for storing in an interrupt control register. */ +#define V850E_INTC_IC_PR(pr) (pr) +/* Interrupt disable bit in an interrupt control register. */ +#define V850E_INTC_IC_MK_BIT 6 +#define V850E_INTC_IC_MK (1 << V850E_INTC_IC_MK_BIT) +/* Interrupt pending flag in an interrupt control register. */ +#define V850E_INTC_IC_IF_BIT 7 +#define V850E_INTC_IC_IF (1 << V850E_INTC_IC_IF_BIT) + +/* The ISPR (In-service priority register) contains one bit for each interrupt + priority level, which is set to one when that level is currently being + serviced (and thus blocking any interrupts of equal or lesser level). */ +#define V850E_INTC_ISPR_ADDR 0xFFFFF1FA +#define V850E_INTC_ISPR (*(volatile u8 *)V850E_INTC_ISPR_ADDR) + + +#ifndef __ASSEMBLY__ + +/* Enable interrupt handling for interrupt IRQ. */ +static inline void v850e_intc_enable_irq (unsigned irq) +{ + __asm__ __volatile__ ("clr1 %0, [%1]" + :: "r" (V850E_INTC_IMR_BIT (irq)), + "r" (V850E_INTC_IMR_ADDR (irq)) + : "memory"); +} + +/* Disable interrupt handling for interrupt IRQ. Note that any + interrupts received while disabled will be delivered once the + interrupt is enabled again, unless they are explicitly cleared using + `v850e_intc_clear_pending_irq'. */ +static inline void v850e_intc_disable_irq (unsigned irq) +{ + __asm__ __volatile__ ("set1 %0, [%1]" + :: "r" (V850E_INTC_IMR_BIT (irq)), + "r" (V850E_INTC_IMR_ADDR (irq)) + : "memory"); +} + +/* Return true if interrupt handling for interrupt IRQ is enabled. */ +static inline int v850e_intc_irq_enabled (unsigned irq) +{ + int rval; + __asm__ __volatile__ ("tst1 %1, [%2]; setf z, %0" + : "=r" (rval) + : "r" (V850E_INTC_IMR_BIT (irq)), + "r" (V850E_INTC_IMR_ADDR (irq))); + return rval; +} + +/* Disable irqs from 0 until LIMIT. LIMIT must be a multiple of 8. */ +static inline void _v850e_intc_disable_irqs (unsigned limit) +{ + unsigned long addr; + for (addr = V850E_INTC_IMR_BASE_ADDR; limit >= 8; addr++, limit -= 8) + *(char *)addr = 0xFF; +} + +/* Disable all irqs. This is purposely a macro, because NUM_MACH_IRQS + will be only be defined later. */ +#define v850e_intc_disable_irqs() _v850e_intc_disable_irqs (NUM_MACH_IRQS) + +/* Clear any pending interrupts for IRQ. */ +static inline void v850e_intc_clear_pending_irq (unsigned irq) +{ + __asm__ __volatile__ ("clr1 %0, 0[%1]" + :: "i" (V850E_INTC_IC_IF_BIT), + "r" (V850E_INTC_IC_ADDR (irq)) + : "memory"); +} + +/* Return true if interrupt IRQ is pending (but disabled). */ +static inline int v850e_intc_irq_pending (unsigned irq) +{ + int rval; + __asm__ __volatile__ ("tst1 %1, 0[%2]; setf nz, %0" + : "=r" (rval) + : "i" (V850E_INTC_IC_IF_BIT), + "r" (V850E_INTC_IC_ADDR (irq))); + return rval; +} + + +struct v850e_intc_irq_init { + const char *name; /* name of interrupt type */ + + /* Range of kernel irq numbers for this type: + BASE, BASE+INTERVAL, ..., BASE+INTERVAL*NUM */ + unsigned base, num, interval; + + unsigned priority; /* interrupt priority to assign */ +}; +struct hw_interrupt_type; /* fwd decl */ + +/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array + INITS (which is terminated by an entry with the name field == 0). */ +extern void v850e_intc_init_irq_types (struct v850e_intc_irq_init *inits, + struct hw_interrupt_type *hw_irq_types); + + +#endif /* !__ASSEMBLY__ */ + + +#endif /* __V850_V850E_INTC_H__ */ diff --git a/include/asm-v850/v850e_timer_c.h b/include/asm-v850/v850e_timer_c.h new file mode 100644 index 000000000000..f70575df6ea9 --- /dev/null +++ b/include/asm-v850/v850e_timer_c.h @@ -0,0 +1,48 @@ +/* + * include/asm-v850/v850e_timer_c.h -- `Timer C' component often used + * with the V850E cpu core + * + * Copyright (C) 2001,03 NEC Electronics Corporation + * Copyright (C) 2001,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +/* NOTE: this include file currently contains only enough to allow us to + use timer C as an interrupt pass-through. */ + +#ifndef __V850_V850E_TIMER_C_H__ +#define __V850_V850E_TIMER_C_H__ + +#include +#include /* Pick up chip-specific defs. */ + + +/* Timer C (16-bit interval timers). */ + +/* Control register 0 for timer C. */ +#define V850E_TIMER_C_TMCC0_ADDR(n) (V850E_TIMER_C_BASE_ADDR + 0x6 + 0x10 *(n)) +#define V850E_TIMER_C_TMCC0(n) (*(volatile u8 *)V850E_TIMER_C_TMCC0_ADDR(n)) +#define V850E_TIMER_C_TMCC0_CAE 0x01 /* clock action enable */ +#define V850E_TIMER_C_TMCC0_CE 0x02 /* count enable */ +/* ... */ + +/* Control register 1 for timer C. */ +#define V850E_TIMER_C_TMCC1_ADDR(n) (V850E_TIMER_C_BASE_ADDR + 0x8 + 0x10 *(n)) +#define V850E_TIMER_C_TMCC1(n) (*(volatile u8 *)V850E_TIMER_C_TMCC1_ADDR(n)) +#define V850E_TIMER_C_TMCC1_CMS0 0x01 /* capture/compare mode select (ccc0) */ +#define V850E_TIMER_C_TMCC1_CMS1 0x02 /* capture/compare mode select (ccc1) */ +/* ... */ + +/* Interrupt edge-sensitivity control for timer C. */ +#define V850E_TIMER_C_SESC_ADDR(n) (V850E_TIMER_C_BASE_ADDR + 0x9 + 0x10 *(n)) +#define V850E_TIMER_C_SESC(n) (*(volatile u8 *)V850E_TIMER_C_SESC_ADDR(n)) + +/* ...etc... */ + + +#endif /* __V850_V850E_TIMER_C_H__ */ diff --git a/include/asm-v850/v850e_timer_d.h b/include/asm-v850/v850e_timer_d.h new file mode 100644 index 000000000000..417612c5b22f --- /dev/null +++ b/include/asm-v850/v850e_timer_d.h @@ -0,0 +1,62 @@ +/* + * include/asm-v850/v850e_timer_d.h -- `Timer D' component often used + * with the V850E cpu core + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#ifndef __V850_V850E_TIMER_D_H__ +#define __V850_V850E_TIMER_D_H__ + +#include +#include /* Pick up chip-specific defs. */ + + +/* Timer D (16-bit interval timers). */ + +/* Count registers for timer D. */ +#define V850E_TIMER_D_TMD_ADDR(n) (V850E_TIMER_D_TMD_BASE_ADDR + 0x10 * (n)) +#define V850E_TIMER_D_TMD(n) (*(volatile u16 *)V850E_TIMER_D_TMD_ADDR(n)) + +/* Count compare registers for timer D. */ +#define V850E_TIMER_D_CMD_ADDR(n) (V850E_TIMER_D_CMD_BASE_ADDR + 0x10 * (n)) +#define V850E_TIMER_D_CMD(n) (*(volatile u16 *)V850E_TIMER_D_CMD_ADDR(n)) + +/* Control registers for timer D. */ +#define V850E_TIMER_D_TMCD_ADDR(n) (V850E_TIMER_D_TMCD_BASE_ADDR + 0x10 * (n)) +#define V850E_TIMER_D_TMCD(n) (*(volatile u8 *)V850E_TIMER_D_TMCD_ADDR(n)) +/* Control bits for timer D. */ +#define V850E_TIMER_D_TMCD_CE 0x2 /* count enable */ +#define V850E_TIMER_D_TMCD_CAE 0x1 /* clock action enable */ +/* Clock divider setting (log2). */ +#define V850E_TIMER_D_TMCD_CS(divlog2) (((divlog2) - V850E_TIMER_D_TMCD_CS_MIN) << 4) +/* Minimum clock divider setting (log2). */ +#ifndef V850E_TIMER_D_TMCD_CS_MIN /* Can be overridden by mach-specific hdrs */ +#define V850E_TIMER_D_TMCD_CS_MIN 2 /* Default is correct for the v850e/ma1 */ +#endif +/* Maximum clock divider setting (log2). */ +#define V850E_TIMER_D_TMCD_CS_MAX (V850E_TIMER_D_TMCD_CS_MIN + 7) + +/* Return the clock-divider (log2) of timer D unit N. */ +#define V850E_TIMER_D_DIVLOG2(n) \ + (((V850E_TIMER_D_TMCD(n) >> 4) & 0x7) + V850E_TIMER_D_TMCD_CS_MIN) + + +#ifndef __ASSEMBLY__ + +/* Start interval timer TIMER (0-3). The timer will issue the + corresponding INTCMD interrupt RATE times per second. This function + does not enable the interrupt. */ +extern void v850e_timer_d_configure (unsigned timer, unsigned rate); + +#endif /* !__ASSEMBLY__ */ + + +#endif /* __V850_V850E_TIMER_D_H__ */ diff --git a/include/asm-v850/v850e_utils.h b/include/asm-v850/v850e_utils.h new file mode 100644 index 000000000000..52eb72822d3d --- /dev/null +++ b/include/asm-v850/v850e_utils.h @@ -0,0 +1,35 @@ +/* + * include/asm-v850/v850e_utils.h -- Utility functions associated with + * V850E CPUs + * + * Copyright (C) 2001,03 NEC Electronics Corporation + * Copyright (C) 2001,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#ifndef __V850_V850E_UTILS_H__ +#define __V850_V850E_UTILS_H__ + +/* Calculate counter clock-divider and count values to attain the + desired frequency RATE from the base frequency BASE_FREQ. The + counter is expected to have a clock-divider, which can divide the + system cpu clock by a power of two value from MIN_DIVLOG2 to + MAX_DIV_LOG2, and a word-size of COUNTER_SIZE bits (the counter + counts up and resets whenever it's equal to the compare register, + generating an interrupt or whatever when it does so). The returned + values are: *DIVLOG2 -- log2 of the desired clock divider and *COUNT + -- the counter compare value to use. Returns true if it was possible + to find a reasonable value, otherwise false (and the other return + values will be set to be as good as possible). */ +extern int calc_counter_params (unsigned long base_freq, + unsigned long rate, + unsigned min_divlog2, unsigned max_divlog2, + unsigned counter_size, + unsigned *divlog2, unsigned *count); + +#endif /* __V850_V850E_UTILS_H__ */ -- cgit v1.2.3 From 701096cf9b0b69c4167d9010b964da2c013e2c20 Mon Sep 17 00:00:00 2001 From: Miles Bader Date: Thu, 17 Jul 2003 20:10:48 -0700 Subject: [PATCH] Refactor v850 UART driver The v850 family contains several related-but-not-identical on-chip UARTs. This patch factors out the common code and uses it to implement both types (only one was supported before). Also, this patch changes the way the v850 UART is initialized, to use the same method as other linux serial drivers. This patch renames the UART code to be `v850e_uart' rather than `nb85e_uart', as the former is more correct. As this change renames some files too, the patch contains a number of whole-file add/removes. --- arch/v850/kernel/anna.c | 4 - arch/v850/kernel/as85ep1.c | 4 - arch/v850/kernel/rte_cb.c | 14 +- drivers/serial/Kconfig | 19 +- drivers/serial/Makefile | 2 +- drivers/serial/nb85e_uart.c | 610 ---------------------------------------- drivers/serial/v850e_uart.c | 549 ++++++++++++++++++++++++++++++++++++ include/asm-v850/anna.h | 15 +- include/asm-v850/as85ep1.h | 12 +- include/asm-v850/ma.h | 4 +- include/asm-v850/ma1.h | 7 +- include/asm-v850/nb85e_uart.h | 144 ---------- include/asm-v850/rte_ma1_cb.h | 8 +- include/asm-v850/rte_nb85e_cb.h | 8 +- include/asm-v850/teg.h | 22 +- include/asm-v850/v850e_uart.h | 77 +++++ include/asm-v850/v850e_uarta.h | 278 ++++++++++++++++++ include/asm-v850/v850e_uartb.h | 262 +++++++++++++++++ include/linux/serial_core.h | 2 +- 19 files changed, 1220 insertions(+), 821 deletions(-) delete mode 100644 drivers/serial/nb85e_uart.c create mode 100644 drivers/serial/v850e_uart.c delete mode 100644 include/asm-v850/nb85e_uart.h create mode 100644 include/asm-v850/v850e_uart.h create mode 100644 include/asm-v850/v850e_uarta.h create mode 100644 include/asm-v850/v850e_uartb.h (limited to 'include') diff --git a/arch/v850/kernel/anna.c b/arch/v850/kernel/anna.c index b47c42dc4175..c6590eab99cb 100644 --- a/arch/v850/kernel/anna.c +++ b/arch/v850/kernel/anna.c @@ -63,10 +63,6 @@ void __init mach_early_init (void) void __init mach_setup (char **cmdline) { -#ifdef CONFIG_V850E_NB85E_UART_CONSOLE - nb85e_uart_cons_init (1); -#endif - ANNA_PORT_PM (LEDS_PORT) = 0; /* Make all LED pins output pins. */ mach_tick = anna_led_tick; } diff --git a/arch/v850/kernel/as85ep1.c b/arch/v850/kernel/as85ep1.c index 9699d76acbbb..94ea12259f3e 100644 --- a/arch/v850/kernel/as85ep1.c +++ b/arch/v850/kernel/as85ep1.c @@ -95,10 +95,6 @@ void __init mach_early_init (void) void __init mach_setup (char **cmdline) { -#ifdef CONFIG_V850E_NB85E_UART_CONSOLE - nb85e_uart_cons_init (1); -#endif - AS85EP1_PORT_PMC (LEDS_PORT) = 0; /* Make the LEDs port an I/O port. */ AS85EP1_PORT_PM (LEDS_PORT) = 0; /* Make all the bits output pins. */ mach_tick = as85ep1_led_tick; diff --git a/arch/v850/kernel/rte_cb.c b/arch/v850/kernel/rte_cb.c index cdc819886ae6..45c1b1197c1b 100644 --- a/arch/v850/kernel/rte_cb.c +++ b/arch/v850/kernel/rte_cb.c @@ -53,23 +53,11 @@ void __init mach_setup (char **cmdline) " NEC SolutionGear/Midas lab" " RTE-MOTHER-A motherboard\n"); } - -#if defined (CONFIG_V850E_NB85E_UART_CONSOLE) && !defined (CONFIG_TIME_BOOTUP) - nb85e_uart_cons_init (0); -#endif +#endif /* CONFIG_RTE_MB_A_PCI */ mach_tick = led_tick; } -#ifdef CONFIG_TIME_BOOTUP -void initial_boot_done (void) -{ -#ifdef CONFIG_V850E_NB85E_UART_CONSOLE - nb85e_uart_cons_init (0); -#endif -} -#endif - void machine_restart (char *__unused) { #ifdef CONFIG_RESET_GUARD diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 94b36c3a01c8..cae6bc1239ec 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -404,14 +404,19 @@ config SERIAL_SUNSAB_CONSOLE on your Sparc system as the console, you can do so by answering Y to this option. -config V850E_NB85E_UART +config V850E_UART bool "NEC V850E on-chip UART support" - depends on V850E_NB85E || V850E2_ANNA || V850E_AS85EP1 + depends on V850E_MA1 || V850E_ME2 || V850E_TEG || V850E2_ANNA || V850E_AS85EP1 default y -config V850E_NB85E_UART_CONSOLE +config V850E_UARTB + bool + depends V850E_UART && V850E_ME2 + default y + +config V850E_UART_CONSOLE bool "Use NEC V850E on-chip UART for console" - depends on V850E_NB85E_UART + depends on V850E_UART config SERIAL98 tristate "PC-9800 8251-based primary serial port support" @@ -426,12 +431,12 @@ config SERIAL98_CONSOLE config SERIAL_CORE tristate - default m if SERIAL_AMBA!=y && SERIAL_CLPS711X!=y && SERIAL_21285!=y && !SERIAL_SA1100 && !SERIAL_ANAKIN && !SERIAL_UART00 && SERIAL_8250!=y && SERIAL_MUX!=y && !SERIAL_ROCKETPORT && !SERIAL_SUNCORE && !V850E_NB85E_UART && (SERIAL_AMBA=m || SERIAL_CLPS711X=m || SERIAL_21285=m || SERIAL_8250=m || SERIAL_MUX=m || SERIAL98=m) - default y if SERIAL_AMBA=y || SERIAL_CLPS711X=y || SERIAL_21285=y || SERIAL_SA1100 || SERIAL_ANAKIN || SERIAL_UART00 || SERIAL_8250=y || SERIAL_MUX=y || SERIAL_ROCKETPORT || SERIAL_SUNCORE || V850E_NB85E_UART || SERIAL98=y + default m if SERIAL_AMBA!=y && SERIAL_CLPS711X!=y && SERIAL_21285!=y && !SERIAL_SA1100 && !SERIAL_ANAKIN && !SERIAL_UART00 && SERIAL_8250!=y && SERIAL_MUX!=y && !SERIAL_ROCKETPORT && !SERIAL_SUNCORE && !V850E_UART && (SERIAL_AMBA=m || SERIAL_CLPS711X=m || SERIAL_21285=m || SERIAL_8250=m || SERIAL_MUX=m || SERIAL98=m) + default y if SERIAL_AMBA=y || SERIAL_CLPS711X=y || SERIAL_21285=y || SERIAL_SA1100 || SERIAL_ANAKIN || SERIAL_UART00 || SERIAL_8250=y || SERIAL_MUX=y || SERIAL_ROCKETPORT || SERIAL_SUNCORE || V850E_UART || SERIAL98=y config SERIAL_CORE_CONSOLE bool - depends on SERIAL_AMBA_CONSOLE || SERIAL_CLPS711X_CONSOLE || SERIAL_21285_CONSOLE || SERIAL_SA1100_CONSOLE || SERIAL_ANAKIN_CONSOLE || SERIAL_UART00_CONSOLE || SERIAL_8250_CONSOLE || SERIAL_MUX_CONSOLE || SERIAL_SUNZILOG_CONSOLE || SERIAL_SUNSU_CONSOLE || SERIAL_SUNSAB_CONSOLE || V850E_NB85E_UART_CONSOLE || SERIAL98_CONSOLE + depends on SERIAL_AMBA_CONSOLE || SERIAL_CLPS711X_CONSOLE || SERIAL_21285_CONSOLE || SERIAL_SA1100_CONSOLE || SERIAL_ANAKIN_CONSOLE || SERIAL_UART00_CONSOLE || SERIAL_8250_CONSOLE || SERIAL_MUX_CONSOLE || SERIAL_SUNZILOG_CONSOLE || SERIAL_SUNSU_CONSOLE || SERIAL_SUNSAB_CONSOLE || V850E_UART_CONSOLE || SERIAL98_CONSOLE default y config SERIAL_68328 diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 13a7dc306853..c6e1fba4a2ad 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -29,5 +29,5 @@ obj-$(CONFIG_SERIAL_MUX) += mux.o obj-$(CONFIG_SERIAL_68328) += 68328serial.o obj-$(CONFIG_SERIAL_68360) += 68360serial.o obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o -obj-$(CONFIG_V850E_NB85E_UART) += nb85e_uart.o +obj-$(CONFIG_V850E_UART) += v850e_uart.o obj-$(CONFIG_SERIAL98) += serial98.o diff --git a/drivers/serial/nb85e_uart.c b/drivers/serial/nb85e_uart.c deleted file mode 100644 index 883be05241df..000000000000 --- a/drivers/serial/nb85e_uart.c +++ /dev/null @@ -1,610 +0,0 @@ -/* - * drivers/serial/nb85e_uart.c -- Serial I/O using V850E/NB85E on-chip UART - * - * Copyright (C) 2001,02,03 NEC Corporation - * Copyright (C) 2001,02,03 Miles Bader - * - * 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. - * - * Written by Miles Bader - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* Initial UART state. This may be overridden by machine-dependent headers. */ -#ifndef NB85E_UART_INIT_BAUD -#define NB85E_UART_INIT_BAUD 115200 -#endif -#ifndef NB85E_UART_INIT_CFLAGS -#define NB85E_UART_INIT_CFLAGS (B115200 | CS8 | CREAD) -#endif - -/* XXX This should be in a header file. */ -#define NB85E_UART_BRGC_MIN 8 - -/* A string used for prefixing printed descriptions; since the same UART - macro is actually used on other chips than the V850E/NB85E. This must - be a constant string. */ -#ifndef NB85E_UART_CHIP_NAME -#define NB85E_UART_CHIP_NAME "V850E/NB85E" -#endif - - -/* Helper functions for doing baud-rate/frequency calculations. */ - -/* Calculate the minimum value for CKSR on this processor. */ -static inline unsigned cksr_min (void) -{ - int min = 0; - unsigned freq = NB85E_UART_BASE_FREQ; - while (freq > NB85E_UART_CKSR_MAX_FREQ) { - freq >>= 1; - min++; - } - return min; -} - -/* Minimum baud rate possible. */ -#define min_baud() \ - ((NB85E_UART_BASE_FREQ >> NB85E_UART_CKSR_MAX) / (2 * 255) + 1) - -/* Maximum baud rate possible. The error is quite high at max, though. */ -#define max_baud() \ - ((NB85E_UART_BASE_FREQ >> cksr_min()) / (2 * NB85E_UART_BRGC_MIN)) - - -/* Low-level UART functions. */ - -/* These masks define which control bits affect TX/RX modes, respectively. */ -#define RX_BITS \ - (NB85E_UART_ASIM_PS_MASK | NB85E_UART_ASIM_CL_8 | NB85E_UART_ASIM_ISRM) -#define TX_BITS \ - (NB85E_UART_ASIM_PS_MASK | NB85E_UART_ASIM_CL_8 | NB85E_UART_ASIM_SL_2) - -/* The UART require various delays after writing control registers. */ -static inline void nb85e_uart_delay (unsigned cycles) -{ - /* The loop takes 2 insns, so loop CYCLES / 2 times. */ - register unsigned count = cycles >> 1; - while (--count != 0) - /* nothing */; -} - -/* Configure and turn on uart channel CHAN, using the termios `control - modes' bits in CFLAGS, and a baud-rate of BAUD. */ -void nb85e_uart_configure (unsigned chan, unsigned cflags, unsigned baud) -{ - int flags; - unsigned new_config = 0; /* What we'll write to the control reg. */ - unsigned new_clk_divlog2; /* New baud-rate generate clock divider. */ - unsigned new_brgen_count; /* New counter max for baud-rate generator.*/ - /* These are the current values corresponding to the above. */ - unsigned old_config, old_clk_divlog2, old_brgen_count; - - /* Calculate new baud-rate generator config values. */ - - /* Calculate the log2 clock divider and baud-rate counter values - (note that the UART divides the resulting clock by 2, so - multiply BAUD by 2 here to compensate). */ - calc_counter_params (NB85E_UART_BASE_FREQ, baud * 2, - cksr_min(), NB85E_UART_CKSR_MAX, 8/*bits*/, - &new_clk_divlog2, &new_brgen_count); - - /* Figure out new configuration of control register. */ - if (cflags & CSTOPB) - /* Number of stop bits, 1 or 2. */ - new_config |= NB85E_UART_ASIM_SL_2; - if ((cflags & CSIZE) == CS8) - /* Number of data bits, 7 or 8. */ - new_config |= NB85E_UART_ASIM_CL_8; - if (! (cflags & PARENB)) - /* No parity check/generation. */ - new_config |= NB85E_UART_ASIM_PS_NONE; - else if (cflags & PARODD) - /* Odd parity check/generation. */ - new_config |= NB85E_UART_ASIM_PS_ODD; - else - /* Even parity check/generation. */ - new_config |= NB85E_UART_ASIM_PS_EVEN; - if (cflags & CREAD) - /* Reading enabled. */ - new_config |= NB85E_UART_ASIM_RXE; - - new_config |= NB85E_UART_ASIM_TXE; /* Writing is always enabled. */ - new_config |= NB85E_UART_ASIM_CAE; - new_config |= NB85E_UART_ASIM_ISRM; /* Errors generate a read-irq. */ - - /* Disable interrupts while we're twiddling the hardware. */ - local_irq_save (flags); - -#ifdef NB85E_UART_PRE_CONFIGURE - NB85E_UART_PRE_CONFIGURE (chan, cflags, baud); -#endif - - old_config = NB85E_UART_ASIM (chan); - old_clk_divlog2 = NB85E_UART_CKSR (chan); - old_brgen_count = NB85E_UART_BRGC (chan); - - if (new_clk_divlog2 != old_clk_divlog2 - || new_brgen_count != old_brgen_count) - { - /* The baud rate has changed. First, disable the UART. */ - NB85E_UART_ASIM (chan) = 0; - old_config = 0; - /* Reprogram the baud-rate generator. */ - NB85E_UART_CKSR (chan) = new_clk_divlog2; - NB85E_UART_BRGC (chan) = new_brgen_count; - } - - if (! (old_config & NB85E_UART_ASIM_CAE)) { - /* If we are enabling the uart for the first time, start - by turning on the enable bit, which must be done - before turning on any other bits. */ - NB85E_UART_ASIM (chan) = NB85E_UART_ASIM_CAE; - /* Enabling the uart also resets it. */ - old_config = NB85E_UART_ASIM_CAE; - } - - if (new_config != old_config) { - /* Which of the TXE/RXE bits we'll temporarily turn off - before changing other control bits. */ - unsigned temp_disable = 0; - /* Which of the TXE/RXE bits will be enabled. */ - unsigned enable = 0; - unsigned changed_bits = new_config ^ old_config; - - /* Which of RX/TX will be enabled in the new configuration. */ - if (new_config & RX_BITS) - enable |= (new_config & NB85E_UART_ASIM_RXE); - if (new_config & TX_BITS) - enable |= (new_config & NB85E_UART_ASIM_TXE); - - /* Figure out which of RX/TX needs to be disabled; note - that this will only happen if they're not already - disabled. */ - if (changed_bits & RX_BITS) - temp_disable |= (old_config & NB85E_UART_ASIM_RXE); - if (changed_bits & TX_BITS) - temp_disable |= (old_config & NB85E_UART_ASIM_TXE); - - /* We have to turn off RX and/or TX mode before changing - any associated control bits. */ - if (temp_disable) - NB85E_UART_ASIM (chan) = old_config & ~temp_disable; - - /* Write the new control bits, while RX/TX are disabled. */ - if (changed_bits & ~enable) - NB85E_UART_ASIM (chan) = new_config & ~enable; - - /* The UART may not be reset properly unless we - wait at least 2 `basic-clocks' until turning - on the TXE/RXE bits again. A `basic clock' - is the clock used by the baud-rate generator, i.e., - the cpu clock divided by the 2^new_clk_divlog2. */ - nb85e_uart_delay (1 << (new_clk_divlog2 + 1)); - - /* Write the final version, with enable bits turned on. */ - NB85E_UART_ASIM (chan) = new_config; - } - - local_irq_restore (flags); -} - - -/* Low-level console. */ - -#ifdef CONFIG_V850E_NB85E_UART_CONSOLE - -static void nb85e_uart_cons_write (struct console *co, - const char *s, unsigned count) -{ - if (count > 0) { - unsigned chan = co->index; - unsigned irq = IRQ_INTST (chan); - int irq_was_enabled, irq_was_pending, flags; - - /* We don't want to get `transmission completed' (INTST) - interrupts, since we're busy-waiting, so we disable - them while sending (we don't disable interrupts - entirely because sending over a serial line is really - slow). We save the status of INTST and restore it - when we're done so that using printk doesn't - interfere with normal serial transmission (other than - interleaving the output, of course!). This should - work correctly even if this function is interrupted - and the interrupt printks something. */ - - /* Disable interrupts while fiddling with INTST. */ - local_irq_save (flags); - /* Get current INTST status. */ - irq_was_enabled = nb85e_intc_irq_enabled (irq); - irq_was_pending = nb85e_intc_irq_pending (irq); - /* Disable INTST if necessary. */ - if (irq_was_enabled) - nb85e_intc_disable_irq (irq); - /* Turn interrupts back on. */ - local_irq_restore (flags); - - /* Send characters. */ - while (count > 0) { - int ch = *s++; - - if (ch == '\n') { - /* We don't have the benefit of a tty - driver, so translate NL into CR LF. */ - nb85e_uart_wait_for_xmit_ok (chan); - nb85e_uart_putc (chan, '\r'); - } - - nb85e_uart_wait_for_xmit_ok (chan); - nb85e_uart_putc (chan, ch); - - count--; - } - - /* Restore saved INTST status. */ - if (irq_was_enabled) { - /* Wait for the last character we sent to be - completely transmitted (as we'll get an INTST - interrupt at that point). */ - nb85e_uart_wait_for_xmit_done (chan); - /* Clear pending interrupts received due - to our transmission, unless there was already - one pending, in which case we want the - handler to be called. */ - if (! irq_was_pending) - nb85e_intc_clear_pending_irq (irq); - /* ... and then turn back on handling. */ - nb85e_intc_enable_irq (irq); - } - } -} - -extern struct uart_driver nb85e_uart_driver; -static struct console nb85e_uart_cons = -{ - .name = "ttyS", - .write = nb85e_uart_cons_write, - .device = uart_console_device, - .flags = CON_PRINTBUFFER, - .cflag = NB85E_UART_INIT_CFLAGS, - .index = -1, - .data = &nb85e_uart_driver, -}; - -void nb85e_uart_cons_init (unsigned chan) -{ - nb85e_uart_configure (chan, NB85E_UART_INIT_CFLAGS, - NB85E_UART_INIT_BAUD); - nb85e_uart_cons.index = chan; - register_console (&nb85e_uart_cons); - printk ("Console: %s on-chip UART channel %d\n", - NB85E_UART_CHIP_NAME, chan); -} - -#define NB85E_UART_CONSOLE &nb85e_uart_cons - -#else /* !CONFIG_V850E_NB85E_UART_CONSOLE */ -#define NB85E_UART_CONSOLE 0 -#endif /* CONFIG_V850E_NB85E_UART_CONSOLE */ - -/* TX/RX interrupt handlers. */ - -static void nb85e_uart_stop_tx (struct uart_port *port, unsigned tty_stop); - -void nb85e_uart_tx (struct uart_port *port) -{ - struct circ_buf *xmit = &port->info->xmit; - int stopped = uart_tx_stopped (port); - - if (nb85e_uart_xmit_ok (port->line)) { - int tx_ch; - - if (port->x_char) { - tx_ch = port->x_char; - port->x_char = 0; - } else if (!uart_circ_empty (xmit) && !stopped) { - tx_ch = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } else - goto no_xmit; - - nb85e_uart_putc (port->line, tx_ch); - port->icount.tx++; - - if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS) - uart_write_wakeup (port); - } - - no_xmit: - if (uart_circ_empty (xmit) || stopped) - nb85e_uart_stop_tx (port, stopped); -} - -static void nb85e_uart_tx_irq (int irq, void *data, struct pt_regs *regs) -{ - struct uart_port *port = data; - nb85e_uart_tx (port); -} - -static void nb85e_uart_rx_irq (int irq, void *data, struct pt_regs *regs) -{ - struct uart_port *port = data; - unsigned ch_stat = TTY_NORMAL; - unsigned ch = NB85E_UART_RXB (port->line); - unsigned err = NB85E_UART_ASIS (port->line); - - if (err) { - if (err & NB85E_UART_ASIS_OVE) { - ch_stat = TTY_OVERRUN; - port->icount.overrun++; - } else if (err & NB85E_UART_ASIS_FE) { - ch_stat = TTY_FRAME; - port->icount.frame++; - } else if (err & NB85E_UART_ASIS_PE) { - ch_stat = TTY_PARITY; - port->icount.parity++; - } - } - - port->icount.rx++; - - tty_insert_flip_char (port->info->tty, ch, ch_stat); - tty_schedule_flip (port->info->tty); -} - -/* Control functions for the serial framework. */ - -static void nb85e_uart_nop (struct uart_port *port) { } -static int nb85e_uart_success (struct uart_port *port) { return 0; } - -static unsigned nb85e_uart_tx_empty (struct uart_port *port) -{ - return TIOCSER_TEMT; /* Can't detect. */ -} - -static void nb85e_uart_set_mctrl (struct uart_port *port, unsigned mctrl) -{ -#ifdef NB85E_UART_SET_RTS - NB85E_UART_SET_RTS (port->line, (mctrl & TIOCM_RTS)); -#endif -} - -static unsigned nb85e_uart_get_mctrl (struct uart_port *port) -{ - /* We don't support DCD or DSR, so consider them permanently active. */ - int mctrl = TIOCM_CAR | TIOCM_DSR; - - /* We may support CTS. */ -#ifdef NB85E_UART_CTS - mctrl |= NB85E_UART_CTS(port->line) ? TIOCM_CTS : 0; -#else - mctrl |= TIOCM_CTS; -#endif - - return mctrl; -} - -static void nb85e_uart_start_tx (struct uart_port *port, unsigned tty_start) -{ - nb85e_intc_disable_irq (IRQ_INTST (port->line)); - nb85e_uart_tx (port); - nb85e_intc_enable_irq (IRQ_INTST (port->line)); -} - -static void nb85e_uart_stop_tx (struct uart_port *port, unsigned tty_stop) -{ - nb85e_intc_disable_irq (IRQ_INTST (port->line)); -} - -static void nb85e_uart_start_rx (struct uart_port *port) -{ - nb85e_intc_enable_irq (IRQ_INTSR (port->line)); -} - -static void nb85e_uart_stop_rx (struct uart_port *port) -{ - nb85e_intc_disable_irq (IRQ_INTSR (port->line)); -} - -static void nb85e_uart_break_ctl (struct uart_port *port, int break_ctl) -{ - /* Umm, do this later. */ -} - -static int nb85e_uart_startup (struct uart_port *port) -{ - int err; - - /* Alloc RX irq. */ - err = request_irq (IRQ_INTSR (port->line), nb85e_uart_rx_irq, - SA_INTERRUPT, "nb85e_uart", port); - if (err) - return err; - - /* Alloc TX irq. */ - err = request_irq (IRQ_INTST (port->line), nb85e_uart_tx_irq, - SA_INTERRUPT, "nb85e_uart", port); - if (err) { - free_irq (IRQ_INTSR (port->line), port); - return err; - } - - nb85e_uart_start_rx (port); - - return 0; -} - -static void nb85e_uart_shutdown (struct uart_port *port) -{ - /* Disable port interrupts. */ - free_irq (IRQ_INTST (port->line), port); - free_irq (IRQ_INTSR (port->line), port); - - /* Turn off xmit/recv enable bits. */ - NB85E_UART_ASIM (port->line) - &= ~(NB85E_UART_ASIM_TXE | NB85E_UART_ASIM_RXE); - /* Then reset the channel. */ - NB85E_UART_ASIM (port->line) = 0; -} - -static void -nb85e_uart_set_termios (struct uart_port *port, struct termios *termios, - struct termios *old) -{ - unsigned cflags = termios->c_cflag; - - /* Restrict flags to legal values. */ - if ((cflags & CSIZE) != CS7 && (cflags & CSIZE) != CS8) - /* The new value of CSIZE is invalid, use the old value. */ - cflags = (cflags & ~CSIZE) - | (old ? (old->c_cflag & CSIZE) : CS8); - - termios->c_cflag = cflags; - - nb85e_uart_configure (port->line, cflags, - uart_get_baud_rate (port, termios, old, - min_baud(), max_baud())); -} - -static const char *nb85e_uart_type (struct uart_port *port) -{ - return port->type == PORT_NB85E_UART ? "nb85e_uart" : 0; -} - -static void nb85e_uart_config_port (struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) - port->type = PORT_NB85E_UART; -} - -static int -nb85e_uart_verify_port (struct uart_port *port, struct serial_struct *ser) -{ - if (ser->type != PORT_UNKNOWN && ser->type != PORT_NB85E_UART) - return -EINVAL; - if (ser->irq != IRQ_INTST (port->line)) - return -EINVAL; - return 0; -} - -static struct uart_ops nb85e_uart_ops = { - .tx_empty = nb85e_uart_tx_empty, - .get_mctrl = nb85e_uart_get_mctrl, - .set_mctrl = nb85e_uart_set_mctrl, - .start_tx = nb85e_uart_start_tx, - .stop_tx = nb85e_uart_stop_tx, - .stop_rx = nb85e_uart_stop_rx, - .enable_ms = nb85e_uart_nop, - .break_ctl = nb85e_uart_break_ctl, - .startup = nb85e_uart_startup, - .shutdown = nb85e_uart_shutdown, - .set_termios = nb85e_uart_set_termios, - .type = nb85e_uart_type, - .release_port = nb85e_uart_nop, - .request_port = nb85e_uart_success, - .config_port = nb85e_uart_config_port, - .verify_port = nb85e_uart_verify_port, -}; - -/* Initialization and cleanup. */ - -static struct uart_driver nb85e_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "nb85e_uart", - .devfs_name = "tts/", - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = NB85E_UART_MINOR_BASE, - .nr = NB85E_UART_NUM_CHANNELS, - .cons = NB85E_UART_CONSOLE, -}; - - -static struct uart_port nb85e_uart_ports[NB85E_UART_NUM_CHANNELS]; - -static int __init nb85e_uart_init (void) -{ - int rval; - - printk (KERN_INFO "%s on-chip UART\n", NB85E_UART_CHIP_NAME); - - rval = uart_register_driver (&nb85e_uart_driver); - if (rval == 0) { - unsigned chan; - - for (chan = 0; chan < NB85E_UART_NUM_CHANNELS; chan++) { - struct uart_port *port = &nb85e_uart_ports[chan]; - - memset (port, 0, sizeof *port); - - port->ops = &nb85e_uart_ops; - port->line = chan; - port->iotype = SERIAL_IO_MEM; - port->flags = UPF_BOOT_AUTOCONF; - - /* We actually use multiple IRQs, but the serial - framework seems to mainly use this for - informational purposes anyway. Here we use the TX - irq. */ - port->irq = IRQ_INTST (chan); - - /* The serial framework doesn't really use these - membase/mapbase fields for anything useful, but - it requires that they be something non-zero to - consider the port `valid', and also uses them - for informational purposes. */ - port->membase = (void *)NB85E_UART_BASE_ADDR (chan); - port->mapbase = NB85E_UART_BASE_ADDR (chan); - - /* The framework insists on knowing the uart's master - clock freq, though it doesn't seem to do anything - useful for us with it. We must make it at least - higher than (the maximum baud rate * 16), otherwise - the framework will puke during its internal - calculations, and force the baud rate to be 9600. - To be accurate though, just repeat the calculation - we use when actually setting the speed. - - The `* 8' means `* 16 / 2': 16 to account for for - the serial framework's built-in bias, and 2 because - there's an additional / 2 in the hardware. */ - port->uartclk = - (NB85E_UART_BASE_FREQ >> cksr_min()) * 8; - - uart_add_one_port (&nb85e_uart_driver, port); - } - } - - return rval; -} - -static void __exit nb85e_uart_exit (void) -{ - unsigned chan; - - for (chan = 0; chan < NB85E_UART_NUM_CHANNELS; chan++) - uart_remove_one_port (&nb85e_uart_driver, - &nb85e_uart_ports[chan]); - - uart_unregister_driver (&nb85e_uart_driver); -} - -module_init (nb85e_uart_init); -module_exit (nb85e_uart_exit); - -MODULE_AUTHOR ("Miles Bader"); -MODULE_DESCRIPTION ("NEC " NB85E_UART_CHIP_NAME " on-chip UART"); -MODULE_LICENSE ("GPL"); diff --git a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c new file mode 100644 index 000000000000..bb482780a41d --- /dev/null +++ b/drivers/serial/v850e_uart.c @@ -0,0 +1,549 @@ +/* + * drivers/serial/v850e_uart.c -- Serial I/O using V850E on-chip UART or UARTB + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +/* This driver supports both the original V850E UART interface (called + merely `UART' in the docs) and the newer `UARTB' interface, which is + roughly a superset of the first one. The selection is made at + configure time -- if CONFIG_V850E_UARTB is defined, then UARTB is + presumed, otherwise the old UART -- as these are on-CPU UARTS, a system + can never have both. + + The UARTB interface also has a 16-entry FIFO mode, which is not + yet supported by this driver. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Initial UART state. This may be overridden by machine-dependent headers. */ +#ifndef V850E_UART_INIT_BAUD +#define V850E_UART_INIT_BAUD 115200 +#endif +#ifndef V850E_UART_INIT_CFLAGS +#define V850E_UART_INIT_CFLAGS (B115200 | CS8 | CREAD) +#endif + +/* A string used for prefixing printed descriptions; since the same UART + macro is actually used on other chips than the V850E. This must be a + constant string. */ +#ifndef V850E_UART_CHIP_NAME +#define V850E_UART_CHIP_NAME "V850E" +#endif + +#define V850E_UART_MINOR_BASE 64 /* First tty minor number */ + + +/* Low-level UART functions. */ + +/* Configure and turn on uart channel CHAN, using the termios `control + modes' bits in CFLAGS, and a baud-rate of BAUD. */ +void v850e_uart_configure (unsigned chan, unsigned cflags, unsigned baud) +{ + int flags; + v850e_uart_speed_t old_speed; + v850e_uart_config_t old_config; + v850e_uart_speed_t new_speed = v850e_uart_calc_speed (baud); + v850e_uart_config_t new_config = v850e_uart_calc_config (cflags); + + /* Disable interrupts while we're twiddling the hardware. */ + local_irq_save (flags); + +#ifdef V850E_UART_PRE_CONFIGURE + V850E_UART_PRE_CONFIGURE (chan, cflags, baud); +#endif + + old_config = V850E_UART_CONFIG (chan); + old_speed = v850e_uart_speed (chan); + + if (! v850e_uart_speed_eq (old_speed, new_speed)) { + /* The baud rate has changed. First, disable the UART. */ + V850E_UART_CONFIG (chan) = V850E_UART_CONFIG_FINI; + old_config = 0; /* Force the uart to be re-initialized. */ + + /* Reprogram the baud-rate generator. */ + v850e_uart_set_speed (chan, new_speed); + } + + if (! (old_config & V850E_UART_CONFIG_ENABLED)) { + /* If we are using the uart for the first time, start by + enabling it, which must be done before turning on any + other bits. */ + V850E_UART_CONFIG (chan) = V850E_UART_CONFIG_INIT; + /* See the initial state. */ + old_config = V850E_UART_CONFIG (chan); + } + + if (new_config != old_config) { + /* Which of the TXE/RXE bits we'll temporarily turn off + before changing other control bits. */ + unsigned temp_disable = 0; + /* Which of the TXE/RXE bits will be enabled. */ + unsigned enable = 0; + unsigned changed_bits = new_config ^ old_config; + + /* Which of RX/TX will be enabled in the new configuration. */ + if (new_config & V850E_UART_CONFIG_RX_BITS) + enable |= (new_config & V850E_UART_CONFIG_RX_ENABLE); + if (new_config & V850E_UART_CONFIG_TX_BITS) + enable |= (new_config & V850E_UART_CONFIG_TX_ENABLE); + + /* Figure out which of RX/TX needs to be disabled; note + that this will only happen if they're not already + disabled. */ + if (changed_bits & V850E_UART_CONFIG_RX_BITS) + temp_disable + |= (old_config & V850E_UART_CONFIG_RX_ENABLE); + if (changed_bits & V850E_UART_CONFIG_TX_BITS) + temp_disable + |= (old_config & V850E_UART_CONFIG_TX_ENABLE); + + /* We have to turn off RX and/or TX mode before changing + any associated control bits. */ + if (temp_disable) + V850E_UART_CONFIG (chan) = old_config & ~temp_disable; + + /* Write the new control bits, while RX/TX are disabled. */ + if (changed_bits & ~enable) + V850E_UART_CONFIG (chan) = new_config & ~enable; + + v850e_uart_config_delay (new_config, new_speed); + + /* Write the final version, with enable bits turned on. */ + V850E_UART_CONFIG (chan) = new_config; + } + + local_irq_restore (flags); +} + + +/* Low-level console. */ + +#ifdef CONFIG_V850E_UART_CONSOLE + +static void v850e_uart_cons_write (struct console *co, + const char *s, unsigned count) +{ + if (count > 0) { + unsigned chan = co->index; + unsigned irq = V850E_UART_TX_IRQ (chan); + int irq_was_enabled, irq_was_pending, flags; + + /* We don't want to get `transmission completed' + interrupts, since we're busy-waiting, so we disable them + while sending (we don't disable interrupts entirely + because sending over a serial line is really slow). We + save the status of the tx interrupt and restore it when + we're done so that using printk doesn't interfere with + normal serial transmission (other than interleaving the + output, of course!). This should work correctly even if + this function is interrupted and the interrupt printks + something. */ + + /* Disable interrupts while fiddling with tx interrupt. */ + local_irq_save (flags); + /* Get current tx interrupt status. */ + irq_was_enabled = v850e_intc_irq_enabled (irq); + irq_was_pending = v850e_intc_irq_pending (irq); + /* Disable tx interrupt if necessary. */ + if (irq_was_enabled) + v850e_intc_disable_irq (irq); + /* Turn interrupts back on. */ + local_irq_restore (flags); + + /* Send characters. */ + while (count > 0) { + int ch = *s++; + + if (ch == '\n') { + /* We don't have the benefit of a tty + driver, so translate NL into CR LF. */ + v850e_uart_wait_for_xmit_ok (chan); + v850e_uart_putc (chan, '\r'); + } + + v850e_uart_wait_for_xmit_ok (chan); + v850e_uart_putc (chan, ch); + + count--; + } + + /* Restore saved tx interrupt status. */ + if (irq_was_enabled) { + /* Wait for the last character we sent to be + completely transmitted (as we'll get an + interrupt interrupt at that point). */ + v850e_uart_wait_for_xmit_done (chan); + /* Clear pending interrupts received due + to our transmission, unless there was already + one pending, in which case we want the + handler to be called. */ + if (! irq_was_pending) + v850e_intc_clear_pending_irq (irq); + /* ... and then turn back on handling. */ + v850e_intc_enable_irq (irq); + } + } +} + +extern struct uart_driver v850e_uart_driver; +static struct console v850e_uart_cons = +{ + .name = "ttyS", + .write = v850e_uart_cons_write, + .device = uart_console_device, + .flags = CON_PRINTBUFFER, + .cflag = V850E_UART_INIT_CFLAGS, + .index = -1, + .data = &v850e_uart_driver, +}; + +void v850e_uart_cons_init (unsigned chan) +{ + v850e_uart_configure (chan, V850E_UART_INIT_CFLAGS, + V850E_UART_INIT_BAUD); + v850e_uart_cons.index = chan; + register_console (&v850e_uart_cons); + printk ("Console: %s on-chip UART channel %d\n", + V850E_UART_CHIP_NAME, chan); +} + +/* This is what the init code actually calls. */ +static int v850e_uart_console_init (void) +{ + v850e_uart_cons_init (V850E_UART_CONSOLE_CHANNEL); + return 0; +} +console_initcall(v850e_uart_console_init); + +#define V850E_UART_CONSOLE &v850e_uart_cons + +#else /* !CONFIG_V850E_UART_CONSOLE */ +#define V850E_UART_CONSOLE 0 +#endif /* CONFIG_V850E_UART_CONSOLE */ + +/* TX/RX interrupt handlers. */ + +static void v850e_uart_stop_tx (struct uart_port *port, unsigned tty_stop); + +void v850e_uart_tx (struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + int stopped = uart_tx_stopped (port); + + if (v850e_uart_xmit_ok (port->line)) { + int tx_ch; + + if (port->x_char) { + tx_ch = port->x_char; + port->x_char = 0; + } else if (!uart_circ_empty (xmit) && !stopped) { + tx_ch = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + } else + goto no_xmit; + + v850e_uart_putc (port->line, tx_ch); + port->icount.tx++; + + if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS) + uart_write_wakeup (port); + } + + no_xmit: + if (uart_circ_empty (xmit) || stopped) + v850e_uart_stop_tx (port, stopped); +} + +static irqreturn_t v850e_uart_tx_irq(int irq, void *data, struct pt_regs *regs) +{ + struct uart_port *port = data; + v850e_uart_tx (port); + return IRQ_HANDLED; +} + +static irqreturn_t v850e_uart_rx_irq(int irq, void *data, struct pt_regs *regs) +{ + struct uart_port *port = data; + unsigned ch_stat = TTY_NORMAL; + unsigned ch = v850e_uart_getc (port->line); + unsigned err = v850e_uart_err (port->line); + + if (err) { + if (err & V850E_UART_ERR_OVERRUN) { + ch_stat = TTY_OVERRUN; + port->icount.overrun++; + } else if (err & V850E_UART_ERR_FRAME) { + ch_stat = TTY_FRAME; + port->icount.frame++; + } else if (err & V850E_UART_ERR_PARITY) { + ch_stat = TTY_PARITY; + port->icount.parity++; + } + } + + port->icount.rx++; + + tty_insert_flip_char (port->info->tty, ch, ch_stat); + tty_schedule_flip (port->info->tty); + + return IRQ_HANDLED; +} + + +/* Control functions for the serial framework. */ + +static void v850e_uart_nop (struct uart_port *port) { } +static int v850e_uart_success (struct uart_port *port) { return 0; } + +static unsigned v850e_uart_tx_empty (struct uart_port *port) +{ + return TIOCSER_TEMT; /* Can't detect. */ +} + +static void v850e_uart_set_mctrl (struct uart_port *port, unsigned mctrl) +{ +#ifdef V850E_UART_SET_RTS + V850E_UART_SET_RTS (port->line, (mctrl & TIOCM_RTS)); +#endif +} + +static unsigned v850e_uart_get_mctrl (struct uart_port *port) +{ + /* We don't support DCD or DSR, so consider them permanently active. */ + int mctrl = TIOCM_CAR | TIOCM_DSR; + + /* We may support CTS. */ +#ifdef V850E_UART_CTS + mctrl |= V850E_UART_CTS(port->line) ? TIOCM_CTS : 0; +#else + mctrl |= TIOCM_CTS; +#endif + + return mctrl; +} + +static void v850e_uart_start_tx (struct uart_port *port, unsigned tty_start) +{ + v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line)); + v850e_uart_tx (port); + v850e_intc_enable_irq (V850E_UART_TX_IRQ (port->line)); +} + +static void v850e_uart_stop_tx (struct uart_port *port, unsigned tty_stop) +{ + v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line)); +} + +static void v850e_uart_start_rx (struct uart_port *port) +{ + v850e_intc_enable_irq (V850E_UART_RX_IRQ (port->line)); +} + +static void v850e_uart_stop_rx (struct uart_port *port) +{ + v850e_intc_disable_irq (V850E_UART_RX_IRQ (port->line)); +} + +static void v850e_uart_break_ctl (struct uart_port *port, int break_ctl) +{ + /* Umm, do this later. */ +} + +static int v850e_uart_startup (struct uart_port *port) +{ + int err; + + /* Alloc RX irq. */ + err = request_irq (V850E_UART_RX_IRQ (port->line), v850e_uart_rx_irq, + SA_INTERRUPT, "v850e_uart", port); + if (err) + return err; + + /* Alloc TX irq. */ + err = request_irq (V850E_UART_TX_IRQ (port->line), v850e_uart_tx_irq, + SA_INTERRUPT, "v850e_uart", port); + if (err) { + free_irq (V850E_UART_RX_IRQ (port->line), port); + return err; + } + + v850e_uart_start_rx (port); + + return 0; +} + +static void v850e_uart_shutdown (struct uart_port *port) +{ + /* Disable port interrupts. */ + free_irq (V850E_UART_TX_IRQ (port->line), port); + free_irq (V850E_UART_RX_IRQ (port->line), port); + + /* Turn off xmit/recv enable bits. */ + V850E_UART_CONFIG (port->line) + &= ~(V850E_UART_CONFIG_TX_ENABLE + | V850E_UART_CONFIG_RX_ENABLE); + /* Then reset the channel. */ + V850E_UART_CONFIG (port->line) = 0; +} + +static void +v850e_uart_set_termios (struct uart_port *port, struct termios *termios, + struct termios *old) +{ + unsigned cflags = termios->c_cflag; + + /* Restrict flags to legal values. */ + if ((cflags & CSIZE) != CS7 && (cflags & CSIZE) != CS8) + /* The new value of CSIZE is invalid, use the old value. */ + cflags = (cflags & ~CSIZE) + | (old ? (old->c_cflag & CSIZE) : CS8); + + termios->c_cflag = cflags; + + v850e_uart_configure (port->line, cflags, + uart_get_baud_rate (port, termios, old, + v850e_uart_min_baud(), + v850e_uart_max_baud())); +} + +static const char *v850e_uart_type (struct uart_port *port) +{ + return port->type == PORT_V850E_UART ? "v850e_uart" : 0; +} + +static void v850e_uart_config_port (struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_V850E_UART; +} + +static int +v850e_uart_verify_port (struct uart_port *port, struct serial_struct *ser) +{ + if (ser->type != PORT_UNKNOWN && ser->type != PORT_V850E_UART) + return -EINVAL; + if (ser->irq != V850E_UART_TX_IRQ (port->line)) + return -EINVAL; + return 0; +} + +static struct uart_ops v850e_uart_ops = { + .tx_empty = v850e_uart_tx_empty, + .get_mctrl = v850e_uart_get_mctrl, + .set_mctrl = v850e_uart_set_mctrl, + .start_tx = v850e_uart_start_tx, + .stop_tx = v850e_uart_stop_tx, + .stop_rx = v850e_uart_stop_rx, + .enable_ms = v850e_uart_nop, + .break_ctl = v850e_uart_break_ctl, + .startup = v850e_uart_startup, + .shutdown = v850e_uart_shutdown, + .set_termios = v850e_uart_set_termios, + .type = v850e_uart_type, + .release_port = v850e_uart_nop, + .request_port = v850e_uart_success, + .config_port = v850e_uart_config_port, + .verify_port = v850e_uart_verify_port, +}; + +/* Initialization and cleanup. */ + +static struct uart_driver v850e_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "v850e_uart", + .devfs_name = "tts/", + .dev_name = "ttyS", + .major = TTY_MAJOR, + .minor = V850E_UART_MINOR_BASE, + .nr = V850E_UART_NUM_CHANNELS, + .cons = V850E_UART_CONSOLE, +}; + + +static struct uart_port v850e_uart_ports[V850E_UART_NUM_CHANNELS]; + +static int __init v850e_uart_init (void) +{ + int rval; + + printk (KERN_INFO "%s on-chip UART\n", V850E_UART_CHIP_NAME); + + rval = uart_register_driver (&v850e_uart_driver); + if (rval == 0) { + unsigned chan; + + for (chan = 0; chan < V850E_UART_NUM_CHANNELS; chan++) { + struct uart_port *port = &v850e_uart_ports[chan]; + + memset (port, 0, sizeof *port); + + port->ops = &v850e_uart_ops; + port->line = chan; + port->iotype = SERIAL_IO_MEM; + port->flags = UPF_BOOT_AUTOCONF; + + /* We actually use multiple IRQs, but the serial + framework seems to mainly use this for + informational purposes anyway. Here we use the TX + irq. */ + port->irq = V850E_UART_TX_IRQ (chan); + + /* The serial framework doesn't really use these + membase/mapbase fields for anything useful, but + it requires that they be something non-zero to + consider the port `valid', and also uses them + for informational purposes. */ + port->membase = (void *)V850E_UART_BASE_ADDR (chan); + port->mapbase = V850E_UART_BASE_ADDR (chan); + + /* The framework insists on knowing the uart's master + clock freq, though it doesn't seem to do anything + useful for us with it. We must make it at least + higher than (the maximum baud rate * 16), otherwise + the framework will puke during its internal + calculations, and force the baud rate to be 9600. + To be accurate though, just repeat the calculation + we use when actually setting the speed. */ + port->uartclk = v850e_uart_max_clock() * 16; + + uart_add_one_port (&v850e_uart_driver, port); + } + } + + return rval; +} + +static void __exit v850e_uart_exit (void) +{ + unsigned chan; + + for (chan = 0; chan < V850E_UART_NUM_CHANNELS; chan++) + uart_remove_one_port (&v850e_uart_driver, + &v850e_uart_ports[chan]); + + uart_unregister_driver (&v850e_uart_driver); +} + +module_init (v850e_uart_init); +module_exit (v850e_uart_exit); + +MODULE_AUTHOR ("Miles Bader"); +MODULE_DESCRIPTION ("NEC " V850E_UART_CHIP_NAME " on-chip UART"); +MODULE_LICENSE ("GPL"); diff --git a/include/asm-v850/anna.h b/include/asm-v850/anna.h index 44d261afa82a..1bb65a29c0b0 100644 --- a/include/asm-v850/anna.h +++ b/include/asm-v850/anna.h @@ -116,12 +116,15 @@ extern void anna_init_irqs (void); /* Anna UART details (basically the same as the V850E/MA1, but 2 channels). */ -#define NB85E_UART_NUM_CHANNELS 2 -#define NB85E_UART_BASE_FREQ (SYS_CLOCK_FREQ / 2) -#define NB85E_UART_CHIP_NAME "V850E2/NA85E2A" +#define V850E_UART_NUM_CHANNELS 2 +#define V850E_UART_BASE_FREQ (SYS_CLOCK_FREQ / 2) +#define V850E_UART_CHIP_NAME "V850E2/NA85E2A" + +/* This is the UART channel that's actually connected on the board. */ +#define V850E_UART_CONSOLE_CHANNEL 1 /* This is a function that gets called before configuring the UART. */ -#define NB85E_UART_PRE_CONFIGURE anna_uart_pre_configure +#define V850E_UART_PRE_CONFIGURE anna_uart_pre_configure #ifndef __ASSEMBLY__ extern void anna_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud); @@ -130,9 +133,9 @@ extern void anna_uart_pre_configure (unsigned chan, /* This board supports RTS/CTS for the on-chip UART, but only for channel 1. */ /* CTS for UART channel 1 is pin P37 (bit 7 of port 3). */ -#define NB85E_UART_CTS(chan) ((chan) == 1 ? !(ANNA_PORT_IO(3) & 0x80) : 1) +#define V850E_UART_CTS(chan) ((chan) == 1 ? !(ANNA_PORT_IO(3) & 0x80) : 1) /* RTS for UART channel 1 is pin P07 (bit 7 of port 0). */ -#define NB85E_UART_SET_RTS(chan, val) \ +#define V850E_UART_SET_RTS(chan, val) \ do { \ if (chan == 1) { \ unsigned old = ANNA_PORT_IO(0); \ diff --git a/include/asm-v850/as85ep1.h b/include/asm-v850/as85ep1.h index 707d40da101a..ceeb5f09f703 100644 --- a/include/asm-v850/as85ep1.h +++ b/include/asm-v850/as85ep1.h @@ -110,12 +110,12 @@ extern void as85ep1_init_irqs (void); /* AS85EP1 UART details (basically the same as the V850E/MA1, but 2 channels). */ -#define NB85E_UART_NUM_CHANNELS 2 -#define NB85E_UART_BASE_FREQ (SYS_CLOCK_FREQ / 4) -#define NB85E_UART_CHIP_NAME "V850E/NA85E" +#define V850E_UART_NUM_CHANNELS 2 +#define V850E_UART_BASE_FREQ (SYS_CLOCK_FREQ / 4) +#define V850E_UART_CHIP_NAME "V850E/NA85E" /* This is a function that gets called before configuring the UART. */ -#define NB85E_UART_PRE_CONFIGURE as85ep1_uart_pre_configure +#define V850E_UART_PRE_CONFIGURE as85ep1_uart_pre_configure #ifndef __ASSEMBLY__ extern void as85ep1_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud); @@ -124,9 +124,9 @@ extern void as85ep1_uart_pre_configure (unsigned chan, /* This board supports RTS/CTS for the on-chip UART, but only for channel 1. */ /* CTS for UART channel 1 is pin P54 (bit 4 of port 5). */ -#define NB85E_UART_CTS(chan) ((chan) == 1 ? !(AS85EP1_PORT_IO(5) & 0x10) : 1) +#define V850E_UART_CTS(chan) ((chan) == 1 ? !(AS85EP1_PORT_IO(5) & 0x10) : 1) /* RTS for UART channel 1 is pin P53 (bit 3 of port 5). */ -#define NB85E_UART_SET_RTS(chan, val) \ +#define V850E_UART_SET_RTS(chan, val) \ do { \ if (chan == 1) { \ unsigned old = AS85EP1_PORT_IO(5); \ diff --git a/include/asm-v850/ma.h b/include/asm-v850/ma.h index 991a9c343ef1..89e66473a176 100644 --- a/include/asm-v850/ma.h +++ b/include/asm-v850/ma.h @@ -27,10 +27,10 @@ /* MA series UART details. */ -#define NB85E_UART_BASE_FREQ CPU_CLOCK_FREQ +#define V850E_UART_BASE_FREQ CPU_CLOCK_FREQ /* This is a function that gets called before configuring the UART. */ -#define NB85E_UART_PRE_CONFIGURE ma_uart_pre_configure +#define V850E_UART_PRE_CONFIGURE ma_uart_pre_configure #ifndef __ASSEMBLY__ extern void ma_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud); diff --git a/include/asm-v850/ma1.h b/include/asm-v850/ma1.h index 034eea17a02f..ede1f1de2b7a 100644 --- a/include/asm-v850/ma1.h +++ b/include/asm-v850/ma1.h @@ -1,8 +1,8 @@ /* * include/asm-v850/ma1.h -- V850E/MA1 cpu chip * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader * * 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 @@ -40,12 +40,11 @@ #define IRQ_INTST(n) (0x27 + (n)*4) /* UART 0-2 transmission completion */ #define IRQ_INTST_NUM 3 -/* For */ #define NUM_CPU_IRQS 0x30 /* The MA1 has a UART with 3 channels. */ -#define NB85E_UART_NUM_CHANNELS 3 +#define V850E_UART_NUM_CHANNELS 3 #endif /* __V850_MA1_H__ */ diff --git a/include/asm-v850/nb85e_uart.h b/include/asm-v850/nb85e_uart.h deleted file mode 100644 index ac8e8b1375fe..000000000000 --- a/include/asm-v850/nb85e_uart.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * include/asm-v850/nb85e_uart.h -- On-chip UART often used with the - * NB85E cpu core - * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader - * - * 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. - * - * Written by Miles Bader - */ - -/* There's not actually a single UART implementation used by nb85e - derivatives, but rather a series of implementations that are all - `close' to one another. This file attempts to capture some - commonality between them. */ - -#ifndef __V850_NB85E_UART_H__ -#define __V850_NB85E_UART_H__ - -#include -#include /* Pick up chip-specific defs. */ - - -/* The base address of the UART control registers for channel N. - The default is the address used on the V850E/MA1. */ -#ifndef NB85E_UART_BASE_ADDR -#define NB85E_UART_BASE_ADDR(n) (0xFFFFFA00 + 0x10 * (n)) -#endif - -/* Addresses of specific UART control registers for channel N. - The defaults are the addresses used on the V850E/MA1; if a platform - wants to redefine any of these, it must redefine them all. */ -#ifndef NB85E_UART_ASIM_ADDR -#define NB85E_UART_ASIM_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x0) -#define NB85E_UART_RXB_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x2) -#define NB85E_UART_ASIS_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x3) -#define NB85E_UART_TXB_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x4) -#define NB85E_UART_ASIF_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x5) -#define NB85E_UART_CKSR_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x6) -#define NB85E_UART_BRGC_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x7) -#endif - -#ifndef NB85E_UART_CKSR_MAX_FREQ -#define NB85E_UART_CKSR_MAX_FREQ (25*1000*1000) -#endif - -/* UART config registers. */ -#define NB85E_UART_ASIM(n) (*(volatile u8 *)NB85E_UART_ASIM_ADDR(n)) -/* Control bits for config registers. */ -#define NB85E_UART_ASIM_CAE 0x80 /* clock enable */ -#define NB85E_UART_ASIM_TXE 0x40 /* transmit enable */ -#define NB85E_UART_ASIM_RXE 0x20 /* receive enable */ -#define NB85E_UART_ASIM_PS_MASK 0x18 /* mask covering parity-select bits */ -#define NB85E_UART_ASIM_PS_NONE 0x00 /* no parity */ -#define NB85E_UART_ASIM_PS_ZERO 0x08 /* zero parity */ -#define NB85E_UART_ASIM_PS_ODD 0x10 /* odd parity */ -#define NB85E_UART_ASIM_PS_EVEN 0x18 /* even parity */ -#define NB85E_UART_ASIM_CL_8 0x04 /* char len is 8 bits (otherwise, 7) */ -#define NB85E_UART_ASIM_SL_2 0x02 /* 2 stop bits (otherwise, 1) */ -#define NB85E_UART_ASIM_ISRM 0x01 /* generate INTSR interrupt on errors - (otherwise, generate INTSER) */ - -/* UART serial interface status registers. */ -#define NB85E_UART_ASIS(n) (*(volatile u8 *)NB85E_UART_ASIS_ADDR(n)) -/* Control bits for status registers. */ -#define NB85E_UART_ASIS_PE 0x04 /* parity error */ -#define NB85E_UART_ASIS_FE 0x02 /* framing error */ -#define NB85E_UART_ASIS_OVE 0x01 /* overrun error */ - -/* UART serial interface transmission status registers. */ -#define NB85E_UART_ASIF(n) (*(volatile u8 *)NB85E_UART_ASIF_ADDR(n)) -#define NB85E_UART_ASIF_TXBF 0x02 /* transmit buffer flag (data in TXB) */ -#define NB85E_UART_ASIF_TXSF 0x01 /* transmit shift flag (sending data) */ - -/* UART receive buffer register. */ -#define NB85E_UART_RXB(n) (*(volatile u8 *)NB85E_UART_RXB_ADDR(n)) - -/* UART transmit buffer register. */ -#define NB85E_UART_TXB(n) (*(volatile u8 *)NB85E_UART_TXB_ADDR(n)) - -/* UART baud-rate generator control registers. */ -#define NB85E_UART_CKSR(n) (*(volatile u8 *)NB85E_UART_CKSR_ADDR(n)) -#define NB85E_UART_CKSR_MAX 11 -#define NB85E_UART_BRGC(n) (*(volatile u8 *)NB85E_UART_BRGC_ADDR(n)) - - -/* This UART doesn't implement RTS/CTS by default, but some platforms - implement them externally, so check to see if defined - anything. */ -#ifdef NB85E_UART_CTS -#define nb85e_uart_cts(n) NB85E_UART_CTS(n) -#else -#define nb85e_uart_cts(n) (1) -#endif - -/* Do the same for RTS. */ -#ifdef NB85E_UART_SET_RTS -#define nb85e_uart_set_rts(n,v) NB85E_UART_SET_RTS(n,v) -#else -#define nb85e_uart_set_rts(n,v) ((void)0) -#endif - -/* Return true if all characters awaiting transmission on uart channel N - have been transmitted. */ -#define nb85e_uart_xmit_done(n) \ - (! (NB85E_UART_ASIF(n) & NB85E_UART_ASIF_TXBF)) -/* Wait for this to be true. */ -#define nb85e_uart_wait_for_xmit_done(n) \ - do { } while (! nb85e_uart_xmit_done (n)) - -/* Return true if uart channel N is ready to transmit a character. */ -#define nb85e_uart_xmit_ok(n) \ - (nb85e_uart_xmit_done(n) && nb85e_uart_cts(n)) -/* Wait for this to be true. */ -#define nb85e_uart_wait_for_xmit_ok(n) \ - do { } while (! nb85e_uart_xmit_ok (n)) - -/* Write character CH to uart channel N. */ -#define nb85e_uart_putc(n, ch) (NB85E_UART_TXB(n) = (ch)) - - -#define NB85E_UART_MINOR_BASE 64 - - -#ifndef __ASSEMBLY__ - -/* Setup a console using channel 0 of the builtin uart. */ -extern void nb85e_uart_cons_init (unsigned chan); - -/* Configure and turn on uart channel CHAN, using the termios `control - modes' bits in CFLAGS, and a baud-rate of BAUD. */ -void nb85e_uart_configure (unsigned chan, unsigned cflags, unsigned baud); - -/* If the macro NB85E_UART_PRE_CONFIGURE is defined (presumably by a - ), it is called from nb85e_uart_pre_configure before - anything else is done, with interrupts disabled. */ - -#endif /* !__ASSEMBLY__ */ - - -#endif /* __V850_NB85E_UART_H__ */ diff --git a/include/asm-v850/rte_ma1_cb.h b/include/asm-v850/rte_ma1_cb.h index c9e7fb89e34d..94c287bdbc70 100644 --- a/include/asm-v850/rte_ma1_cb.h +++ b/include/asm-v850/rte_ma1_cb.h @@ -98,8 +98,8 @@ /* Override the basic MA uart pre-initialization so that we can initialize extra stuff. */ -#undef NB85E_UART_PRE_CONFIGURE /* should be defined by */ -#define NB85E_UART_PRE_CONFIGURE rte_ma1_cb_uart_pre_configure +#undef V850E_UART_PRE_CONFIGURE /* should be defined by */ +#define V850E_UART_PRE_CONFIGURE rte_ma1_cb_uart_pre_configure #ifndef __ASSEMBLY__ extern void rte_ma1_cb_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud); @@ -108,9 +108,9 @@ extern void rte_ma1_cb_uart_pre_configure (unsigned chan, /* This board supports RTS/CTS for the on-chip UART, but only for channel 0. */ /* CTS for UART channel 0 is pin P43 (bit 3 of port 4). */ -#define NB85E_UART_CTS(chan) ((chan) == 0 ? !(MA_PORT4_IO & 0x8) : 1) +#define V850E_UART_CTS(chan) ((chan) == 0 ? !(MA_PORT4_IO & 0x8) : 1) /* RTS for UART channel 0 is pin P42 (bit 2 of port 4). */ -#define NB85E_UART_SET_RTS(chan, val) \ +#define V850E_UART_SET_RTS(chan, val) \ do { \ if (chan == 0) { \ unsigned old = MA_PORT4_IO; \ diff --git a/include/asm-v850/rte_nb85e_cb.h b/include/asm-v850/rte_nb85e_cb.h index 77aa72f8cc81..f56591cad90a 100644 --- a/include/asm-v850/rte_nb85e_cb.h +++ b/include/asm-v850/rte_nb85e_cb.h @@ -89,8 +89,8 @@ /* Override the basic TEG UART pre-initialization so that we can initialize extra stuff. */ -#undef NB85E_UART_PRE_CONFIGURE /* should be defined by */ -#define NB85E_UART_PRE_CONFIGURE rte_nb85e_cb_uart_pre_configure +#undef V850E_UART_PRE_CONFIGURE /* should be defined by */ +#define V850E_UART_PRE_CONFIGURE rte_nb85e_cb_uart_pre_configure #ifndef __ASSEMBLY__ extern void rte_nb85e_cb_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud); @@ -99,9 +99,9 @@ extern void rte_nb85e_cb_uart_pre_configure (unsigned chan, /* This board supports RTS/CTS for the on-chip UART. */ /* CTS is pin P00. */ -#define NB85E_UART_CTS(chan) (! (TEG_PORT0_IO & 0x1)) +#define V850E_UART_CTS(chan) (! (TEG_PORT0_IO & 0x1)) /* RTS is pin P02. */ -#define NB85E_UART_SET_RTS(chan, val) \ +#define V850E_UART_SET_RTS(chan, val) \ do { \ unsigned old = TEG_PORT0_IO; \ TEG_PORT0_IO = val ? (old & ~0x4) : (old | 0x4); \ diff --git a/include/asm-v850/teg.h b/include/asm-v850/teg.h index 0f641a4e6eb9..acc8c7d95329 100644 --- a/include/asm-v850/teg.h +++ b/include/asm-v850/teg.h @@ -51,18 +51,18 @@ /* TEG UART details. */ -#define NB85E_UART_BASE_ADDR(n) (0xFFFFF600 + 0x10 * (n)) -#define NB85E_UART_ASIM_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x0) -#define NB85E_UART_ASIS_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x2) -#define NB85E_UART_ASIF_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x4) -#define NB85E_UART_CKSR_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x6) -#define NB85E_UART_BRGC_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x8) -#define NB85E_UART_TXB_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0xA) -#define NB85E_UART_RXB_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0xC) -#define NB85E_UART_NUM_CHANNELS 1 -#define NB85E_UART_BASE_FREQ CPU_CLOCK_FREQ +#define V850E_UART_BASE_ADDR(n) (0xFFFFF600 + 0x10 * (n)) +#define V850E_UART_ASIM_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x0) +#define V850E_UART_ASIS_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x2) +#define V850E_UART_ASIF_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x4) +#define V850E_UART_CKSR_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x6) +#define V850E_UART_BRGC_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x8) +#define V850E_UART_TXB_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0xA) +#define V850E_UART_RXB_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0xC) +#define V850E_UART_NUM_CHANNELS 1 +#define V850E_UART_BASE_FREQ CPU_CLOCK_FREQ /* This is a function that gets called before configuring the UART. */ -#define NB85E_UART_PRE_CONFIGURE teg_uart_pre_configure +#define V850E_UART_PRE_CONFIGURE teg_uart_pre_configure #ifndef __ASSEMBLY__ extern void teg_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud); diff --git a/include/asm-v850/v850e_uart.h b/include/asm-v850/v850e_uart.h new file mode 100644 index 000000000000..5930d5990b19 --- /dev/null +++ b/include/asm-v850/v850e_uart.h @@ -0,0 +1,77 @@ +/* + * include/asm-v850/v850e_uart.h -- common V850E on-chip UART driver + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +/* There's not actually a single UART implementation used by V850E CPUs, + but rather a series of implementations that are all `close' to one + another. This file corresponds to the single driver which handles all + of them. */ + +#ifndef __V850_V850E_UART_H__ +#define __V850_V850E_UART_H__ + +#include +#include + +#include +#include +#include /* Pick up chip-specific defs. */ + + +/* Include model-specific definitions. */ +#ifdef CONFIG_V850E_UART +# ifdef CONFIG_V850E_UARTB +# include +# else +# include /* original V850E UART */ +# endif +#endif + + +/* Optional capabilities some hardware provides. */ + +/* This UART doesn't implement RTS/CTS by default, but some platforms + implement them externally, so check to see if defined + anything. */ +#ifdef V850E_UART_CTS +#define v850e_uart_cts(n) V850E_UART_CTS(n) +#else +#define v850e_uart_cts(n) (1) +#endif + +/* Do the same for RTS. */ +#ifdef V850E_UART_SET_RTS +#define v850e_uart_set_rts(n,v) V850E_UART_SET_RTS(n,v) +#else +#define v850e_uart_set_rts(n,v) ((void)0) +#endif + + +/* This is the serial channel to use for the boot console (if desired). */ +#ifndef V850E_UART_CONSOLE_CHANNEL +# define V850E_UART_CONSOLE_CHANNEL 0 +#endif + + +#ifndef __ASSEMBLY__ + +/* Setup a console using channel 0 of the builtin uart. */ +extern void v850e_uart_cons_init (unsigned chan); + +/* Configure and turn on uart channel CHAN, using the termios `control + modes' bits in CFLAGS, and a baud-rate of BAUD. */ +void v850e_uart_configure (unsigned chan, unsigned cflags, unsigned baud); + +#endif /* !__ASSEMBLY__ */ + + +#endif /* __V850_V850E_UART_H__ */ diff --git a/include/asm-v850/v850e_uarta.h b/include/asm-v850/v850e_uarta.h new file mode 100644 index 000000000000..e483e0950725 --- /dev/null +++ b/include/asm-v850/v850e_uarta.h @@ -0,0 +1,278 @@ +/* + * include/asm-v850/v850e_uarta.h -- original V850E on-chip UART + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +/* This is the original V850E UART implementation is called just `UART' in + the docs, but we name this header file because the + name is used for the common driver that handles both + `UART' and `UARTB' implementations. */ + +#ifndef __V850_V850E_UARTA_H__ +#define __V850_V850E_UARTA_H__ + + +/* Raw hardware interface. */ + +/* The base address of the UART control registers for channel N. + The default is the address used on the V850E/MA1. */ +#ifndef V850E_UART_BASE_ADDR +#define V850E_UART_BASE_ADDR(n) (0xFFFFFA00 + 0x10 * (n)) +#endif + +/* Addresses of specific UART control registers for channel N. + The defaults are the addresses used on the V850E/MA1; if a platform + wants to redefine any of these, it must redefine them all. */ +#ifndef V850E_UART_ASIM_ADDR +#define V850E_UART_ASIM_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x0) +#define V850E_UART_RXB_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x2) +#define V850E_UART_ASIS_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x3) +#define V850E_UART_TXB_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x4) +#define V850E_UART_ASIF_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x5) +#define V850E_UART_CKSR_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x6) +#define V850E_UART_BRGC_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x7) +#endif + +/* UART config registers. */ +#define V850E_UART_ASIM(n) (*(volatile u8 *)V850E_UART_ASIM_ADDR(n)) +/* Control bits for config registers. */ +#define V850E_UART_ASIM_CAE 0x80 /* clock enable */ +#define V850E_UART_ASIM_TXE 0x40 /* transmit enable */ +#define V850E_UART_ASIM_RXE 0x20 /* receive enable */ +#define V850E_UART_ASIM_PS_MASK 0x18 /* mask covering parity-select bits */ +#define V850E_UART_ASIM_PS_NONE 0x00 /* no parity */ +#define V850E_UART_ASIM_PS_ZERO 0x08 /* zero parity */ +#define V850E_UART_ASIM_PS_ODD 0x10 /* odd parity */ +#define V850E_UART_ASIM_PS_EVEN 0x18 /* even parity */ +#define V850E_UART_ASIM_CL_8 0x04 /* char len is 8 bits (otherwise, 7) */ +#define V850E_UART_ASIM_SL_2 0x02 /* 2 stop bits (otherwise, 1) */ +#define V850E_UART_ASIM_ISRM 0x01 /* generate INTSR interrupt on errors + (otherwise, generate INTSER) */ + +/* UART serial interface status registers. */ +#define V850E_UART_ASIS(n) (*(volatile u8 *)V850E_UART_ASIS_ADDR(n)) +/* Control bits for status registers. */ +#define V850E_UART_ASIS_PE 0x04 /* parity error */ +#define V850E_UART_ASIS_FE 0x02 /* framing error */ +#define V850E_UART_ASIS_OVE 0x01 /* overrun error */ + +/* UART serial interface transmission status registers. */ +#define V850E_UART_ASIF(n) (*(volatile u8 *)V850E_UART_ASIF_ADDR(n)) +#define V850E_UART_ASIF_TXBF 0x02 /* transmit buffer flag (data in TXB) */ +#define V850E_UART_ASIF_TXSF 0x01 /* transmit shift flag (sending data) */ + +/* UART receive buffer register. */ +#define V850E_UART_RXB(n) (*(volatile u8 *)V850E_UART_RXB_ADDR(n)) + +/* UART transmit buffer register. */ +#define V850E_UART_TXB(n) (*(volatile u8 *)V850E_UART_TXB_ADDR(n)) + +/* UART baud-rate generator control registers. */ +#define V850E_UART_CKSR(n) (*(volatile u8 *)V850E_UART_CKSR_ADDR(n)) +#define V850E_UART_CKSR_MAX 11 +#define V850E_UART_BRGC(n) (*(volatile u8 *)V850E_UART_BRGC_ADDR(n)) +#define V850E_UART_BRGC_MIN 8 + + +#ifndef V850E_UART_CKSR_MAX_FREQ +#define V850E_UART_CKSR_MAX_FREQ (25*1000*1000) +#endif + +/* Calculate the minimum value for CKSR on this processor. */ +static inline unsigned v850e_uart_cksr_min (void) +{ + int min = 0; + unsigned freq = V850E_UART_BASE_FREQ; + while (freq > V850E_UART_CKSR_MAX_FREQ) { + freq >>= 1; + min++; + } + return min; +} + + +/* Slightly abstract interface used by driver. */ + + +/* Interrupts used by the UART. */ + +/* Received when the most recently transmitted character has been sent. */ +#define V850E_UART_TX_IRQ(chan) IRQ_INTST (chan) +/* Received when a new character has been received. */ +#define V850E_UART_RX_IRQ(chan) IRQ_INTSR (chan) + + +/* UART clock generator interface. */ + +/* This type encapsulates a particular uart frequency. */ +typedef struct { + unsigned clk_divlog2; + unsigned brgen_count; +} v850e_uart_speed_t; + +/* Calculate a uart speed from BAUD for this uart. */ +static inline v850e_uart_speed_t v850e_uart_calc_speed (unsigned baud) +{ + v850e_uart_speed_t speed; + + /* Calculate the log2 clock divider and baud-rate counter values + (note that the UART divides the resulting clock by 2, so + multiply BAUD by 2 here to compensate). */ + calc_counter_params (V850E_UART_BASE_FREQ, baud * 2, + v850e_uart_cksr_min(), + V850E_UART_CKSR_MAX, 8/*bits*/, + &speed.clk_divlog2, &speed.brgen_count); + + return speed; +} + +/* Return the current speed of uart channel CHAN. */ +static inline v850e_uart_speed_t v850e_uart_speed (unsigned chan) +{ + v850e_uart_speed_t speed; + speed.clk_divlog2 = V850E_UART_CKSR (chan); + speed.brgen_count = V850E_UART_BRGC (chan); + return speed; +} + +/* Set the current speed of uart channel CHAN. */ +static inline void v850e_uart_set_speed(unsigned chan,v850e_uart_speed_t speed) +{ + V850E_UART_CKSR (chan) = speed.clk_divlog2; + V850E_UART_BRGC (chan) = speed.brgen_count; +} + +static inline int +v850e_uart_speed_eq (v850e_uart_speed_t speed1, v850e_uart_speed_t speed2) +{ + return speed1.clk_divlog2 == speed2.clk_divlog2 + && speed1.brgen_count == speed2.brgen_count; +} + +/* Minimum baud rate possible. */ +#define v850e_uart_min_baud() \ + ((V850E_UART_BASE_FREQ >> V850E_UART_CKSR_MAX) / (2 * 255) + 1) + +/* Maximum baud rate possible. The error is quite high at max, though. */ +#define v850e_uart_max_baud() \ + ((V850E_UART_BASE_FREQ >> v850e_uart_cksr_min()) / (2 *V850E_UART_BRGC_MIN)) + +/* The `maximum' clock rate the uart can used, which is wanted (though not + really used in any useful way) by the serial framework. */ +#define v850e_uart_max_clock() \ + ((V850E_UART_BASE_FREQ >> v850e_uart_cksr_min()) / 2) + + +/* UART configuration interface. */ + +/* Type of the uart config register; must be a scalar. */ +typedef u16 v850e_uart_config_t; + +/* The uart hardware config register for channel CHAN. */ +#define V850E_UART_CONFIG(chan) V850E_UART_ASIM (chan) + +/* This config bit set if the uart is enabled. */ +#define V850E_UART_CONFIG_ENABLED V850E_UART_ASIM_CAE +/* If the uart _isn't_ enabled, store this value to it to do so. */ +#define V850E_UART_CONFIG_INIT V850E_UART_ASIM_CAE +/* Store this config value to disable the uart channel completely. */ +#define V850E_UART_CONFIG_FINI 0 + +/* Setting/clearing these bits enable/disable TX/RX, respectively (but + otherwise generally leave things running). */ +#define V850E_UART_CONFIG_RX_ENABLE V850E_UART_ASIM_RXE +#define V850E_UART_CONFIG_TX_ENABLE V850E_UART_ASIM_TXE + +/* These masks define which config bits affect TX/RX modes, respectively. */ +#define V850E_UART_CONFIG_RX_BITS \ + (V850E_UART_ASIM_PS_MASK | V850E_UART_ASIM_CL_8 | V850E_UART_ASIM_ISRM) +#define V850E_UART_CONFIG_TX_BITS \ + (V850E_UART_ASIM_PS_MASK | V850E_UART_ASIM_CL_8 | V850E_UART_ASIM_SL_2) + +static inline v850e_uart_config_t v850e_uart_calc_config (unsigned cflags) +{ + v850e_uart_config_t config = 0; + + /* Figure out new configuration of control register. */ + if (cflags & CSTOPB) + /* Number of stop bits, 1 or 2. */ + config |= V850E_UART_ASIM_SL_2; + if ((cflags & CSIZE) == CS8) + /* Number of data bits, 7 or 8. */ + config |= V850E_UART_ASIM_CL_8; + if (! (cflags & PARENB)) + /* No parity check/generation. */ + config |= V850E_UART_ASIM_PS_NONE; + else if (cflags & PARODD) + /* Odd parity check/generation. */ + config |= V850E_UART_ASIM_PS_ODD; + else + /* Even parity check/generation. */ + config |= V850E_UART_ASIM_PS_EVEN; + if (cflags & CREAD) + /* Reading enabled. */ + config |= V850E_UART_ASIM_RXE; + + config |= V850E_UART_ASIM_CAE; + config |= V850E_UART_ASIM_TXE; /* Writing is always enabled. */ + config |= V850E_UART_ASIM_ISRM; /* Errors generate a read-irq. */ + + return config; +} + +/* This should delay as long as necessary for a recently written config + setting to settle, before we turn the uart back on. */ +static inline void +v850e_uart_config_delay (v850e_uart_config_t config, v850e_uart_speed_t speed) +{ + /* The UART may not be reset properly unless we wait at least 2 + `basic-clocks' until turning on the TXE/RXE bits again. + A `basic clock' is the clock used by the baud-rate generator, + i.e., the cpu clock divided by the 2^new_clk_divlog2. + The loop takes 2 insns, so loop CYCLES / 2 times. */ + register unsigned count = 1 << speed.clk_divlog2; + while (--count != 0) + /* nothing */; +} + + +/* RX/TX interface. */ + +/* Return true if all characters awaiting transmission on uart channel N + have been transmitted. */ +#define v850e_uart_xmit_done(n) \ + (! (V850E_UART_ASIF(n) & V850E_UART_ASIF_TXBF)) +/* Wait for this to be true. */ +#define v850e_uart_wait_for_xmit_done(n) \ + do { } while (! v850e_uart_xmit_done (n)) + +/* Return true if uart channel N is ready to transmit a character. */ +#define v850e_uart_xmit_ok(n) \ + (v850e_uart_xmit_done(n) && v850e_uart_cts(n)) +/* Wait for this to be true. */ +#define v850e_uart_wait_for_xmit_ok(n) \ + do { } while (! v850e_uart_xmit_ok (n)) + +/* Write character CH to uart channel CHAN. */ +#define v850e_uart_putc(chan, ch) (V850E_UART_TXB(chan) = (ch)) + +/* Return latest character read on channel CHAN. */ +#define v850e_uart_getc(chan) V850E_UART_RXB (chan) + +/* Return bit-mask of uart error status. */ +#define v850e_uart_err(chan) V850E_UART_ASIS (chan) +/* Various error bits set in the error result. */ +#define V850E_UART_ERR_OVERRUN V850E_UART_ASIS_OVE +#define V850E_UART_ERR_FRAME V850E_UART_ASIS_FE +#define V850E_UART_ERR_PARITY V850E_UART_ASIS_PE + + +#endif /* __V850_V850E_UARTA_H__ */ diff --git a/include/asm-v850/v850e_uartb.h b/include/asm-v850/v850e_uartb.h new file mode 100644 index 000000000000..6d4767d5a835 --- /dev/null +++ b/include/asm-v850/v850e_uartb.h @@ -0,0 +1,262 @@ +/* + * include/asm-v850/v850e_uartb.h -- V850E on-chip `UARTB' UART + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +/* The V850E UARTB is basically a superset of the original V850E UART, but + even where it's the same, the names and details have changed a bit. + It's similar enough to use the same driver (v850e_uart.c), but the + details have been abstracted slightly to do so. */ + +#ifndef __V850_V850E_UARTB_H__ +#define __V850_V850E_UARTB_H__ + + +/* Raw hardware interface. */ + +#define V850E_UARTB_BASE_ADDR(n) (0xFFFFFA00 + 0x10 * (n)) + +/* Addresses of specific UART control registers for channel N. */ +#define V850E_UARTB_CTL0_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0x0) +#define V850E_UARTB_CTL2_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0x2) +#define V850E_UARTB_STR_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0x4) +#define V850E_UARTB_RX_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0x6) +#define V850E_UARTB_RXAP_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0x6) +#define V850E_UARTB_TX_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0x8) +#define V850E_UARTB_FIC0_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0xA) +#define V850E_UARTB_FIC1_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0xB) +#define V850E_UARTB_FIC2_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0xC) +#define V850E_UARTB_FIS0_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0xE) +#define V850E_UARTB_FIS1_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0xF) + +/* UARTB control register 0 (general config). */ +#define V850E_UARTB_CTL0(n) (*(volatile u8 *)V850E_UARTB_CTL0_ADDR(n)) +/* Control bits for config registers. */ +#define V850E_UARTB_CTL0_PWR 0x80 /* clock enable */ +#define V850E_UARTB_CTL0_TXE 0x40 /* transmit enable */ +#define V850E_UARTB_CTL0_RXE 0x20 /* receive enable */ +#define V850E_UARTB_CTL0_DIR 0x10 /* */ +#define V850E_UARTB_CTL0_PS1 0x08 /* parity */ +#define V850E_UARTB_CTL0_PS0 0x04 /* parity */ +#define V850E_UARTB_CTL0_CL 0x02 /* char len 1:8bit, 0:7bit */ +#define V850E_UARTB_CTL0_SL 0x01 /* stop bit 1:2bit, 0:1bit */ +#define V850E_UARTB_CTL0_PS_MASK 0x0C /* mask covering parity bits */ +#define V850E_UARTB_CTL0_PS_NONE 0x00 /* no parity */ +#define V850E_UARTB_CTL0_PS_ZERO 0x04 /* zero parity */ +#define V850E_UARTB_CTL0_PS_ODD 0x08 /* odd parity */ +#define V850E_UARTB_CTL0_PS_EVEN 0x0C /* even parity */ +#define V850E_UARTB_CTL0_CL_8 0x02 /* char len 1:8bit, 0:7bit */ +#define V850E_UARTB_CTL0_SL_2 0x01 /* stop bit 1:2bit, 0:1bit */ + +/* UARTB control register 2 (clock divider). */ +#define V850E_UARTB_CTL2(n) (*(volatile u16 *)V850E_UARTB_CTL2_ADDR(n)) +#define V850E_UARTB_CTL2_MIN 4 +#define V850E_UARTB_CTL2_MAX 0xFFFF + +/* UARTB serial interface status register. */ +#define V850E_UARTB_STR(n) (*(volatile u8 *)V850E_UARTB_STR_ADDR(n)) +/* Control bits for status registers. */ +#define V850E_UARTB_STR_TSF 0x80 /* UBTX or FIFO exist data */ +#define V850E_UARTB_STR_OVF 0x08 /* overflow error */ +#define V850E_UARTB_STR_PE 0x04 /* parity error */ +#define V850E_UARTB_STR_FE 0x02 /* framing error */ +#define V850E_UARTB_STR_OVE 0x01 /* overrun error */ + +/* UARTB receive data register. */ +#define V850E_UARTB_RX(n) (*(volatile u8 *)V850E_UARTB_RX_ADDR(n)) +#define V850E_UARTB_RXAP(n) (*(volatile u16 *)V850E_UARTB_RXAP_ADDR(n)) +/* Control bits for status registers. */ +#define V850E_UARTB_RXAP_PEF 0x0200 /* parity error */ +#define V850E_UARTB_RXAP_FEF 0x0100 /* framing error */ + +/* UARTB transmit data register. */ +#define V850E_UARTB_TX(n) (*(volatile u8 *)V850E_UARTB_TX_ADDR(n)) + +/* UARTB FIFO control register 0. */ +#define V850E_UARTB_FIC0(n) (*(volatile u8 *)V850E_UARTB_FIC0_ADDR(n)) + +/* UARTB FIFO control register 1. */ +#define V850E_UARTB_FIC1(n) (*(volatile u8 *)V850E_UARTB_FIC1_ADDR(n)) + +/* UARTB FIFO control register 2. */ +#define V850E_UARTB_FIC2(n) (*(volatile u16 *)V850E_UARTB_FIC2_ADDR(n)) + +/* UARTB FIFO status register 0. */ +#define V850E_UARTB_FIS0(n) (*(volatile u8 *)V850E_UARTB_FIS0_ADDR(n)) + +/* UARTB FIFO status register 1. */ +#define V850E_UARTB_FIS1(n) (*(volatile u8 *)V850E_UARTB_FIS1_ADDR(n)) + + +/* Slightly abstract interface used by driver. */ + + +/* Interrupts used by the UART. */ + +/* Received when the most recently transmitted character has been sent. */ +#define V850E_UART_TX_IRQ(chan) IRQ_INTUBTIT (chan) +/* Received when a new character has been received. */ +#define V850E_UART_RX_IRQ(chan) IRQ_INTUBTIR (chan) + +/* Use by serial driver for information purposes. */ +#define V850E_UART_BASE_ADDR(chan) V850E_UARTB_BASE_ADDR(chan) + + +/* UART clock generator interface. */ + +/* This type encapsulates a particular uart frequency. */ +typedef u16 v850e_uart_speed_t; + +/* Calculate a uart speed from BAUD for this uart. */ +static inline v850e_uart_speed_t v850e_uart_calc_speed (unsigned baud) +{ + v850e_uart_speed_t speed; + + /* + * V850E/ME2 UARTB baud rate is determined by the value of UBCTL2 + * fx = V850E_UARTB_BASE_FREQ = CPU_CLOCK_FREQ/4 + * baud = fx / 2*speed [ speed >= 4 ] + */ + speed = V850E_UARTB_CTL2_MIN; + while (((V850E_UARTB_BASE_FREQ / 2) / speed ) > baud) + speed++; + + return speed; +} + +/* Return the current speed of uart channel CHAN. */ +#define v850e_uart_speed(chan) V850E_UARTB_CTL2 (chan) + +/* Set the current speed of uart channel CHAN. */ +#define v850e_uart_set_speed(chan, speed) (V850E_UARTB_CTL2 (chan) = (speed)) + +/* Return true if SPEED1 and SPEED2 are the same. */ +#define v850e_uart_speed_eq(speed1, speed2) ((speed1) == (speed2)) + +/* Minimum baud rate possible. */ +#define v850e_uart_min_baud() \ + ((V850E_UARTB_BASE_FREQ / 2) / V850E_UARTB_CTL2_MAX) + +/* Maximum baud rate possible. The error is quite high at max, though. */ +#define v850e_uart_max_baud() \ + ((V850E_UARTB_BASE_FREQ / 2) / V850E_UARTB_CTL2_MIN) + +/* The `maximum' clock rate the uart can used, which is wanted (though not + really used in any useful way) by the serial framework. */ +#define v850e_uart_max_clock() \ + (V850E_UARTB_BASE_FREQ / 2) + + +/* UART configuration interface. */ + +/* Type of the uart config register; must be a scalar. */ +typedef u16 v850e_uart_config_t; + +/* The uart hardware config register for channel CHAN. */ +#define V850E_UART_CONFIG(chan) V850E_UARTB_CTL0 (chan) + +/* This config bit set if the uart is enabled. */ +#define V850E_UART_CONFIG_ENABLED V850E_UARTB_CTL0_PWR +/* If the uart _isn't_ enabled, store this value to it to do so. */ +#define V850E_UART_CONFIG_INIT V850E_UARTB_CTL0_PWR +/* Store this config value to disable the uart channel completely. */ +#define V850E_UART_CONFIG_FINI 0 + +/* Setting/clearing these bits enable/disable TX/RX, respectively (but + otherwise generally leave things running). */ +#define V850E_UART_CONFIG_RX_ENABLE V850E_UARTB_CTL0_RXE +#define V850E_UART_CONFIG_TX_ENABLE V850E_UARTB_CTL0_TXE + +/* These masks define which config bits affect TX/RX modes, respectively. */ +#define V850E_UART_CONFIG_RX_BITS \ + (V850E_UARTB_CTL0_PS_MASK | V850E_UARTB_CTL0_CL_8) +#define V850E_UART_CONFIG_TX_BITS \ + (V850E_UARTB_CTL0_PS_MASK | V850E_UARTB_CTL0_CL_8 | V850E_UARTB_CTL0_SL_2) + +static inline v850e_uart_config_t v850e_uart_calc_config (unsigned cflags) +{ + v850e_uart_config_t config = 0; + + /* Figure out new configuration of control register. */ + if (cflags & CSTOPB) + /* Number of stop bits, 1 or 2. */ + config |= V850E_UARTB_CTL0_SL_2; + if ((cflags & CSIZE) == CS8) + /* Number of data bits, 7 or 8. */ + config |= V850E_UARTB_CTL0_CL_8; + if (! (cflags & PARENB)) + /* No parity check/generation. */ + config |= V850E_UARTB_CTL0_PS_NONE; + else if (cflags & PARODD) + /* Odd parity check/generation. */ + config |= V850E_UARTB_CTL0_PS_ODD; + else + /* Even parity check/generation. */ + config |= V850E_UARTB_CTL0_PS_EVEN; + if (cflags & CREAD) + /* Reading enabled. */ + config |= V850E_UARTB_CTL0_RXE; + + config |= V850E_UARTB_CTL0_PWR; + config |= V850E_UARTB_CTL0_TXE; /* Writing is always enabled. */ + config |= V850E_UARTB_CTL0_DIR; /* LSB first. */ + + return config; +} + +/* This should delay as long as necessary for a recently written config + setting to settle, before we turn the uart back on. */ +static inline void +v850e_uart_config_delay (v850e_uart_config_t config, v850e_uart_speed_t speed) +{ + /* The UART may not be reset properly unless we wait at least 2 + `basic-clocks' until turning on the TXE/RXE bits again. + A `basic clock' is the clock used by the baud-rate generator, + i.e., the cpu clock divided by the 2^new_clk_divlog2. + The loop takes 2 insns, so loop CYCLES / 2 times. */ + register unsigned count = 1 << speed; + while (--count != 0) + /* nothing */; +} + + +/* RX/TX interface. */ + +/* Return true if all characters awaiting transmission on uart channel N + have been transmitted. */ +#define v850e_uart_xmit_done(n) \ + (! (V850E_UARTB_STR(n) & V850E_UARTB_STR_TSF)) +/* Wait for this to be true. */ +#define v850e_uart_wait_for_xmit_done(n) \ + do { } while (! v850e_uart_xmit_done (n)) + +/* Return true if uart channel N is ready to transmit a character. */ +#define v850e_uart_xmit_ok(n) \ + (v850e_uart_xmit_done(n) && v850e_uart_cts(n)) +/* Wait for this to be true. */ +#define v850e_uart_wait_for_xmit_ok(n) \ + do { } while (! v850e_uart_xmit_ok (n)) + +/* Write character CH to uart channel CHAN. */ +#define v850e_uart_putc(chan, ch) (V850E_UARTB_TX(chan) = (ch)) + +/* Return latest character read on channel CHAN. */ +#define v850e_uart_getc(chan) V850E_UARTB_RX (chan) + +/* Return bit-mask of uart error status. */ +#define v850e_uart_err(chan) V850E_UARTB_STR (chan) +/* Various error bits set in the error result. */ +#define V850E_UART_ERR_OVERRUN V850E_UARTB_STR_OVE +#define V850E_UART_ERR_FRAME V850E_UARTB_STR_FE +#define V850E_UART_ERR_PARITY V850E_UARTB_STR_PE + + +#endif /* __V850_V850E_UARTB_H__ */ diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 93ab5714ad94..a7cb796c4deb 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -57,7 +57,7 @@ #define PORT_SUNSAB 39 /* NEC v850. */ -#define PORT_NB85E_UART 40 +#define PORT_V850E_UART 40 /* NEC PC-9800 */ #define PORT_8251_PC98 41 -- cgit v1.2.3 From bf3cc1dd8e05a3bf0ce533839399cab8bab5e628 Mon Sep 17 00:00:00 2001 From: Miles Bader Date: Thu, 17 Jul 2003 20:11:09 -0700 Subject: [PATCH] Cleanup v850 cache-flushing code a bit (1) Add support for the V850E/ME2 processor (2) Clean up the cache-flushing function naming a bit (3) Similar to previous patches, rename everything from `nb85e' to `v850e'. This patch renames some files, and so contains a number of whole-file add/removes. --- arch/v850/kernel/nb85e_cache.c | 178 ----------------------------------------- arch/v850/kernel/v850e_cache.c | 173 +++++++++++++++++++++++++++++++++++++++ include/asm-v850/cacheflush.h | 33 ++++++-- include/asm-v850/nb85e_cache.h | 78 ------------------ include/asm-v850/v850e_cache.h | 48 +++++++++++ 5 files changed, 247 insertions(+), 263 deletions(-) delete mode 100644 arch/v850/kernel/nb85e_cache.c create mode 100644 arch/v850/kernel/v850e_cache.c delete mode 100644 include/asm-v850/nb85e_cache.h create mode 100644 include/asm-v850/v850e_cache.h (limited to 'include') diff --git a/arch/v850/kernel/nb85e_cache.c b/arch/v850/kernel/nb85e_cache.c deleted file mode 100644 index c7c35312b9a3..000000000000 --- a/arch/v850/kernel/nb85e_cache.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * arch/v850/kernel/nb85e_cache.c -- Cache control for NB85E_CACHE212 and - * NB85E_CACHE213 cache memories - * - * Copyright (C) 2003 NEC Electronics Corporation - * Copyright (C) 2003 Miles Bader - * - * 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. - * - * Written by Miles Bader - */ - -#include -#include - -#define WAIT_UNTIL_CLEAR(value) while (value) {} - -/* Set caching params via the BHC and DCC registers. */ -void nb85e_cache_enable (u16 bhc, u16 dcc) -{ - unsigned long *r0_ram = (unsigned long *)R0_RAM_ADDR; - register u16 bhc_val asm ("r6") = bhc; - - /* Configure data-cache. */ - NB85E_CACHE_DCC = dcc; - - /* Configure caching for various memory regions by writing the BHC - register. The documentation says that an instruction _cannot_ - enable/disable caching for the memory region in which the - instruction itself exists; to work around this, we store - appropriate instructions into the on-chip RAM area (which is never - cached), and briefly jump there to do the work. */ - r0_ram[0] = 0xf0720760; /* st.h r0, 0xfffff072[r0] */ - r0_ram[1] = 0xf06a3760; /* st.h r6, 0xfffff06a[r0] */ - r0_ram[2] = 0x5640006b; /* jmp [r11] */ - asm ("mov hilo(1f), r11; jmp [%1]; 1:;" - :: "r" (bhc_val), "r" (R0_RAM_ADDR) : "r11"); -} - -static void clear_icache (void) -{ - /* 1. Read the instruction cache control register (ICC) and confirm - that bits 0 and 1 (TCLR0, TCLR1) are all cleared. */ - WAIT_UNTIL_CLEAR (NB85E_CACHE_ICC & 0x3); - - /* 2. Read the ICC register and confirm that bit 12 (LOCK0) is - cleared. Bit 13 of the ICC register is always cleared. */ - WAIT_UNTIL_CLEAR (NB85E_CACHE_ICC & 0x1000); - - /* 3. Set the TCLR0 and TCLR1 bits of the ICC register as follows, - when clearing way 0 and way 1 at the same time: - (a) Set the TCLR0 and TCLR1 bits. - (b) Read the TCLR0 and TCLR1 bits to confirm that these bits - are cleared. - (c) Perform (a) and (b) above again. */ - NB85E_CACHE_ICC |= 0x3; - WAIT_UNTIL_CLEAR (NB85E_CACHE_ICC & 0x3); - /* Do it again. */ - NB85E_CACHE_ICC |= 0x3; - WAIT_UNTIL_CLEAR (NB85E_CACHE_ICC & 0x3); -} - -/* Flush or clear (or both) the data cache, depending on the value of FLAGS; - the procedure is the same for both, just the control bits used differ (and - both may be performed simultaneously). */ -static void dcache_op (unsigned short flags) -{ - /* 1. Read the data cache control register (DCC) and confirm that bits - 0, 1, 4, and 5 (DC00, DC01, DC04, DC05) are all cleared. */ - WAIT_UNTIL_CLEAR (NB85E_CACHE_DCC & 0x33); - - /* 2. Clear DCC register bit 12 (DC12), bit 13 (DC13), or both - depending on the way for which tags are to be cleared. */ - NB85E_CACHE_DCC &= ~0xC000; - - /* 3. Set DCC register bit 0 (DC00), bit 1 (DC01) or both depending on - the way for which tags are to be cleared. - ... - Set DCC register bit 4 (DC04), bit 5 (DC05), or both depending - on the way to be data flushed. */ - NB85E_CACHE_DCC |= flags; - - /* 4. Read DCC register bit DC00, DC01 [DC04, DC05], or both depending - on the way for which tags were cleared [flushed] and confirm - that that bit is cleared. */ - WAIT_UNTIL_CLEAR (NB85E_CACHE_DCC & flags); -} - -/* Flushes the contents of the dcache to memory. */ -static inline void flush_dcache (void) -{ - /* We only need to do something if in write-back mode. */ - if (NB85E_CACHE_DCC & 0x0400) - dcache_op (0x30); -} - -/* Flushes the contents of the dcache to memory, and then clears it. */ -static inline void clear_dcache (void) -{ - /* We only need to do something if the dcache is enabled. */ - if (NB85E_CACHE_DCC & 0x0C00) - dcache_op (0x33); -} - -/* Clears the dcache without flushing to memory first. */ -static inline void clear_dcache_no_flush (void) -{ - /* We only need to do something if the dcache is enabled. */ - if (NB85E_CACHE_DCC & 0x0C00) - dcache_op (0x3); -} - -static inline void cache_exec_after_store (void) -{ - flush_dcache (); - clear_icache (); -} - - -/* Exported functions. */ - -void inline nb85e_cache_flush_all (void) -{ - clear_icache (); - clear_dcache (); -} - -void nb85e_cache_flush_mm (struct mm_struct *mm) -{ - /* nothing */ -} - -void nb85e_cache_flush_range (struct mm_struct *mm, - unsigned long start, unsigned long end) -{ - /* nothing */ -} - -void nb85e_cache_flush_page (struct vm_area_struct *vma, - unsigned long page_addr) -{ - /* nothing */ -} - -void nb85e_cache_flush_dcache_page (struct page *page) -{ - /* nothing */ -} - -void nb85e_cache_flush_icache (void) -{ - cache_exec_after_store (); -} - -void nb85e_cache_flush_icache_range (unsigned long start, unsigned long end) -{ - cache_exec_after_store (); -} - -void nb85e_cache_flush_icache_page (struct vm_area_struct *vma, - struct page *page) -{ - cache_exec_after_store (); -} - -void nb85e_cache_flush_icache_user_range (struct vm_area_struct *vma, - struct page *page, - unsigned long adr, int len) -{ - cache_exec_after_store (); -} - -void nb85e_cache_flush_sigtramp (unsigned long addr) -{ - cache_exec_after_store (); -} diff --git a/arch/v850/kernel/v850e_cache.c b/arch/v850/kernel/v850e_cache.c new file mode 100644 index 000000000000..6ab5cee48ddd --- /dev/null +++ b/arch/v850/kernel/v850e_cache.c @@ -0,0 +1,173 @@ +/* + * arch/v850/kernel/v850e_cache.c -- Cache control for V850E cache memories + * + * Copyright (C) 2003 NEC Electronics Corporation + * Copyright (C) 2003 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +/* This file implements cache control for the rather simple cache used on + some V850E CPUs, specifically the NB85E/TEG CPU-core and the V850E/ME2 + CPU. V850E2 processors have their own (better) cache + implementation. */ + +#include +#include + +#define WAIT_UNTIL_CLEAR(value) while (value) {} + +/* Set caching params via the BHC and DCC registers. */ +void v850e_cache_enable (u16 bhc, u16 icc, u16 dcc) +{ + unsigned long *r0_ram = (unsigned long *)R0_RAM_ADDR; + register u16 bhc_val asm ("r6") = bhc; + + /* Read the instruction cache control register (ICC) and confirm + that bits 0 and 1 (TCLR0, TCLR1) are all cleared. */ + WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x3); + V850E_CACHE_ICC = icc; + +#ifdef V850E_CACHE_DCC + /* Configure data-cache. */ + V850E_CACHE_DCC = dcc; +#endif /* V850E_CACHE_DCC */ + + /* Configure caching for various memory regions by writing the BHC + register. The documentation says that an instruction _cannot_ + enable/disable caching for the memory region in which the + instruction itself exists; to work around this, we store + appropriate instructions into the on-chip RAM area (which is never + cached), and briefly jump there to do the work. */ +#ifdef V850E_CACHE_WRITE_IBS + *r0_ram++ = 0xf0720760; /* st.h r0, 0xfffff072[r0] */ +#endif + *r0_ram++ = 0xf06a3760; /* st.h r6, 0xfffff06a[r0] */ + *r0_ram = 0x5640006b; /* jmp [r11] */ + + asm ("mov hilo(1f), r11; jmp [%1]; 1:;" + :: "r" (bhc_val), "r" (R0_RAM_ADDR) : "r11"); +} + +static void clear_icache (void) +{ + /* 1. Read the instruction cache control register (ICC) and confirm + that bits 0 and 1 (TCLR0, TCLR1) are all cleared. */ + WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x3); + + /* 2. Read the ICC register and confirm that bit 12 (LOCK0) is + cleared. Bit 13 of the ICC register is always cleared. */ + WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x1000); + + /* 3. Set the TCLR0 and TCLR1 bits of the ICC register as follows, + when clearing way 0 and way 1 at the same time: + (a) Set the TCLR0 and TCLR1 bits. + (b) Read the TCLR0 and TCLR1 bits to confirm that these bits + are cleared. + (c) Perform (a) and (b) above again. */ + V850E_CACHE_ICC |= 0x3; + WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x3); + +#ifdef V850E_CACHE_REPEAT_ICC_WRITE + /* Do it again. */ + V850E_CACHE_ICC |= 0x3; + WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x3); +#endif +} + +#ifdef V850E_CACHE_DCC +/* Flush or clear (or both) the data cache, depending on the value of FLAGS; + the procedure is the same for both, just the control bits used differ (and + both may be performed simultaneously). */ +static void dcache_op (unsigned short flags) +{ + /* 1. Read the data cache control register (DCC) and confirm that bits + 0, 1, 4, and 5 (DC00, DC01, DC04, DC05) are all cleared. */ + WAIT_UNTIL_CLEAR (V850E_CACHE_DCC & 0x33); + + /* 2. Clear DCC register bit 12 (DC12), bit 13 (DC13), or both + depending on the way for which tags are to be cleared. */ + V850E_CACHE_DCC &= ~0xC000; + + /* 3. Set DCC register bit 0 (DC00), bit 1 (DC01) or both depending on + the way for which tags are to be cleared. + ... + Set DCC register bit 4 (DC04), bit 5 (DC05), or both depending + on the way to be data flushed. */ + V850E_CACHE_DCC |= flags; + + /* 4. Read DCC register bit DC00, DC01 [DC04, DC05], or both depending + on the way for which tags were cleared [flushed] and confirm + that that bit is cleared. */ + WAIT_UNTIL_CLEAR (V850E_CACHE_DCC & flags); +} +#endif /* V850E_CACHE_DCC */ + +/* Flushes the contents of the dcache to memory. */ +static inline void flush_dcache (void) +{ +#ifdef V850E_CACHE_DCC + /* We only need to do something if in write-back mode. */ + if (V850E_CACHE_DCC & 0x0400) + dcache_op (0x30); +#endif /* V850E_CACHE_DCC */ +} + +/* Flushes the contents of the dcache to memory, and then clears it. */ +static inline void clear_dcache (void) +{ +#ifdef V850E_CACHE_DCC + /* We only need to do something if the dcache is enabled. */ + if (V850E_CACHE_DCC & 0x0C00) + dcache_op (0x33); +#endif /* V850E_CACHE_DCC */ +} + +/* Clears the dcache without flushing to memory first. */ +static inline void clear_dcache_no_flush (void) +{ +#ifdef V850E_CACHE_DCC + /* We only need to do something if the dcache is enabled. */ + if (V850E_CACHE_DCC & 0x0C00) + dcache_op (0x3); +#endif /* V850E_CACHE_DCC */ +} + +static inline void cache_exec_after_store (void) +{ + flush_dcache (); + clear_icache (); +} + + +/* Exported functions. */ + +void flush_icache (void) +{ + cache_exec_after_store (); +} + +void flush_icache_range (unsigned long start, unsigned long end) +{ + cache_exec_after_store (); +} + +void flush_icache_page (struct vm_area_struct *vma, struct page *page) +{ + cache_exec_after_store (); +} + +void flush_icache_user_range (struct vm_area_struct *vma, struct page *page, + unsigned long adr, int len) +{ + cache_exec_after_store (); +} + +void flush_cache_sigtramp (unsigned long addr) +{ + cache_exec_after_store (); +} diff --git a/include/asm-v850/cacheflush.h b/include/asm-v850/cacheflush.h index 3584a7ee9f14..de27e98490f8 100644 --- a/include/asm-v850/cacheflush.h +++ b/include/asm-v850/cacheflush.h @@ -1,8 +1,8 @@ /* * include/asm-v850/cacheflush.h * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader * * 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 @@ -21,21 +21,40 @@ #include -#ifndef flush_cache_all -/* If there's no flush_cache_all macro defined by , then - this processor has no cache, so just define these as nops. */ - +/* The following are all used by the kernel in ways that only affect + systems with MMUs, so we don't need them. */ #define flush_cache_all() ((void)0) #define flush_cache_mm(mm) ((void)0) #define flush_cache_range(vma, start, end) ((void)0) #define flush_cache_page(vma, vmaddr) ((void)0) #define flush_dcache_page(page) ((void)0) + +#ifdef CONFIG_NO_CACHE + +/* Some systems have no cache at all, in which case we don't need these + either. */ #define flush_icache() ((void)0) #define flush_icache_range(start, end) ((void)0) #define flush_icache_page(vma,pg) ((void)0) #define flush_icache_user_range(vma,pg,adr,len) ((void)0) #define flush_cache_sigtramp(vaddr) ((void)0) -#endif /* !flush_cache_all */ +#else /* !CONFIG_NO_CACHE */ + +struct page; +struct mm_struct; +struct vm_area_struct; + +/* Otherwise, somebody had better define them. */ +extern void flush_icache (void); +extern void flush_icache_range (unsigned long start, unsigned long end); +extern void flush_icache_page (struct vm_area_struct *vma, struct page *page); +extern void flush_icache_user_range (struct vm_area_struct *vma, + struct page *page, + unsigned long adr, int len); +extern void flush_cache_sigtramp (unsigned long addr); + +#endif /* CONFIG_NO_CACHE */ + #endif /* __V850_CACHEFLUSH_H__ */ diff --git a/include/asm-v850/nb85e_cache.h b/include/asm-v850/nb85e_cache.h deleted file mode 100644 index 82b02547ad83..000000000000 --- a/include/asm-v850/nb85e_cache.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * include/asm-v850/nb85e_cache_cache.h -- Cache control for NB85E_CACHE212 and - * NB85E_CACHE213 cache memories - * - * Copyright (C) 2001,03 NEC Electronics Corporation - * Copyright (C) 2001,03 Miles Bader - * - * 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. - * - * Written by Miles Bader - */ - -#ifndef __V850_NB85E_CACHE_H__ -#define __V850_NB85E_CACHE_H__ - -#include - - -/* Cache control registers. */ -#define NB85E_CACHE_BHC_ADDR 0xFFFFF06A -#define NB85E_CACHE_BHC (*(volatile u16 *)NB85E_CACHE_BHC_ADDR) -#define NB85E_CACHE_ICC_ADDR 0xFFFFF070 -#define NB85E_CACHE_ICC (*(volatile u16 *)NB85E_CACHE_ICC_ADDR) -#define NB85E_CACHE_ISI_ADDR 0xFFFFF072 -#define NB85E_CACHE_ISI (*(volatile u16 *)NB85E_CACHE_ISI_ADDR) -#define NB85E_CACHE_DCC_ADDR 0xFFFFF078 -#define NB85E_CACHE_DCC (*(volatile u16 *)NB85E_CACHE_DCC_ADDR) - -/* Size of a cache line in bytes. */ -#define NB85E_CACHE_LINE_SIZE 16 - -/* For */ -#define L1_CACHE_BYTES NB85E_CACHE_LINE_SIZE - - -#if defined(__KERNEL__) && !defined(__ASSEMBLY__) - -/* Set caching params via the BHC and DCC registers. */ -void nb85e_cache_enable (u16 bhc, u16 dcc); - -struct page; -struct mm_struct; -struct vm_area_struct; - -extern void nb85e_cache_flush_all (void); -extern void nb85e_cache_flush_mm (struct mm_struct *mm); -extern void nb85e_cache_flush_range (struct mm_struct *mm, - unsigned long start, - unsigned long end); -extern void nb85e_cache_flush_page (struct vm_area_struct *vma, - unsigned long page_addr); -extern void nb85e_cache_flush_dcache_page (struct page *page); -extern void nb85e_cache_flush_icache (void); -extern void nb85e_cache_flush_icache_range (unsigned long start, - unsigned long end); -extern void nb85e_cache_flush_icache_page (struct vm_area_struct *vma, - struct page *page); -extern void nb85e_cache_flush_icache_user_range (struct vm_area_struct *vma, - struct page *page, - unsigned long adr, int len); -extern void nb85e_cache_flush_sigtramp (unsigned long addr); - -#define flush_cache_all nb85e_cache_flush_all -#define flush_cache_mm nb85e_cache_flush_mm -#define flush_cache_range nb85e_cache_flush_range -#define flush_cache_page nb85e_cache_flush_page -#define flush_dcache_page nb85e_cache_flush_dcache_page -#define flush_icache nb85e_cache_flush_icache -#define flush_icache_range nb85e_cache_flush_icache_range -#define flush_icache_page nb85e_cache_flush_icache_page -#define flush_icache_user_range nb85e_cache_flush_icache_user_range -#define flush_cache_sigtramp nb85e_cache_flush_sigtramp - -#endif /* __KERNEL__ && !__ASSEMBLY__ */ - -#endif /* __V850_NB85E_CACHE_H__ */ diff --git a/include/asm-v850/v850e_cache.h b/include/asm-v850/v850e_cache.h new file mode 100644 index 000000000000..aa7d7eb9da50 --- /dev/null +++ b/include/asm-v850/v850e_cache.h @@ -0,0 +1,48 @@ +/* + * include/asm-v850/v850e_cache.h -- Cache control for V850E cache memories + * + * Copyright (C) 2001,03 NEC Electronics Corporation + * Copyright (C) 2001,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +/* This file implements cache control for the rather simple cache used on + some V850E CPUs, specifically the NB85E/TEG CPU-core and the V850E/ME2 + CPU. V850E2 processors have their own (better) cache + implementation. */ + +#ifndef __V850_V850E_CACHE_H__ +#define __V850_V850E_CACHE_H__ + +#include + + +/* Cache control registers. */ +#define V850E_CACHE_BHC_ADDR 0xFFFFF06A +#define V850E_CACHE_BHC (*(volatile u16 *)V850E_CACHE_BHC_ADDR) +#define V850E_CACHE_ICC_ADDR 0xFFFFF070 +#define V850E_CACHE_ICC (*(volatile u16 *)V850E_CACHE_ICC_ADDR) +#define V850E_CACHE_ISI_ADDR 0xFFFFF072 +#define V850E_CACHE_ISI (*(volatile u16 *)V850E_CACHE_ISI_ADDR) +#define V850E_CACHE_DCC_ADDR 0xFFFFF078 +#define V850E_CACHE_DCC (*(volatile u16 *)V850E_CACHE_DCC_ADDR) + +/* Size of a cache line in bytes. */ +#define V850E_CACHE_LINE_SIZE 16 + +/* For */ +#define L1_CACHE_BYTES V850E_CACHE_LINE_SIZE + + +#if defined(__KERNEL__) && !defined(__ASSEMBLY__) +/* Set caching params via the BHC, ICC, and DCC registers. */ +void v850e_cache_enable (u16 bhc, u16 icc, u16 dcc); +#endif /* __KERNEL__ && !__ASSEMBLY__ */ + + +#endif /* __V850_V850E_CACHE_H__ */ -- cgit v1.2.3 From 4fd24edde8133c7b12331bd66a4bf7cb497f91af Mon Sep 17 00:00:00 2001 From: Miles Bader Date: Thu, 17 Jul 2003 20:11:15 -0700 Subject: [PATCH] Add another layer of indirection for irq numbering with v850 `gbus' irqs This allows ports that support the v850 RTE-CB `GBUS' interrupts to use both them and processor-board-specific interrupts at the same time. --- include/asm-v850/rte_cb.h | 56 ++++++++++++++++++++++++++----------------- include/asm-v850/rte_ma1_cb.h | 41 ++++++++++++++++--------------- 2 files changed, 56 insertions(+), 41 deletions(-) (limited to 'include') diff --git a/include/asm-v850/rte_cb.h b/include/asm-v850/rte_cb.h index fd8ff5350624..9f7f02cb0391 100644 --- a/include/asm-v850/rte_cb.h +++ b/include/asm-v850/rte_cb.h @@ -1,7 +1,7 @@ /* * include/asm-v850/rte_cb.h -- Midas labs RTE-CB series of evaluation boards * - * Copyright (C) 2001,02,03 NEC Corporation + * Copyright (C) 2001,02,03 NEC Electronics Corporation * Copyright (C) 2001,02,03 Miles Bader * * This file is subject to the terms and conditions of the GNU General @@ -20,42 +20,54 @@ #define MB_A_SRAM_SIZE 0x00200000 /* 2MB */ +#ifdef CONFIG_RTE_GBUS_INT /* GBUS interrupt support. */ -#define GBUS_INT_BASE_IRQ NUM_CPU_IRQS -#define GBUS_INT_BASE_ADDR (GCS2_ADDR + 0x00006000) -#include -/* We define NUM_MACH_IRQS to include extra interrupts from the GBUS. */ -#define NUM_MACH_IRQS (NUM_CPU_IRQS + IRQ_GBUS_INT_NUM) +# include + +# define GBUS_INT_BASE_IRQ NUM_RTE_CB_IRQS +# define GBUS_INT_BASE_ADDR (GCS2_ADDR + 0x00006000) /* Some specific interrupts. */ -#define IRQ_MB_A_LAN IRQ_GBUS_INT(10) -#define IRQ_MB_A_PCI1(n) (IRQ_GBUS_INT(16) + (n)) -#define IRQ_MB_A_PCI1_NUM 4 -#define IRQ_MB_A_PCI2(n) (IRQ_GBUS_INT(20) + (n)) -#define IRQ_MB_A_PCI2_NUM 4 -#define IRQ_MB_A_EXT(n) (IRQ_GBUS_INT(24) + (n)) -#define IRQ_MB_A_EXT_NUM 4 -#define IRQ_MB_A_USB_OC(n) (IRQ_GBUS_INT(28) + (n)) -#define IRQ_MB_A_USB_OC_NUM 2 -#define IRQ_MB_A_PCMCIA_OC IRQ_GBUS_INT(30) +# define IRQ_MB_A_LAN IRQ_GBUS_INT(10) +# define IRQ_MB_A_PCI1(n) (IRQ_GBUS_INT(16) + (n)) +# define IRQ_MB_A_PCI1_NUM 4 +# define IRQ_MB_A_PCI2(n) (IRQ_GBUS_INT(20) + (n)) +# define IRQ_MB_A_PCI2_NUM 4 +# define IRQ_MB_A_EXT(n) (IRQ_GBUS_INT(24) + (n)) +# define IRQ_MB_A_EXT_NUM 4 +# define IRQ_MB_A_USB_OC(n) (IRQ_GBUS_INT(28) + (n)) +# define IRQ_MB_A_USB_OC_NUM 2 +# define IRQ_MB_A_PCMCIA_OC IRQ_GBUS_INT(30) + +/* We define NUM_MACH_IRQS to include extra interrupts from the GBUS. */ +# define NUM_MACH_IRQS (NUM_RTE_CB_IRQS + IRQ_GBUS_INT_NUM) +#else /* !CONFIG_RTE_GBUS_INT */ +# define NUM_MACH_IRQS NUM_RTE_CB_IRQS + +#endif /* CONFIG_RTE_GBUS_INT */ + + +#ifdef CONFIG_RTE_MB_A_PCI /* Mother-A PCI bus support. */ -#include + +# include /* These are the base addresses used for allocating device address space. 512K of the motherboard SRAM is in the same space, so we have to be careful not to let it be allocated. */ -#define PCIBIOS_MIN_MEM (MB_A_PCI_MEM_ADDR + 0x80000) -#define PCIBIOS_MIN_IO MB_A_PCI_IO_ADDR +# define PCIBIOS_MIN_MEM (MB_A_PCI_MEM_ADDR + 0x80000) +# define PCIBIOS_MIN_IO MB_A_PCI_IO_ADDR /* As we don't really support PCI DMA to cpu memory, and use bounce-buffers instead, perversely enough, this becomes always true! */ -#define pci_dma_supported(dev, mask) 1 -#define pci_dac_dma_supported(dev, mask) 0 -#define pcibios_assign_all_busses() 1 +# define pci_dma_supported(dev, mask) 1 +# define pci_dac_dma_supported(dev, mask) 0 +# define pcibios_assign_all_busses() 1 +#endif /* CONFIG_RTE_MB_A_PCI */ /* For */ diff --git a/include/asm-v850/rte_ma1_cb.h b/include/asm-v850/rte_ma1_cb.h index 94c287bdbc70..bd3162ab9844 100644 --- a/include/asm-v850/rte_ma1_cb.h +++ b/include/asm-v850/rte_ma1_cb.h @@ -17,25 +17,6 @@ #include /* Common defs for Midas RTE-CB boards. */ -/* CPU addresses of GBUS memory spaces. */ -#define GCS0_ADDR 0x05000000 /* GCS0 - Common SRAM (2MB) */ -#define GCS0_SIZE 0x00200000 /* 2MB */ -#define GCS1_ADDR 0x06000000 /* GCS1 - Flash ROM (8MB) */ -#define GCS1_SIZE 0x00800000 /* 8MB */ -#define GCS2_ADDR 0x07900000 /* GCS2 - I/O registers */ -#define GCS2_SIZE 0x00400000 /* 4MB */ -#define GCS5_ADDR 0x04000000 /* GCS5 - PCI bus space */ -#define GCS5_SIZE 0x01000000 /* 16MB */ -#define GCS6_ADDR 0x07980000 /* GCS6 - PCI control registers */ -#define GCS6_SIZE 0x00000200 /* 512B */ - - -/* The GBUS GINT0 - GINT4 interrupts are connected to the INTP000 - INTP011 - pins on the CPU. These are shared among the GBUS interrupts. */ -#define IRQ_GINT(n) IRQ_INTP(n) -#define IRQ_GINT_NUM 4 - - #define PLATFORM "rte-v850e/ma1-cb" #define PLATFORM_LONG "Midas lab RTE-V850E/MA1-CB" @@ -53,10 +34,32 @@ #define SDRAM_SIZE 0x02000000 /* 32MB */ +/* CPU addresses of GBUS memory spaces. */ +#define GCS0_ADDR 0x05000000 /* GCS0 - Common SRAM (2MB) */ +#define GCS0_SIZE 0x00200000 /* 2MB */ +#define GCS1_ADDR 0x06000000 /* GCS1 - Flash ROM (8MB) */ +#define GCS1_SIZE 0x00800000 /* 8MB */ +#define GCS2_ADDR 0x07900000 /* GCS2 - I/O registers */ +#define GCS2_SIZE 0x00400000 /* 4MB */ +#define GCS5_ADDR 0x04000000 /* GCS5 - PCI bus space */ +#define GCS5_SIZE 0x01000000 /* 16MB */ +#define GCS6_ADDR 0x07980000 /* GCS6 - PCI control registers */ +#define GCS6_SIZE 0x00000200 /* 512B */ + + /* For */ #define PAGE_OFFSET SRAM_ADDR +/* The GBUS GINT0 - GINT3 interrupts are connected to the INTP000 - INTP011 + pins on the CPU. These are shared among the GBUS interrupts. */ +#define IRQ_GINT(n) IRQ_INTP(n) +#define IRQ_GINT_NUM 4 + +/* Used by to derive NUM_MACH_IRQS. */ +#define NUM_RTE_CB_IRQS NUM_CPU_IRQS + + #ifdef CONFIG_ROM_KERNEL /* Kernel is in ROM, starting at address 0. */ -- cgit v1.2.3 From d20f8c749fa9d1d7b6257cc080666527522490d9 Mon Sep 17 00:00:00 2001 From: Miles Bader Date: Thu, 17 Jul 2003 20:11:24 -0700 Subject: [PATCH] Add v850 RTE-V850E/ME2-CB port This adds a port to the V850E/ME2 processor, and the `SolutionGear mini' RTE-V850E/ME2-CB evaluation board. --- arch/v850/kernel/me2.c | 74 ++++++++++ arch/v850/kernel/rte_me2_cb.c | 308 ++++++++++++++++++++++++++++++++++++++++++ arch/v850/rte_me2_cb.ld | 30 ++++ arch/v850/vmlinux.lds.S | 5 + include/asm-v850/machdep.h | 10 +- include/asm-v850/me2.h | 182 +++++++++++++++++++++++++ include/asm-v850/rte_me2_cb.h | 202 +++++++++++++++++++++++++++ include/asm-v850/serial.h | 58 ++++++++ 8 files changed, 867 insertions(+), 2 deletions(-) create mode 100644 arch/v850/kernel/me2.c create mode 100644 arch/v850/kernel/rte_me2_cb.c create mode 100644 arch/v850/rte_me2_cb.ld create mode 100644 include/asm-v850/me2.h create mode 100644 include/asm-v850/rte_me2_cb.h create mode 100644 include/asm-v850/serial.h (limited to 'include') diff --git a/arch/v850/kernel/me2.c b/arch/v850/kernel/me2.c new file mode 100644 index 000000000000..6527c218f91d --- /dev/null +++ b/arch/v850/kernel/me2.c @@ -0,0 +1,74 @@ +/* + * arch/v850/kernel/me2.c -- V850E/ME2 chip-specific support + * + * Copyright (C) 2003 NEC Corporation + * Copyright (C) 2003 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "mach.h" + +void __init mach_sched_init (struct irqaction *timer_action) +{ + /* Start hardware timer. */ + v850e_timer_d_configure (0, HZ); + /* Install timer interrupt handler. */ + setup_irq (IRQ_INTCMD(0), timer_action); +} + +static struct v850e_intc_irq_init irq_inits[] = { + { "IRQ", 0, NUM_CPU_IRQS, 1, 7 }, + { "INTP", IRQ_INTP(0), IRQ_INTP_NUM, 1, 5 }, + { "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 3 }, + { "UBTIRE", IRQ_INTUBTIRE(0), IRQ_INTUBTIRE_NUM, 5, 4 }, + { "UBTIR", IRQ_INTUBTIR(0), IRQ_INTUBTIR_NUM, 5, 4 }, + { "UBTIT", IRQ_INTUBTIT(0), IRQ_INTUBTIT_NUM, 5, 4 }, + { "UBTIF", IRQ_INTUBTIF(0), IRQ_INTUBTIF_NUM, 5, 4 }, + { "UBTITO", IRQ_INTUBTITO(0), IRQ_INTUBTITO_NUM, 5, 4 }, + { 0 } +}; +#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1) + +static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; + +/* Initialize V850E/ME2 chip interrupts. */ +void __init me2_init_irqs (void) +{ + v850e_intc_init_irq_types (irq_inits, hw_itypes); +} + +/* Called before configuring an on-chip UART. */ +void me2_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud) +{ + if (chan == 0) { + /* Specify that the relevent pins on the chip should do + serial I/O, not direct I/O. */ + ME2_PORT1_PMC |= 0xC; + /* Specify that we're using the UART, not the CSI device. */ + ME2_PORT1_PFC |= 0xC; + } else if (chan == 1) { + /* Specify that the relevent pins on the chip should do + serial I/O, not direct I/O. */ + ME2_PORT2_PMC |= 0x6; + /* Specify that we're using the UART, not the CSI device. */ + ME2_PORT2_PFC |= 0x6; + } +} diff --git a/arch/v850/kernel/rte_me2_cb.c b/arch/v850/kernel/rte_me2_cb.c new file mode 100644 index 000000000000..25ae5f6d01c3 --- /dev/null +++ b/arch/v850/kernel/rte_me2_cb.c @@ -0,0 +1,308 @@ +/* + * arch/v850/kernel/rte_me2_cb.c -- Midas labs RTE-V850E/ME2-CB board + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mach.h" + +extern unsigned long *_intv_start; +extern unsigned long *_intv_end; + +/* LED access routines. */ +extern unsigned read_leds (int pos, char *buf, int len); +extern unsigned write_leds (int pos, const char *buf, int len); + + +/* SDRAM are almost contiguous (with a small hole in between; + see mach_reserve_bootmem for details), so just use both as one big area. */ +#define RAM_START SDRAM_ADDR +#define RAM_END (SDRAM_ADDR + SDRAM_SIZE) + + +void __init mach_get_physical_ram (unsigned long *ram_start, + unsigned long *ram_len) +{ + *ram_start = RAM_START; + *ram_len = RAM_END - RAM_START; +} + +void __init mach_reserve_bootmem () +{ + extern char _root_fs_image_start, _root_fs_image_end; + u32 root_fs_image_start = (u32)&_root_fs_image_start; + u32 root_fs_image_end = (u32)&_root_fs_image_end; + + /* Reserve the memory used by the root filesystem image if it's + in RAM. */ + if (root_fs_image_start >= RAM_START && root_fs_image_start < RAM_END) + reserve_bootmem (root_fs_image_start, + root_fs_image_end - root_fs_image_start); +} + +void mach_gettimeofday (struct timespec *tv) +{ + tv->tv_sec = 0; + tv->tv_nsec = 0; +} + +/* Called before configuring an on-chip UART. */ +void rte_me2_cb_uart_pre_configure (unsigned chan, + unsigned cflags, unsigned baud) +{ + /* The RTE-V850E/ME2-CB connects some general-purpose I/O + pins on the CPU to the RTS/CTS lines of UARTB channel 0's + serial connection. + I/O pins P21 and P22 are RTS and CTS respectively. */ + if (chan == 0) { + /* Put P21 & P22 in I/O port mode. */ + ME2_PORT2_PMC &= ~0x6; + /* Make P21 and output, and P22 an input. */ + ME2_PORT2_PM = (ME2_PORT2_PM & ~0xC) | 0x4; + } + + me2_uart_pre_configure (chan, cflags, baud); +} + +void __init mach_init_irqs (void) +{ + /* Initialize interrupts. */ + me2_init_irqs (); + rte_me2_cb_init_irqs (); +} + +#ifdef CONFIG_ROM_KERNEL +/* Initialization for kernel in ROM. */ +static inline rom_kernel_init (void) +{ + /* If the kernel is in ROM, we have to copy any initialized data + from ROM into RAM. */ + extern unsigned long _data_load_start, _sdata, _edata; + register unsigned long *src = &_data_load_start; + register unsigned long *dst = &_sdata, *end = &_edata; + + while (dst != end) + *dst++ = *src++; +} +#endif /* CONFIG_ROM_KERNEL */ + +static void install_interrupt_vectors (void) +{ + unsigned long *p1, *p2; + + ME2_IRAMM = 0x03; /* V850E/ME2 iRAM write mode */ + + /* vector copy to iRAM */ + p1 = (unsigned long *)0; /* v85x vector start */ + p2 = (unsigned long *)&_intv_start; + while (p2 < (unsigned long *)&_intv_end) + *p1++ = *p2++; + + ME2_IRAMM = 0x00; /* V850E/ME2 iRAM read mode */ +} + +/* CompactFlash */ + +static void cf_power_on (void) +{ + /* CF card detected? */ + if (CB_CF_STS0 & 0x0030) + return; + + CB_CF_REG0 = 0x0002; /* reest on */ + mdelay (10); + CB_CF_REG0 = 0x0003; /* power on */ + mdelay (10); + CB_CF_REG0 = 0x0001; /* reset off */ + mdelay (10); +} + +static void cf_power_off (void) +{ + CB_CF_REG0 = 0x0003; /* power on */ + mdelay (10); + CB_CF_REG0 = 0x0002; /* reest on */ + mdelay (10); +} + +void __init mach_early_init (void) +{ + install_interrupt_vectors (); + + /* CS1 SDRAM instruction cache enable */ + v850e_cache_enable (0x04, 0x03, 0); + + rte_cb_early_init (); + + /* CompactFlash power on */ + cf_power_on (); + +#if defined (CONFIG_ROM_KERNEL) + rom_kernel_init (); +#endif +} + + +/* RTE-V850E/ME2-CB Programmable Interrupt Controller. */ + +static struct cb_pic_irq_init cb_pic_irq_inits[] = { + { "CB_EXTTM0", IRQ_CB_EXTTM0, 1, 1, 6 }, + { "CB_EXTSIO", IRQ_CB_EXTSIO, 1, 1, 6 }, + { "CB_TOVER", IRQ_CB_TOVER, 1, 1, 6 }, + { "CB_GINT0", IRQ_CB_GINT0, 1, 1, 6 }, + { "CB_USB", IRQ_CB_USB, 1, 1, 6 }, + { "CB_LANC", IRQ_CB_LANC, 1, 1, 6 }, + { "CB_USB_VBUS_ON", IRQ_CB_USB_VBUS_ON, 1, 1, 6 }, + { "CB_USB_VBUS_OFF", IRQ_CB_USB_VBUS_OFF, 1, 1, 6 }, + { "CB_EXTTM1", IRQ_CB_EXTTM1, 1, 1, 6 }, + { "CB_EXTTM2", IRQ_CB_EXTTM2, 1, 1, 6 }, + { 0 } +}; +#define NUM_CB_PIC_IRQ_INITS \ + ((sizeof cb_pic_irq_inits / sizeof cb_pic_irq_inits[0]) - 1) + +static struct hw_interrupt_type cb_pic_hw_itypes[NUM_CB_PIC_IRQ_INITS]; +static unsigned char cb_pic_active_irqs = 0; + +void __init rte_me2_cb_init_irqs (void) +{ + cb_pic_init_irq_types (cb_pic_irq_inits, cb_pic_hw_itypes); + + /* Initalize on board PIC1 (not PIC0) enable */ + CB_PIC_INT0M = 0x0000; + CB_PIC_INT1M = 0x0000; + CB_PIC_INTR = 0x0000; + CB_PIC_INTEN |= CB_PIC_INT1EN; + + ME2_PORT2_PMC |= 0x08; /* INTP23/SCK1 mode */ + ME2_PORT2_PFC &= ~0x08; /* INTP23 mode */ + ME2_INTR(2) &= ~0x08; /* INTP23 falling-edge detect */ + ME2_INTF(2) &= ~0x08; /* " */ + + rte_cb_init_irqs (); /* gbus &c */ +} + + +/* Enable interrupt handling for interrupt IRQ. */ +void cb_pic_enable_irq (unsigned irq) +{ + CB_PIC_INT1M |= 1 << (irq - CB_PIC_BASE_IRQ); +} + +void cb_pic_disable_irq (unsigned irq) +{ + CB_PIC_INT1M &= ~(1 << (irq - CB_PIC_BASE_IRQ)); +} + +void cb_pic_shutdown_irq (unsigned irq) +{ + cb_pic_disable_irq (irq); + + if (--cb_pic_active_irqs == 0) + free_irq (IRQ_CB_PIC, 0); + + CB_PIC_INT1M &= ~(1 << (irq - CB_PIC_BASE_IRQ)); +} + +static void cb_pic_handle_irq (int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned status = CB_PIC_INTR; + unsigned enable = CB_PIC_INT1M; + + /* Only pay attention to enabled interrupts. */ + status &= enable; + + CB_PIC_INTEN &= ~CB_PIC_INT1EN; + + if (status) { + unsigned mask = 1; + + irq = CB_PIC_BASE_IRQ; + do { + /* There's an active interrupt, find out which one, + and call its handler. */ + while (! (status & mask)) { + irq++; + mask <<= 1; + } + status &= ~mask; + + CB_PIC_INTR = mask; + + /* Recursively call handle_irq to handle it. */ + handle_irq (irq, regs); + } while (status); + } + + CB_PIC_INTEN |= CB_PIC_INT1EN; +} + + +static void irq_nop (unsigned irq) { } + +static unsigned cb_pic_startup_irq (unsigned irq) +{ + int rval; + + if (cb_pic_active_irqs == 0) { + rval = request_irq (IRQ_CB_PIC, cb_pic_handle_irq, + SA_INTERRUPT, "cb_pic_handler", 0); + if (rval != 0) + return rval; + } + + cb_pic_active_irqs++; + + cb_pic_enable_irq (irq); + + return 0; +} + +/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array + INITS (which is terminated by an entry with the name field == 0). */ +void __init cb_pic_init_irq_types (struct cb_pic_irq_init *inits, + struct hw_interrupt_type *hw_irq_types) +{ + struct cb_pic_irq_init *init; + for (init = inits; init->name; init++) { + struct hw_interrupt_type *hwit = hw_irq_types++; + + hwit->typename = init->name; + + hwit->startup = cb_pic_startup_irq; + hwit->shutdown = cb_pic_shutdown_irq; + hwit->enable = cb_pic_enable_irq; + hwit->disable = cb_pic_disable_irq; + hwit->ack = irq_nop; + hwit->end = irq_nop; + + /* Initialize kernel IRQ infrastructure for this interrupt. */ + init_irq_handlers(init->base, init->num, init->interval, hwit); + } +} diff --git a/arch/v850/rte_me2_cb.ld b/arch/v850/rte_me2_cb.ld new file mode 100644 index 000000000000..e6df7fe1aeae --- /dev/null +++ b/arch/v850/rte_me2_cb.ld @@ -0,0 +1,30 @@ +/* Linker script for the Midas labs RTE-V850E/ME2-CB evaluation board + (CONFIG_RTE_CB_ME2), with kernel in SDRAM. */ + +MEMORY { + /* 128Kbyte of IRAM */ + IRAM : ORIGIN = 0x00000000, LENGTH = 0x00020000 + + /* 32MB of SDRAM. */ + SDRAM : ORIGIN = 0x00800000, LENGTH = 0x02000000 +} + +#define KRAM SDRAM + +SECTIONS { + .text : { + __kram_start = . ; + TEXT_CONTENTS + INTV_CONTENTS /* copy to iRAM (0x0-0x620) */ + } > KRAM + + .data : { + DATA_CONTENTS + BSS_CONTENTS + RAMK_INIT_CONTENTS + __kram_end = . ; + BOOTMAP_CONTENTS + } > KRAM + + .root ALIGN (4096) : { ROOT_FS_CONTENTS } > SDRAM +} diff --git a/arch/v850/vmlinux.lds.S b/arch/v850/vmlinux.lds.S index 7391ab36f1a9..e27b7970ddeb 100644 --- a/arch/v850/vmlinux.lds.S +++ b/arch/v850/vmlinux.lds.S @@ -247,3 +247,8 @@ _jiffies = _jiffies_64 ; # include "rte_nb85e_cb.ld" # endif #endif + +#ifdef CONFIG_RTE_CB_ME2 +# include "rte_me2_cb.ld" +#endif + diff --git a/include/asm-v850/machdep.h b/include/asm-v850/machdep.h index 88b3a6fe24a3..3befbff5c29d 100644 --- a/include/asm-v850/machdep.h +++ b/include/asm-v850/machdep.h @@ -1,8 +1,8 @@ /* * include/asm-v850/machdep.h -- Machine-dependent definitions * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader * * 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 @@ -20,6 +20,9 @@ #ifdef CONFIG_V850E_MA1 #include #endif +#ifdef CONFIG_V850E_ME2 +#include +#endif #ifdef CONFIG_V850E_TEG #include #endif @@ -36,6 +39,9 @@ #ifdef CONFIG_RTE_CB_MA1 #include #endif +#ifdef CONFIG_RTE_CB_ME2 +#include +#endif #ifdef CONFIG_RTE_CB_NB85E #include #endif diff --git a/include/asm-v850/me2.h b/include/asm-v850/me2.h new file mode 100644 index 000000000000..ac7c9ce0bdc1 --- /dev/null +++ b/include/asm-v850/me2.h @@ -0,0 +1,182 @@ +/* + * include/asm-v850/me2.h -- V850E/ME2 cpu chip + * + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#ifndef __V850_ME2_H__ +#define __V850_ME2_H__ + +#include +#include + + +#define CPU_MODEL "v850e/me2" +#define CPU_MODEL_LONG "NEC V850E/ME2" + + +/* Hardware-specific interrupt numbers (in the kernel IRQ namespace). */ +#define IRQ_INTP(n) (n) /* Pnnn (pin) interrupts */ +#define IRQ_INTP_NUM 31 +#define IRQ_INTCMD(n) (0x31 + (n)) /* interval timer interrupts 0-3 */ +#define IRQ_INTCMD_NUM 4 +#define IRQ_INTDMA(n) (0x41 + (n)) /* DMA interrupts 0-3 */ +#define IRQ_INTDMA_NUM 4 +#define IRQ_INTUBTIRE(n) (0x49 + (n)*5)/* UARTB 0-1 reception error */ +#define IRQ_INTUBTIRE_NUM 2 +#define IRQ_INTUBTIR(n) (0x4a + (n)*5) /* UARTB 0-1 reception complete */ +#define IRQ_INTUBTIR_NUM 2 +#define IRQ_INTUBTIT(n) (0x4b + (n)*5) /* UARTB 0-1 transmission complete */ +#define IRQ_INTUBTIT_NUM 2 +#define IRQ_INTUBTIF(n) (0x4c + (n)*5) /* UARTB 0-1 FIFO trans. complete */ +#define IRQ_INTUBTIF_NUM 2 +#define IRQ_INTUBTITO(n) (0x4d + (n)*5) /* UARTB 0-1 reception timeout */ +#define IRQ_INTUBTITO_NUM 2 + +/* For */ +#define NUM_CPU_IRQS 0x59 /* V850E/ME2 */ + + +/* For */ +/* We use on-chip RAM, for a few miscellaneous variables that must be + accessible using a load instruction relative to R0. */ +#define R0_RAM_ADDR 0xFFFFB000 /* V850E/ME2 */ + + +/* V850E/ME2 UARTB details.*/ +#define V850E_UART_NUM_CHANNELS 2 +#define V850E_UARTB_BASE_FREQ (CPU_CLOCK_FREQ / 4) + +/* This is a function that gets called before configuring the UART. */ +#define V850E_UART_PRE_CONFIGURE me2_uart_pre_configure +#ifndef __ASSEMBLY__ +extern void me2_uart_pre_configure (unsigned chan, + unsigned cflags, unsigned baud); +#endif /* __ASSEMBLY__ */ + + +/* V850E/ME2 timer C details. */ +#define V850E_TIMER_C_BASE_ADDR 0xFFFFF600 + + +/* V850E/ME2 timer D details. */ +#define V850E_TIMER_D_BASE_ADDR 0xFFFFF540 +#define V850E_TIMER_D_TMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x0) +#define V850E_TIMER_D_CMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x2) +#define V850E_TIMER_D_TMCD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x4) + +#define V850E_TIMER_D_BASE_FREQ (CPU_CLOCK_FREQ / 2) + + +/* Select iRAM mode. */ +#define ME2_IRAMM_ADDR 0xFFFFF80A +#define ME2_IRAMM (*(volatile u8*)ME2_IRAMM_ADDR) + + +/* Interrupt edge-detection configuration. INTF(n) and INTR(n) are only + valid for n == 1, 2, or 5. */ +#define ME2_INTF_ADDR(n) (0xFFFFFC00 + (n) * 0x2) +#define ME2_INTF(n) (*(volatile u8*)ME2_INTF_ADDR(n)) +#define ME2_INTR_ADDR(n) (0xFFFFFC20 + (n) * 0x2) +#define ME2_INTR(n) (*(volatile u8*)ME2_INTR_ADDR(n)) +#define ME2_INTFAL_ADDR 0xFFFFFC10 +#define ME2_INTFAL (*(volatile u8*)ME2_INTFAL_ADDR) +#define ME2_INTRAL_ADDR 0xFFFFFC30 +#define ME2_INTRAL (*(volatile u8*)ME2_INTRAL_ADDR) +#define ME2_INTFDH_ADDR 0xFFFFFC16 +#define ME2_INTFDH (*(volatile u16*)ME2_INTFDH_ADDR) +#define ME2_INTRDH_ADDR 0xFFFFFC36 +#define ME2_INTRDH (*(volatile u16*)ME2_INTRDH_ADDR) +#define ME2_SESC_ADDR(n) (0xFFFFF609 + (n) * 0x10) +#define ME2_SESC(n) (*(volatile u8*)ME2_SESC_ADDR(n)) +#define ME2_SESA10_ADDR 0xFFFFF5AD +#define ME2_SESA10 (*(volatile u8*)ME2_SESA10_ADDR) +#define ME2_SESA11_ADDR 0xFFFFF5DD +#define ME2_SESA11 (*(volatile u8*)ME2_SESA11_ADDR) + + +/* Port 1 */ +/* Direct I/O. Bits 0-3 are pins P10-P13. */ +#define ME2_PORT1_IO_ADDR 0xFFFFF402 +#define ME2_PORT1_IO (*(volatile u8 *)ME2_PORT1_IO_ADDR) +/* Port mode (for direct I/O, 0 = output, 1 = input). */ +#define ME2_PORT1_PM_ADDR 0xFFFFF422 +#define ME2_PORT1_PM (*(volatile u8 *)ME2_PORT1_PM_ADDR) +/* Port mode control (0 = direct I/O mode, 1 = alternative I/O mode). */ +#define ME2_PORT1_PMC_ADDR 0xFFFFF442 +#define ME2_PORT1_PMC (*(volatile u8 *)ME2_PORT1_PMC_ADDR) +/* Port function control (for serial interfaces, 0 = CSI30, 1 = UARTB0 ). */ +#define ME2_PORT1_PFC_ADDR 0xFFFFF462 +#define ME2_PORT1_PFC (*(volatile u8 *)ME2_PORT1_PFC_ADDR) + +/* Port 2 */ +/* Direct I/O. Bits 0-3 are pins P20-P25. */ +#define ME2_PORT2_IO_ADDR 0xFFFFF404 +#define ME2_PORT2_IO (*(volatile u8 *)ME2_PORT2_IO_ADDR) +/* Port mode (for direct I/O, 0 = output, 1 = input). */ +#define ME2_PORT2_PM_ADDR 0xFFFFF424 +#define ME2_PORT2_PM (*(volatile u8 *)ME2_PORT2_PM_ADDR) +/* Port mode control (0 = direct I/O mode, 1 = alternative I/O mode). */ +#define ME2_PORT2_PMC_ADDR 0xFFFFF444 +#define ME2_PORT2_PMC (*(volatile u8 *)ME2_PORT2_PMC_ADDR) +/* Port function control (for serial interfaces, 0 = INTP2x, 1 = UARTB1 ). */ +#define ME2_PORT2_PFC_ADDR 0xFFFFF464 +#define ME2_PORT2_PFC (*(volatile u8 *)ME2_PORT2_PFC_ADDR) + +/* Port 5 */ +/* Direct I/O. Bits 0-5 are pins P50-P55. */ +#define ME2_PORT5_IO_ADDR 0xFFFFF40A +#define ME2_PORT5_IO (*(volatile u8 *)ME2_PORT5_IO_ADDR) +/* Port mode (for direct I/O, 0 = output, 1 = input). */ +#define ME2_PORT5_PM_ADDR 0xFFFFF42A +#define ME2_PORT5_PM (*(volatile u8 *)ME2_PORT5_PM_ADDR) +/* Port mode control (0 = direct I/O mode, 1 = alternative I/O mode). */ +#define ME2_PORT5_PMC_ADDR 0xFFFFF44A +#define ME2_PORT5_PMC (*(volatile u8 *)ME2_PORT5_PMC_ADDR) +/* Port function control (). */ +#define ME2_PORT5_PFC_ADDR 0xFFFFF46A +#define ME2_PORT5_PFC (*(volatile u8 *)ME2_PORT5_PFC_ADDR) + +/* Port 6 */ +/* Direct I/O. Bits 5-7 are pins P65-P67. */ +#define ME2_PORT6_IO_ADDR 0xFFFFF40C +#define ME2_PORT6_IO (*(volatile u8 *)ME2_PORT6_IO_ADDR) +/* Port mode (for direct I/O, 0 = output, 1 = input). */ +#define ME2_PORT6_PM_ADDR 0xFFFFF42C +#define ME2_PORT6_PM (*(volatile u8 *)ME2_PORT6_PM_ADDR) +/* Port mode control (0 = direct I/O mode, 1 = alternative I/O mode). */ +#define ME2_PORT6_PMC_ADDR 0xFFFFF44C +#define ME2_PORT6_PMC (*(volatile u8 *)ME2_PORT6_PMC_ADDR) +/* Port function control (). */ +#define ME2_PORT6_PFC_ADDR 0xFFFFF46C +#define ME2_PORT6_PFC (*(volatile u8 *)ME2_PORT6_PFC_ADDR) + +/* Port 7 */ +/* Direct I/O. Bits 2-7 are pins P72-P77. */ +#define ME2_PORT7_IO_ADDR 0xFFFFF40E +#define ME2_PORT7_IO (*(volatile u8 *)ME2_PORT7_IO_ADDR) +/* Port mode (for direct I/O, 0 = output, 1 = input). */ +#define ME2_PORT7_PM_ADDR 0xFFFFF42E +#define ME2_PORT7_PM (*(volatile u8 *)ME2_PORT7_PM_ADDR) +/* Port mode control (0 = direct I/O mode, 1 = alternative I/O mode). */ +#define ME2_PORT7_PMC_ADDR 0xFFFFF44E +#define ME2_PORT7_PMC (*(volatile u8 *)ME2_PORT7_PMC_ADDR) +/* Port function control (). */ +#define ME2_PORT7_PFC_ADDR 0xFFFFF46E +#define ME2_PORT7_PFC (*(volatile u8 *)ME2_PORT7_PFC_ADDR) + + +#ifndef __ASSEMBLY__ +/* Initialize V850E/ME2 chip interrupts. */ +extern void me2_init_irqs (void); +#endif /* !__ASSEMBLY__ */ + + +#endif /* __V850_ME2_H__ */ diff --git a/include/asm-v850/rte_me2_cb.h b/include/asm-v850/rte_me2_cb.h new file mode 100644 index 000000000000..bdb7df71410e --- /dev/null +++ b/include/asm-v850/rte_me2_cb.h @@ -0,0 +1,202 @@ +/* + * include/asm-v850/rte_me2_cb.h -- Midas labs RTE-V850E/ME2-CB board + * + * Copyright (C) 2001,02,03 NEC Corporation + * Copyright (C) 2001,02,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#ifndef __V850_RTE_ME2_CB_H__ +#define __V850_RTE_ME2_CB_H__ + +#include /* Common defs for Midas RTE-CB boards. */ + + +#define PLATFORM "rte-v850e/me2-cb" +#define PLATFORM_LONG "Midas lab RTE-V850E/ME2-CB" + +#define CPU_CLOCK_FREQ 150000000 /* 150MHz */ +#define FIXED_BOGOMIPS 50 + +/* 32MB of onbard SDRAM. */ +#define SDRAM_ADDR 0x00800000 +#define SDRAM_SIZE 0x02000000 /* 32MB */ + + +/* CPU addresses of GBUS memory spaces. */ +#define GCS0_ADDR 0x04000000 /* GCS0 - Common SRAM (2MB) */ +#define GCS0_SIZE 0x00800000 /* 8MB */ +#define GCS1_ADDR 0x04800000 /* GCS1 - Flash ROM (8MB) */ +#define GCS1_SIZE 0x00800000 /* 8MB */ +#define GCS2_ADDR 0x07000000 /* GCS2 - I/O registers */ +#define GCS2_SIZE 0x00800000 /* 8MB */ +#define GCS5_ADDR 0x08000000 /* GCS5 - PCI bus space */ +#define GCS5_SIZE 0x02000000 /* 32MB */ +#define GCS6_ADDR 0x07800000 /* GCS6 - PCI control registers */ +#define GCS6_SIZE 0x00800000 /* 8MB */ + + +/* For */ +#define PAGE_OFFSET SDRAM_ADDR + + +#ifdef CONFIG_ROM_KERNEL +/* Kernel is in ROM, starting at address 0. */ + +#define INTV_BASE 0 +#define ROOT_FS_IMAGE_RW 0 + +#else /* !CONFIG_ROM_KERNEL */ +/* Using RAM-kernel. Assume some sort of boot-loader got us loaded at + address 0. */ + +#define INTV_BASE 0 +#define ROOT_FS_IMAGE_RW 1 + +#endif /* CONFIG_ROM_KERNEL */ + + +/* Some misc. on-board devices. */ + +/* Seven-segment LED display (four digits). */ +#define LED_ADDR(n) (0x0FE02000 + (n)) +#define LED(n) (*(volatile unsigned char *)LED_ADDR(n)) +#define LED_NUM_DIGITS 4 + + +/* On-board PIC. */ + +#define CB_PIC_BASE_ADDR 0x0FE04000 + +#define CB_PIC_INT0M_ADDR (CB_PIC_BASE_ADDR + 0x00) +#define CB_PIC_INT0M (*(volatile u16 *)CB_PIC_INT0M_ADDR) +#define CB_PIC_INT1M_ADDR (CB_PIC_BASE_ADDR + 0x10) +#define CB_PIC_INT1M (*(volatile u16 *)CB_PIC_INT1M_ADDR) +#define CB_PIC_INTR_ADDR (CB_PIC_BASE_ADDR + 0x20) +#define CB_PIC_INTR (*(volatile u16 *)CB_PIC_INTR_ADDR) +#define CB_PIC_INTEN_ADDR (CB_PIC_BASE_ADDR + 0x30) +#define CB_PIC_INTEN (*(volatile u16 *)CB_PIC_INTEN_ADDR) + +#define CB_PIC_INT0EN 0x0001 +#define CB_PIC_INT1EN 0x0002 +#define CB_PIC_INT0SEL 0x0080 + +/* The PIC interrupts themselves. */ +#define CB_PIC_BASE_IRQ NUM_CPU_IRQS +#define IRQ_CB_PIC_NUM 10 + +/* Some specific CB_PIC interrupts. */ +#define IRQ_CB_EXTTM0 (CB_PIC_BASE_IRQ + 0) +#define IRQ_CB_EXTSIO (CB_PIC_BASE_IRQ + 1) +#define IRQ_CB_TOVER (CB_PIC_BASE_IRQ + 2) +#define IRQ_CB_GINT0 (CB_PIC_BASE_IRQ + 3) +#define IRQ_CB_USB (CB_PIC_BASE_IRQ + 4) +#define IRQ_CB_LANC (CB_PIC_BASE_IRQ + 5) +#define IRQ_CB_USB_VBUS_ON (CB_PIC_BASE_IRQ + 6) +#define IRQ_CB_USB_VBUS_OFF (CB_PIC_BASE_IRQ + 7) +#define IRQ_CB_EXTTM1 (CB_PIC_BASE_IRQ + 8) +#define IRQ_CB_EXTTM2 (CB_PIC_BASE_IRQ + 9) + +/* The GBUS GINT1 - GINT3 (note, not GINT0!) interrupts are connected to + the INTP65 - INTP67 pins on the CPU. These are shared among the GBUS + interrupts. */ +#define IRQ_GINT(n) IRQ_INTP((n) + 9) /* 0 is unused! */ +#define IRQ_GINT_NUM 4 /* 0 is unused! */ + +/* The shared interrupt line from the PIC is connected to CPU pin INTP23. */ +#define IRQ_CB_PIC IRQ_INTP(4) /* P23 */ + +/* Used by to derive NUM_MACH_IRQS. */ +#define NUM_RTE_CB_IRQS (NUM_CPU_IRQS + IRQ_CB_PIC_NUM) + + +#ifndef __ASSEMBLY__ +struct cb_pic_irq_init { + const char *name; /* name of interrupt type */ + + /* Range of kernel irq numbers for this type: + BASE, BASE+INTERVAL, ..., BASE+INTERVAL*NUM */ + unsigned base, num, interval; + + unsigned priority; /* interrupt priority to assign */ +}; +struct hw_interrupt_type; /* fwd decl */ + +/* Enable interrupt handling for interrupt IRQ. */ +extern void cb_pic_enable_irq (unsigned irq); +/* Disable interrupt handling for interrupt IRQ. Note that any interrupts + received while disabled will be delivered once the interrupt is enabled + again, unless they are explicitly cleared using `cb_pic_clear_pending_irq'. */ +extern void cb_pic_disable_irq (unsigned irq); +/* Initialize HW_IRQ_TYPES for PIC irqs described in array INITS (which is + terminated by an entry with the name field == 0). */ +extern void cb_pic_init_irq_types (struct cb_pic_irq_init *inits, + struct hw_interrupt_type *hw_irq_types); +/* Initialize PIC interrupts. */ +extern void cb_pic_init_irqs (void); +#endif /* __ASSEMBLY__ */ + + +/* TL16C550C on board UART see also asm/serial.h */ +#define CB_UART_BASE 0x0FE08000 +#define CB_UART_REG_GAP 0x10 +#define CB_UART_CLOCK 0x16000000 + +/* CompactFlash setting see also asm/ide.h, asm/hdreg.h. */ +#define CB_CF_BASE 0x0FE0C000 +#define CB_CF_CCR_ADDR (CB_CF_BASE+0x200) +#define CB_CF_CCR (*(volatile u8 *)CB_CF_CCR_ADDR) +#define CB_CF_REG0_ADDR (CB_CF_BASE+0x1000) +#define CB_CF_REG0 (*(volatile u16 *)CB_CF_REG0_ADDR) +#define CB_CF_STS0_ADDR (CB_CF_BASE+0x1004) +#define CB_CF_STS0 (*(volatile u16 *)CB_CF_STS0_ADDR) +#define CB_PCATA_BASE (CB_CF_BASE+0x800) +#define CB_IDE_BASE (CB_CF_BASE+0x9F0) +#define CB_IDE_CTRL (CB_CF_BASE+0xBF6) +#define CB_IDE_REG_OFFS 0x1 + + +/* SMSC LAN91C111 setting */ +#if defined(CONFIG_SMC91111) +#define CB_LANC_BASE 0x0FE10300 +#define CONFIG_SMC16BITONLY +#define ETH0_ADDR CB_LANC_BASE +#define ETH0_IRQ IRQ_CB_LANC +#endif /* CONFIG_SMC16BITONLY */ + + +#undef V850E_UART_PRE_CONFIGURE +#define V850E_UART_PRE_CONFIGURE rte_me2_cb_uart_pre_configure +#ifndef __ASSEMBLY__ +extern void rte_me2_cb_uart_pre_configure (unsigned chan, + unsigned cflags, unsigned baud); +#endif /* __ASSEMBLY__ */ + +/* This board supports RTS/CTS for the on-chip UART, but only for channel 0. */ + +/* CTS for UART channel 0 is pin P22 (bit 2 of port 2). */ +#define V850E_UART_CTS(chan) ((chan) == 0 ? !(ME2_PORT2_IO & 0x4) : 1) +/* RTS for UART channel 0 is pin P21 (bit 1 of port 2). */ +#define V850E_UART_SET_RTS(chan, val) \ + do { \ + if (chan == 0) { \ + unsigned old = ME2_PORT2_IO; \ + if (val) \ + ME2_PORT2_IO = old & ~0x2; \ + else \ + ME2_PORT2_IO = old | 0x2; \ + } \ + } while (0) + + +#ifndef __ASSEMBLY__ +extern void rte_me2_cb_init_irqs (void); +#endif /* !__ASSEMBLY__ */ + + +#endif /* __V850_RTE_ME2_CB_H__ */ diff --git a/include/asm-v850/serial.h b/include/asm-v850/serial.h new file mode 100644 index 000000000000..1b62e3eda886 --- /dev/null +++ b/include/asm-v850/serial.h @@ -0,0 +1,58 @@ +/* + * 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. + * + * Copyright (C) 1999 by Ralf Baechle + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + */ +#include + +#ifdef CONFIG_RTE_CB_ME2 + +#include + +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +#define irq_cannonicalize(x) (x) +#define BASE_BAUD 250000 /* (16MHz / (16 * 38400)) * 9600 */ +#define RS_TABLE_SIZE 1 +#define SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, CB_UART_BASE, IRQ_CB_EXTSIO, STD_COM_FLAGS }, + +/* Redefine UART register offsets. */ +#undef UART_RX +#undef UART_TX +#undef UART_DLL +#undef UART_TRG +#undef UART_DLM +#undef UART_IER +#undef UART_FCTR +#undef UART_IIR +#undef UART_FCR +#undef UART_EFR +#undef UART_LCR +#undef UART_MCR +#undef UART_LSR +#undef UART_MSR +#undef UART_SCR +#undef UART_EMSR + +#define UART_RX (0 * CB_UART_REG_GAP) +#define UART_TX (0 * CB_UART_REG_GAP) +#define UART_DLL (0 * CB_UART_REG_GAP) +#define UART_TRG (0 * CB_UART_REG_GAP) +#define UART_DLM (1 * CB_UART_REG_GAP) +#define UART_IER (1 * CB_UART_REG_GAP) +#define UART_FCTR (1 * CB_UART_REG_GAP) +#define UART_IIR (2 * CB_UART_REG_GAP) +#define UART_FCR (2 * CB_UART_REG_GAP) +#define UART_EFR (2 * CB_UART_REG_GAP) +#define UART_LCR (3 * CB_UART_REG_GAP) +#define UART_MCR (4 * CB_UART_REG_GAP) +#define UART_LSR (5 * CB_UART_REG_GAP) +#define UART_MSR (6 * CB_UART_REG_GAP) +#define UART_SCR (7 * CB_UART_REG_GAP) +#define UART_EMSR (7 * CB_UART_REG_GAP) + +#endif /* CONFIG_RTE_CB_ME2 */ -- cgit v1.2.3 From 46c376398a341a46cc85eefaba7f8f058cad0496 Mon Sep 17 00:00:00 2001 From: Miles Bader Date: Thu, 17 Jul 2003 20:12:08 -0700 Subject: [PATCH] Add v850 `sim85e2s' port, and cleanup v850e2 code This patch adds support for the `sim85e2s' simulation of the NA85E2S processor implementation. As part of this, cache-flushing support for the common v850e2 cache implementation is added. It also cleans up a bunch of code that was duplicated between different v850e2 processors. --- arch/v850/kernel/anna.c | 42 ++++---- arch/v850/kernel/fpga85e2c.c | 2 +- arch/v850/kernel/sim85e2.c | 211 ++++++++++++++++++++++++++++++++++++++++ arch/v850/kernel/sim85e2c.c | 145 --------------------------- arch/v850/kernel/v850e2_cache.c | 127 ++++++++++++++++++++++++ arch/v850/sim85e2.ld | 44 +++++++++ arch/v850/sim85e2c.ld | 44 --------- arch/v850/vmlinux.lds.S | 4 +- include/asm-v850/anna.h | 34 +------ include/asm-v850/fpga85e2c.h | 24 +---- include/asm-v850/machdep.h | 3 + include/asm-v850/sim85e2.h | 79 +++++++++++++++ include/asm-v850/sim85e2c.h | 70 +------------ include/asm-v850/sim85e2s.h | 28 ++++++ include/asm-v850/v850e2.h | 69 +++++++++++++ include/asm-v850/v850e2_cache.h | 74 ++++++++++++++ 16 files changed, 669 insertions(+), 331 deletions(-) create mode 100644 arch/v850/kernel/sim85e2.c delete mode 100644 arch/v850/kernel/sim85e2c.c create mode 100644 arch/v850/kernel/v850e2_cache.c create mode 100644 arch/v850/sim85e2.ld delete mode 100644 arch/v850/sim85e2c.ld create mode 100644 include/asm-v850/sim85e2.h create mode 100644 include/asm-v850/sim85e2s.h create mode 100644 include/asm-v850/v850e2.h create mode 100644 include/asm-v850/v850e2_cache.h (limited to 'include') diff --git a/arch/v850/kernel/anna.c b/arch/v850/kernel/anna.c index c6590eab99cb..6c542d0a0f9a 100644 --- a/arch/v850/kernel/anna.c +++ b/arch/v850/kernel/anna.c @@ -41,24 +41,30 @@ static void anna_led_tick (void); void __init mach_early_init (void) { - ANNA_ILBEN = 0; - ANNA_CSC(0) = 0x402F; - ANNA_CSC(1) = 0x4000; - ANNA_BPC = 0; - ANNA_BSC = 0xAAAA; - ANNA_BEC = 0; - ANNA_BHC = 0xFFFF; /* icache all memory, dcache all */ - ANNA_BCT(0) = 0xB088; - ANNA_BCT(1) = 0x0008; - ANNA_DWC(0) = 0x0027; - ANNA_DWC(1) = 0; - ANNA_BCC = 0x0006; - ANNA_ASC = 0; - ANNA_LBS = 0x0089; - ANNA_SCR3 = 0x21A9; - ANNA_RFS3 = 0x8121; - - nb85e_intc_disable_irqs (); + ANNA_ILBEN = 0; + + V850E2_CSC(0) = 0x402F; + V850E2_CSC(1) = 0x4000; + V850E2_BPC = 0; + V850E2_BSC = 0xAAAA; + V850E2_BEC = 0; + +#if 0 + V850E2_BHC = 0xFFFF; /* icache all memory, dcache all */ +#else + V850E2_BHC = 0; /* cache no memory */ +#endif + V850E2_BCT(0) = 0xB088; + V850E2_BCT(1) = 0x0008; + V850E2_DWC(0) = 0x0027; + V850E2_DWC(1) = 0; + V850E2_BCC = 0x0006; + V850E2_ASC = 0; + V850E2_LBS = 0x0089; + V850E2_SCR(3) = 0x21A9; + V850E2_RFS(3) = 0x8121; + + v850e_intc_disable_irqs (); } void __init mach_setup (char **cmdline) diff --git a/arch/v850/kernel/fpga85e2c.c b/arch/v850/kernel/fpga85e2c.c index 3f6aad39ed77..290d564855ca 100644 --- a/arch/v850/kernel/fpga85e2c.c +++ b/arch/v850/kernel/fpga85e2c.c @@ -46,7 +46,7 @@ void __init mach_early_init (void) /* Set bus sizes: CS0 32-bit, CS1 16-bit, CS7 8-bit, everything else 32-bit. */ - BSC = 0x2AA6; + V850E2_BSC = 0x2AA6; for (i = 2; i <= 6; i++) CSDEV(i) = 0; /* 32 bit */ diff --git a/arch/v850/kernel/sim85e2.c b/arch/v850/kernel/sim85e2.c new file mode 100644 index 000000000000..9dbb35482ba5 --- /dev/null +++ b/arch/v850/kernel/sim85e2.c @@ -0,0 +1,211 @@ +/* + * arch/v850/kernel/sim85e2.c -- Machine-specific stuff for + * V850E2 RTL simulator + * + * Copyright (C) 2002,03 NEC Electronics Corporation + * Copyright (C) 2002,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "mach.h" + + +/* There are 4 possible areas we can use: + + IRAM (1MB) is fast for instruction fetches, but slow for data + DRAM (1020KB) is fast for data, but slow for instructions + ERAM is cached, so should be fast for both insns and data + SDRAM is external DRAM, similar to ERAM +*/ + +#define INIT_MEMC_FOR_SDRAM +#define USE_SDRAM_AREA +#define KERNEL_IN_SDRAM_AREA + +#define DCACHE_MODE V850E2_CACHE_BTSC_DCM_WT +/*#define DCACHE_MODE V850E2_CACHE_BTSC_DCM_WB_ALLOC*/ + +#ifdef USE_SDRAM_AREA +#define RAM_START SDRAM_ADDR +#define RAM_END (SDRAM_ADDR + SDRAM_SIZE) +#else +/* When we use DRAM, we need to account for the fact that the end of it is + used for R0_RAM. */ +#define RAM_START DRAM_ADDR +#define RAM_END R0_RAM_ADDR +#endif + + +extern void memcons_setup (void); + + +#ifdef KERNEL_IN_SDRAM_AREA +#define EARLY_INIT_SECTION_ATTR __attribute__ ((section (".early.text"))) +#else +#define EARLY_INIT_SECTION_ATTR __init +#endif + +void EARLY_INIT_SECTION_ATTR mach_early_init (void) +{ + extern int panic_timeout; + + /* The sim85e2 simulator tracks `undefined' values, so to make + debugging easier, we begin by zeroing out all otherwise + undefined registers. This is not strictly necessary. + + The registers we zero are: + Every GPR except: + stack-pointer (r3) + task-pointer (r16) + our return addr (r31) + Every system register (SPR) that we know about except for + the PSW (SPR 5), which we zero except for the + disable-interrupts bit. + */ + + /* GPRs */ + asm volatile (" mov r0, r1 ; mov r0, r2 "); + asm volatile ("mov r0, r4 ; mov r0, r5 ; mov r0, r6 ; mov r0, r7 "); + asm volatile ("mov r0, r8 ; mov r0, r9 ; mov r0, r10; mov r0, r11"); + asm volatile ("mov r0, r12; mov r0, r13; mov r0, r14; mov r0, r15"); + asm volatile (" mov r0, r17; mov r0, r18; mov r0, r19"); + asm volatile ("mov r0, r20; mov r0, r21; mov r0, r22; mov r0, r23"); + asm volatile ("mov r0, r24; mov r0, r25; mov r0, r26; mov r0, r27"); + asm volatile ("mov r0, r28; mov r0, r29; mov r0, r30"); + + /* SPRs */ + asm volatile ("ldsr r0, 0; ldsr r0, 1; ldsr r0, 2; ldsr r0, 3"); + asm volatile ("ldsr r0, 4"); + asm volatile ("addi 0x20, r0, r1; ldsr r1, 5"); /* PSW */ + asm volatile ("ldsr r0, 16; ldsr r0, 17; ldsr r0, 18; ldsr r0, 19"); + asm volatile ("ldsr r0, 20"); + + +#ifdef INIT_MEMC_FOR_SDRAM + /* Settings for SDRAM controller. */ + V850E2_VSWC = 0x0042; + V850E2_BSC = 0x9286; + V850E2_BCT(0) = 0xb000; /* was: 0 */ + V850E2_BCT(1) = 0x000b; + V850E2_ASC = 0; + V850E2_LBS = 0xa9aa; /* was: 0xaaaa */ + V850E2_LBC(0) = 0; + V850E2_LBC(1) = 0; /* was: 0x3 */ + V850E2_BCC = 0; + V850E2_RFS(4) = 0x800a; /* was: 0xf109 */ + V850E2_SCR(4) = 0x2091; /* was: 0x20a1 */ + V850E2_RFS(3) = 0x800c; + V850E2_SCR(3) = 0x20a1; + V850E2_DWC(0) = 0; + V850E2_DWC(1) = 0; +#endif + +#if 0 +#ifdef CONFIG_V850E2_SIM85E2S + /* Turn on the caches. */ + V850E2_CACHE_BTSC = V850E2_CACHE_BTSC_ICM | DCACHE_MODE; + V850E2_BHC = 0x1010; +#elif CONFIG_V850E2_SIM85E2C + V850E2_CACHE_BTSC |= (V850E2_CACHE_BTSC_ICM | V850E2_CACHE_BTSC_DCM0); + V850E2_BUSM_BHC = 0xFFFF; +#endif +#else + V850E2_BHC = 0; +#endif + + /* Don't stop the simulator at `halt' instructions. */ + SIM85E2_NOTHAL = 1; + + /* Ensure that the simulator halts on a panic, instead of going + into an infinite loop inside the panic function. */ + panic_timeout = -1; +} + +void __init mach_setup (char **cmdline) +{ + memcons_setup (); +} + +void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len) +{ + *ram_start = RAM_START; + *ram_len = RAM_END - RAM_START; +} + +void __init mach_reserve_bootmem () +{ + extern char _root_fs_image_start, _root_fs_image_end; + u32 root_fs_image_start = (u32)&_root_fs_image_start; + u32 root_fs_image_end = (u32)&_root_fs_image_end; + + /* Reserve the memory used by the root filesystem image if it's + in RAM. */ + if (root_fs_image_end > root_fs_image_start + && root_fs_image_start >= RAM_START + && root_fs_image_start < RAM_END) + reserve_bootmem (root_fs_image_start, + root_fs_image_end - root_fs_image_start); +} + +void __init mach_sched_init (struct irqaction *timer_action) +{ + /* The simulator actually cycles through all interrupts + periodically. We just pay attention to IRQ0, which gives us + 1/64 the rate of the periodic interrupts. */ + setup_irq (0, timer_action); +} + +void mach_gettimeofday (struct timespec *tv) +{ + tv->tv_sec = 0; + tv->tv_nsec = 0; +} + +/* Interrupts */ + +struct v850e_intc_irq_init irq_inits[] = { + { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, + { 0 } +}; +struct hw_interrupt_type hw_itypes[1]; + +/* Initialize interrupts. */ +void __init mach_init_irqs (void) +{ + v850e_intc_init_irq_types (irq_inits, hw_itypes); +} + + +void machine_halt (void) __attribute__ ((noreturn)); +void machine_halt (void) +{ + SIM85E2_SIMFIN = 0; /* Halt immediately. */ + for (;;) {} +} + +void machine_restart (char *__unused) +{ + machine_halt (); +} + +void machine_power_off (void) +{ + machine_halt (); +} diff --git a/arch/v850/kernel/sim85e2c.c b/arch/v850/kernel/sim85e2c.c deleted file mode 100644 index 3eaf4fe72ef3..000000000000 --- a/arch/v850/kernel/sim85e2c.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * arch/v850/kernel/sim85e2c.c -- Machine-specific stuff for - * V850E2 RTL simulator - * - * Copyright (C) 2002 NEC Corporation - * Copyright (C) 2002 Miles Bader - * - * 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. - * - * Written by Miles Bader - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "mach.h" - -extern void memcons_setup (void); - - -void __init mach_early_init (void) -{ - extern int panic_timeout; - - /* Don't stop the simulator at `halt' instructions. */ - NOTHAL = 1; - - /* The sim85e2c simulator tracks `undefined' values, so to make - debugging easier, we begin by zeroing out all otherwise - undefined registers. This is not strictly necessary. - - The registers we zero are: - Every GPR except: - stack-pointer (r3) - task-pointer (r16) - our return addr (r31) - Every system register (SPR) that we know about except for - the PSW (SPR 5), which we zero except for the - disable-interrupts bit. - */ - - /* GPRs */ - asm volatile (" mov r0, r1 ; mov r0, r2 "); - asm volatile ("mov r0, r4 ; mov r0, r5 ; mov r0, r6 ; mov r0, r7 "); - asm volatile ("mov r0, r8 ; mov r0, r9 ; mov r0, r10; mov r0, r11"); - asm volatile ("mov r0, r12; mov r0, r13; mov r0, r14; mov r0, r15"); - asm volatile (" mov r0, r17; mov r0, r18; mov r0, r19"); - asm volatile ("mov r0, r20; mov r0, r21; mov r0, r22; mov r0, r23"); - asm volatile ("mov r0, r24; mov r0, r25; mov r0, r26; mov r0, r27"); - asm volatile ("mov r0, r28; mov r0, r29; mov r0, r30"); - - /* SPRs */ - asm volatile ("ldsr r0, 0; ldsr r0, 1; ldsr r0, 2; ldsr r0, 3"); - asm volatile ("ldsr r0, 4"); - asm volatile ("addi 0x20, r0, r1; ldsr r1, 5"); /* PSW */ - asm volatile ("ldsr r0, 16; ldsr r0, 17; ldsr r0, 18; ldsr r0, 19"); - asm volatile ("ldsr r0, 20"); - - /* Turn on the caches. */ - NA85E2C_CACHE_BTSC - |= (NA85E2C_CACHE_BTSC_ICM | NA85E2C_CACHE_BTSC_DCM0); - NA85E2C_BUSM_BHC = 0xFFFF; - - /* Ensure that the simulator halts on a panic, instead of going - into an infinite loop inside the panic function. */ - panic_timeout = -1; -} - -void __init mach_setup (char **cmdline) -{ - memcons_setup (); -} - -void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len) -{ - /* There are 3 possible areas we can use: - IRAM (1MB) is fast for instruction fetches, but slow for data - DRAM (1020KB) is fast for data, but slow for instructions - ERAM is cached, so should be fast for both insns and data, - _but_ currently only supports write-through caching, so - writes are slow. - Since there's really no area that's good for general kernel - use, we use DRAM -- it won't be good for user programs - (which will be loaded into kernel allocated memory), but - currently we're more concerned with testing the kernel. */ - *ram_start = DRAM_ADDR; - *ram_len = R0_RAM_ADDR - DRAM_ADDR; -} - -void __init mach_sched_init (struct irqaction *timer_action) -{ - /* The simulator actually cycles through all interrupts - periodically. We just pay attention to IRQ0, which gives us - 1/64 the rate of the periodic interrupts. */ - setup_irq (0, timer_action); -} - -void mach_gettimeofday (struct timespec *tv) -{ - tv->tv_sec = 0; - tv->tv_nsec = 0; -} - -/* Interrupts */ - -struct nb85e_intc_irq_init irq_inits[] = { - { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, - { 0 } -}; -struct hw_interrupt_type hw_itypes[1]; - -/* Initialize interrupts. */ -void __init mach_init_irqs (void) -{ - nb85e_intc_init_irq_types (irq_inits, hw_itypes); -} - - -void machine_halt (void) __attribute__ ((noreturn)); -void machine_halt (void) -{ - SIMFIN = 0; /* Halt immediately. */ - for (;;) {} -} - -void machine_restart (char *__unused) -{ - machine_halt (); -} - -void machine_power_off (void) -{ - machine_halt (); -} diff --git a/arch/v850/kernel/v850e2_cache.c b/arch/v850/kernel/v850e2_cache.c new file mode 100644 index 000000000000..4570312c689c --- /dev/null +++ b/arch/v850/kernel/v850e2_cache.c @@ -0,0 +1,127 @@ +/* + * arch/v850/kernel/v850e2_cache.c -- Cache control for V850E2 cache + * memories + * + * Copyright (C) 2003 NEC Electronics Corporation + * Copyright (C) 2003 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#include + +#include + +/* Cache operations we can do. The encoding corresponds directly to the + value we need to write into the COPR register. */ +enum cache_op { + OP_SYNC_IF_DIRTY = V850E2_CACHE_COPR_CFC(0), /* 000 */ + OP_SYNC_IF_VALID = V850E2_CACHE_COPR_CFC(1), /* 001 */ + OP_SYNC_IF_VALID_AND_CLEAR = V850E2_CACHE_COPR_CFC(3), /* 011 */ + OP_WAY_CLEAR = V850E2_CACHE_COPR_CFC(4), /* 100 */ + OP_FILL = V850E2_CACHE_COPR_CFC(5), /* 101 */ + OP_CLEAR = V850E2_CACHE_COPR_CFC(6), /* 110 */ + OP_CREATE_DIRTY = V850E2_CACHE_COPR_CFC(7) /* 111 */ +}; + +/* Which cache to use. This encoding also corresponds directly to the + value we need to write into the COPR register. */ +enum cache { + ICACHE = 0, + DCACHE = V850E2_CACHE_COPR_LBSL +}; + +/* Returns ADDR rounded down to the beginning of its cache-line. */ +#define CACHE_LINE_ADDR(addr) \ + ((addr) & ~(V850E2_CACHE_LINE_SIZE - 1)) +/* Returns END_ADDR rounded up to the `limit' of its cache-line. */ +#define CACHE_LINE_END_ADDR(end_addr) \ + CACHE_LINE_ADDR(end_addr + (V850E2_CACHE_LINE_SIZE - 1)) + + +/* Low-level cache ops. */ + +/* Apply cache-op OP to all entries in CACHE. */ +static inline void cache_op_all (enum cache_op op, enum cache cache) +{ + int cmd = op | cache | V850E2_CACHE_COPR_WSLE | V850E2_CACHE_COPR_STRT; + + if (op != OP_WAY_CLEAR) { + /* The WAY_CLEAR operation does the whole way, but other + ops take begin-index and count params; we just indicate + the entire cache. */ + V850E2_CACHE_CADL = 0; + V850E2_CACHE_CADH = 0; + V850E2_CACHE_CCNT = V850E2_CACHE_WAY_SIZE - 1; + } + + V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(0); /* way 0 */ + V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(1); /* way 1 */ + V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(2); /* way 2 */ + V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(3); /* way 3 */ +} + +/* Apply cache-op OP to all entries in CACHE covering addresses ADDR + through ADDR+LEN. */ +static inline void cache_op_range (enum cache_op op, u32 addr, u32 len, + enum cache cache) +{ + u32 start = CACHE_LINE_ADDR (addr); + u32 end = CACHE_LINE_END_ADDR (addr + len); + u32 num_lines = (end - start) >> V850E2_CACHE_LINE_SIZE_BITS; + + V850E2_CACHE_CADL = start & 0xFFFF; + V850E2_CACHE_CADH = start >> 16; + V850E2_CACHE_CCNT = num_lines - 1; + + V850E2_CACHE_COPR = op | cache | V850E2_CACHE_COPR_STRT; +} + + +/* High-level ops. */ + +static void cache_exec_after_store_all (void) +{ + cache_op_all (OP_SYNC_IF_DIRTY, DCACHE); + cache_op_all (OP_WAY_CLEAR, ICACHE); +} + +static void cache_exec_after_store_range (u32 start, u32 len) +{ + cache_op_range (OP_SYNC_IF_DIRTY, start, len, DCACHE); + cache_op_range (OP_CLEAR, start, len, ICACHE); +} + + +/* Exported functions. */ + +void flush_icache (void) +{ + cache_exec_after_store_all (); +} + +void flush_icache_range (unsigned long start, unsigned long end) +{ + cache_exec_after_store_range (start, end - start); +} + +void flush_icache_page (struct vm_area_struct *vma, struct page *page) +{ + cache_exec_after_store_range (page_to_virt (page), PAGE_SIZE); +} + +void flush_icache_user_range (struct vm_area_struct *vma, struct page *page, + unsigned long addr, int len) +{ + cache_exec_after_store_range (addr, len); +} + +void flush_cache_sigtramp (unsigned long addr) +{ + /* For the exact size, see signal.c, but 16 bytes should be enough. */ + cache_exec_after_store_range (addr, 16); +} diff --git a/arch/v850/sim85e2.ld b/arch/v850/sim85e2.ld new file mode 100644 index 000000000000..26b8bad11e81 --- /dev/null +++ b/arch/v850/sim85e2.ld @@ -0,0 +1,44 @@ +/* Linker script for the sim85e2c simulator, which is a verilog simulation of + the V850E2 NA85E2C cpu core (CONFIG_V850E2_SIM85E2C). */ + +MEMORY { + /* 1MB of `instruction RAM', starting at 0. + Instruction fetches are much faster from IRAM than from DRAM. + This should match IRAM_ADDR in "include/asm-v580/sim85e2c.h". */ + IRAM : ORIGIN = 0x00000000, LENGTH = 0x00100000 + + /* 1MB of `data RAM', below and contiguous with the I/O space. + Data fetches are much faster from DRAM than from IRAM. + This should match DRAM_ADDR in "include/asm-v580/sim85e2c.h". */ + DRAM : ORIGIN = 0xfff00000, LENGTH = 0x000ff000 + /* We have to load DRAM at a mirror-address of 0x1ff00000, + because the simulator's preprocessing script isn't smart + enough to deal with the above LMA. */ + DRAM_LOAD : ORIGIN = 0x1ff00000, LENGTH = 0x000ff000 + + /* `external ram' (CS1 area), comes after IRAM. + This should match ERAM_ADDR in "include/asm-v580/sim85e2c.h". */ + ERAM : ORIGIN = 0x00100000, LENGTH = 0x07f00000 + + /* Dynamic RAM; uses memory controller. */ + /* SDRAM : ORIGIN = 0x10000000, LENGTH = 0x01000000 */ + SDRAM : ORIGIN = 0x10000000, LENGTH = 0x00200000/*use 2MB*/ +} + +SECTIONS { + .iram : { + INTV_CONTENTS + *arch/v850/kernel/head.o + *(.early.text) + } > IRAM + .dram : { + _memcons_output = . ; + . = . + 0x8000 ; + _memcons_output_end = . ; + } > DRAM + .sdram : { + /* We stick console output into a buffer here. */ + RAMK_KRAM_CONTENTS + ROOT_FS_CONTENTS + } > SDRAM +} diff --git a/arch/v850/sim85e2c.ld b/arch/v850/sim85e2c.ld deleted file mode 100644 index b10cb1f38ebf..000000000000 --- a/arch/v850/sim85e2c.ld +++ /dev/null @@ -1,44 +0,0 @@ -/* Linker script for the sim85e2c simulator, which is a verilog simulation of - the V850E2 NA85E2C cpu core (CONFIG_V850E2_SIM85E2C). */ - -MEMORY { - /* 1MB of `instruction RAM', starting at 0. - Instruction fetches are much faster from IRAM than from DRAM. - This should match IRAM_ADDR in "include/asm-v580/sim85e2c.h". */ - IRAM : ORIGIN = 0x00000000, LENGTH = 0x00100000 - - /* 1MB of `data RAM', below and contiguous with the I/O space. - Data fetches are much faster from DRAM than from IRAM. - This should match DRAM_ADDR in "include/asm-v580/sim85e2c.h". */ - DRAM : ORIGIN = 0xfff00000, LENGTH = 0x000ff000 - /* We have to load DRAM at a mirror-address of 0x1ff00000, - because the simulator's preprocessing script isn't smart - enough to deal with the above LMA. */ - DRAM_LOAD : ORIGIN = 0x1ff00000, LENGTH = 0x000ff000 - - /* `external ram' (CS1 area), comes after IRAM. - This should match ERAM_ADDR in "include/asm-v580/sim85e2c.h". */ - ERAM : ORIGIN = 0x00100000, LENGTH = 0x07f00000 -} - -SECTIONS { - .iram : { - INTV_CONTENTS - TEXT_CONTENTS - RAMK_INIT_CONTENTS - } > IRAM - .data : { - __kram_start = . ; - DATA_CONTENTS - BSS_CONTENTS - ROOT_FS_CONTENTS - - /* We stick console output into a buffer here. */ - _memcons_output = . ; - . = . + 0x8000 ; - _memcons_output_end = . ; - - __kram_end = . ; - BOOTMAP_CONTENTS - } > DRAM AT> DRAM_LOAD -} diff --git a/arch/v850/vmlinux.lds.S b/arch/v850/vmlinux.lds.S index e27b7970ddeb..3396649e92ac 100644 --- a/arch/v850/vmlinux.lds.S +++ b/arch/v850/vmlinux.lds.S @@ -206,8 +206,8 @@ _jiffies = _jiffies_64 ; # include "sim.ld" #endif -#ifdef CONFIG_V850E2_SIM85E2C -# include "sim85e2c.ld" +#ifdef CONFIG_V850E2_SIM85E2 +# include "sim85e2.ld" #endif #ifdef CONFIG_V850E2_FPGA85E2C diff --git a/include/asm-v850/anna.h b/include/asm-v850/anna.h index 1bb65a29c0b0..3be77d5ecfce 100644 --- a/include/asm-v850/anna.h +++ b/include/asm-v850/anna.h @@ -1,8 +1,8 @@ /* * include/asm-v850/anna.h -- Anna V850E2 evaluation cpu chip/board * - * Copyright (C) 2001,2002 NEC Corporation - * Copyright (C) 2001,2002 Miles Bader + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader * * 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 @@ -14,8 +14,9 @@ #ifndef __V850_ANNA_H__ #define __V850_ANNA_H__ +#include /* Based on V850E2 core. */ + -#define CPU_ARCH "v850e2" #define CPU_MODEL "v850e2/anna" #define CPU_MODEL_LONG "NEC V850E2/Anna" #define PLATFORM "anna" @@ -48,30 +49,6 @@ /* Anna specific control registers. */ -#define ANNA_CSC_ADDR(n) (0xFFFFF060 + (n) * 2) -#define ANNA_CSC(n) (*(volatile u16 *)ANNA_CSC_ADDR(n)) -#define ANNA_BPC_ADDR 0xFFFFF064 -#define ANNA_BPC (*(volatile u16 *)ANNA_BPC_ADDR) -#define ANNA_BSC_ADDR 0xFFFFF066 -#define ANNA_BSC (*(volatile u16 *)ANNA_BSC_ADDR) -#define ANNA_BEC_ADDR 0xFFFFF068 -#define ANNA_BEC (*(volatile u16 *)ANNA_BEC_ADDR) -#define ANNA_BHC_ADDR 0xFFFFF06A -#define ANNA_BHC (*(volatile u16 *)ANNA_BHC_ADDR) -#define ANNA_BCT_ADDR(n) (0xFFFFF480 + (n) * 2) -#define ANNA_BCT(n) (*(volatile u16 *)ANNA_BCT_ADDR(n)) -#define ANNA_DWC_ADDR(n) (0xFFFFF484 + (n) * 2) -#define ANNA_DWC(n) (*(volatile u16 *)ANNA_DWC_ADDR(n)) -#define ANNA_BCC_ADDR 0xFFFFF488 -#define ANNA_BCC (*(volatile u16 *)ANNA_BCC_ADDR) -#define ANNA_ASC_ADDR 0xFFFFF48A -#define ANNA_ASC (*(volatile u16 *)ANNA_ASC_ADDR) -#define ANNA_LBS_ADDR 0xFFFFF48E -#define ANNA_LBS (*(volatile u16 *)ANNA_LBS_ADDR) -#define ANNA_SCR3_ADDR 0xFFFFF4AC -#define ANNA_SCR3 (*(volatile u16 *)ANNA_SCR3_ADDR) -#define ANNA_RFS3_ADDR 0xFFFFF4AE -#define ANNA_RFS3 (*(volatile u16 *)ANNA_RFS3_ADDR) #define ANNA_ILBEN_ADDR 0xFFFFF7F2 #define ANNA_ILBEN (*(volatile u16 *)ANNA_ILBEN_ADDR) @@ -85,9 +62,6 @@ #define ANNA_PORT_PM(n) (*(volatile u8 *)ANNA_PORT_PM_ADDR(n)) -/* NB85E-style interrupt system. */ -#include - /* Hardware-specific interrupt numbers (in the kernel IRQ namespace). */ #define IRQ_INTP(n) (n) /* Pnnn (pin) interrupts 0-15 */ #define IRQ_INTP_NUM 16 diff --git a/include/asm-v850/fpga85e2c.h b/include/asm-v850/fpga85e2c.h index 77d7d22e5ee5..d32f04504b13 100644 --- a/include/asm-v850/fpga85e2c.h +++ b/include/asm-v850/fpga85e2c.h @@ -15,11 +15,10 @@ #ifndef __V850_FPGA85E2C_H__ #define __V850_FPGA85E2C_H__ - +#include #include -#define CPU_ARCH "v850e2" #define CPU_MODEL "v850e2/fpga85e2c" #define CPU_MODEL_LONG "NEC V850E2/NA85E2C" #define PLATFORM "fpga85e2c" @@ -42,27 +41,6 @@ #define CSDEV_ADDR(n) (0xFFE80110 + 2*(n)) #define CSDEV(n) (*(volatile unsigned char *)CSDEV_ADDR (n)) -/* The BSC register controls bus-sizing. Each memory area CSn uses a pair - of bits N*2 and N*2+1, where 00 means an 8-bit bus size, 01 16-bit, and - 10 32-bit. */ -#define BSC_ADDR 0xFFFFF066 -#define BSC (*(volatile unsigned short *)BSC_ADDR) - -#define DWC_ADDR(n) (0xFFFFF484 + 2*(n)) -#define DWC(n) (*(volatile unsigned short *)DWC_ADDR (n)) - -#define ASC_ADDR 0xFFFFF48A -#define ASC (*(volatile unsigned short *)ASC_ADDR) - -#define BTSC_ADDR 0xFFFFF070 -#define BTSC (*(volatile unsigned short *)BTSC_ADDR) - -#define BHC_ADDR 0xFFFFF06A -#define BHC (*(volatile unsigned short *)BHC_ADDR) - - -/* NB85E-style interrupt system. */ -#include /* Timer interrupts 0-3, interrupt at intervals from CLK/4096 to CLK/16384. */ #define IRQ_RPU(n) (60 + (n)) diff --git a/include/asm-v850/machdep.h b/include/asm-v850/machdep.h index 3befbff5c29d..98d8bf63970e 100644 --- a/include/asm-v850/machdep.h +++ b/include/asm-v850/machdep.h @@ -51,6 +51,9 @@ #ifdef CONFIG_V850E2_SIM85E2C #include #endif +#ifdef CONFIG_V850E2_SIM85E2S +#include +#endif #ifdef CONFIG_V850E2_FPGA85E2C #include #endif diff --git a/include/asm-v850/sim85e2.h b/include/asm-v850/sim85e2.h new file mode 100644 index 000000000000..8cfb5eb13303 --- /dev/null +++ b/include/asm-v850/sim85e2.h @@ -0,0 +1,79 @@ +/* + * include/asm-v850/sim85e2.h -- Machine-dependent defs for + * V850E2 RTL simulator + * + * Copyright (C) 2002,03 NEC Electronics Corporation + * Copyright (C) 2002,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#ifndef __V850_SIM85E2_H__ +#define __V850_SIM85E2_H__ + + +#include /* Based on V850E2 core. */ + + +/* Various memory areas supported by the simulator. + These should match the corresponding definitions in the linker script. */ + +/* `instruction RAM'; instruction fetches are much faster from IRAM than + from DRAM. */ +#define IRAM_ADDR 0 +#define IRAM_SIZE 0x00100000 /* 1MB */ +/* `data RAM', below and contiguous with the I/O space. + Data fetches are much faster from DRAM than from IRAM. */ +#define DRAM_ADDR 0xfff00000 +#define DRAM_SIZE 0x000ff000 /* 1020KB */ +/* `external ram'. Unlike the above RAM areas, this memory is cached, + so both instruction and data fetches should be (mostly) fast -- + however, currently only write-through caching is supported, so writes + to ERAM will be slow. */ +#define ERAM_ADDR 0x00100000 +#define ERAM_SIZE 0x07f00000 /* 127MB (max) */ +/* Dynamic RAM; uses memory controller. */ +#define SDRAM_ADDR 0x10000000 +#if 0 +#define SDRAM_SIZE 0x01000000 /* 16MB */ +#else +#define SDRAM_SIZE 0x00200000 /* Only use 2MB for testing */ +#endif + + +/* Simulator specific control registers. */ +/* NOTHAL controls whether the simulator will stop at a `halt' insn. */ +#define SIM85E2_NOTHAL_ADDR 0xffffff22 +#define SIM85E2_NOTHAL (*(volatile u8 *)SIM85E2_NOTHAL_ADDR) +/* The simulator will stop N cycles after N is written to SIMFIN. */ +#define SIM85E2_SIMFIN_ADDR 0xffffff24 +#define SIM85E2_SIMFIN (*(volatile u16 *)SIM85E2_SIMFIN_ADDR) + + +/* For */ +#define NUM_CPU_IRQS 64 + + +/* For */ +#define PAGE_OFFSET SDRAM_ADDR + + +/* For */ +/* `R0 RAM', used for a few miscellaneous variables that must be accessible + using a load instruction relative to R0. The sim85e2 simulator + actually puts 1020K of RAM from FFF00000 to FFFFF000, so we arbitarily + choose a small portion at the end of that. */ +#define R0_RAM_ADDR 0xFFFFE000 + + +/* For */ +#ifndef HZ +#define HZ 24 /* Minimum supported frequency. */ +#endif + + +#endif /* __V850_SIM85E2_H__ */ diff --git a/include/asm-v850/sim85e2c.h b/include/asm-v850/sim85e2c.h index 12b87873bdef..eee543ff3af8 100644 --- a/include/asm-v850/sim85e2c.h +++ b/include/asm-v850/sim85e2c.h @@ -15,78 +15,12 @@ #ifndef __V850_SIM85E2C_H__ #define __V850_SIM85E2C_H__ +/* Use generic sim85e2 settings, other than the various names. */ +#include -#define CPU_ARCH "v850e2" #define CPU_MODEL "v850e2" #define CPU_MODEL_LONG "NEC V850E2" #define PLATFORM "sim85e2c" #define PLATFORM_LONG "SIM85E2C V850E2 simulator" - -/* Various memory areas supported by the simulator. - These should match the corresponding definitions in the linker script. */ - -/* `instruction RAM'; instruction fetches are much faster from IRAM than - from DRAM. */ -#define IRAM_ADDR 0 -#define IRAM_SIZE 0x00100000 /* 1MB */ -/* `data RAM', below and contiguous with the I/O space. - Data fetches are much faster from DRAM than from IRAM. */ -#define DRAM_ADDR 0xfff00000 -#define DRAM_SIZE 0x000ff000 /* 1020KB */ -/* `external ram'. Unlike the above RAM areas, this memory is cached, - so both instruction and data fetches should be (mostly) fast -- - however, currently only write-through caching is supported, so writes - to ERAM will be slow. */ -#define ERAM_ADDR 0x00100000 -#define ERAM_SIZE 0x07f00000 /* 127MB (max) */ - - -/* CPU core control registers; these should be expanded and moved into - separate header files when we support some other processors based on - the same E2 core. */ -/* Bus Transaction Control Register */ -#define NA85E2C_CACHE_BTSC_ADDR 0xfffff070 -#define NA85E2C_CACHE_BTSC (*(volatile unsigned short *)NA85E2C_CACHE_BTSC_ADDR) -#define NA85E2C_CACHE_BTSC_ICM 0x1 /* icache enable */ -#define NA85E2C_CACHE_BTSC_DCM0 0x4 /* dcache enable, bit 0 */ -#define NA85E2C_CACHE_BTSC_DCM1 0x8 /* dcache enable, bit 1 */ -/* Cache Configuration Register */ -#define NA85E2C_BUSM_BHC_ADDR 0xfffff06a -#define NA85E2C_BUSM_BHC (*(volatile unsigned short *)NA85E2C_BUSM_BHC_ADDR) - -/* Simulator specific control registers. */ -/* NOTHAL controls whether the simulator will stop at a `halt' insn. */ -#define NOTHAL_ADDR 0xffffff22 -#define NOTHAL (*(volatile unsigned char *)NOTHAL_ADDR) -/* The simulator will stop N cycles after N is written to SIMFIN. */ -#define SIMFIN_ADDR 0xffffff24 -#define SIMFIN (*(volatile unsigned short *)SIMFIN_ADDR) - - -/* The simulator has an nb85e-style interrupt system. */ -#include - -/* For */ -#define NUM_CPU_IRQS 64 - - -/* For */ -#define PAGE_OFFSET DRAM_ADDR - - -/* For */ -/* `R0 RAM', used for a few miscellaneous variables that must be accessible - using a load instruction relative to R0. The sim85e2c simulator - actually puts 1020K of RAM from FFF00000 to FFFFF000, so we arbitarily - choose a small portion at the end of that. */ -#define R0_RAM_ADDR 0xFFFFE000 - - -/* For */ -#ifndef HZ -#define HZ 24 /* Minimum supported frequency. */ -#endif - - #endif /* __V850_SIM85E2C_H__ */ diff --git a/include/asm-v850/sim85e2s.h b/include/asm-v850/sim85e2s.h new file mode 100644 index 000000000000..ee066d5d3c51 --- /dev/null +++ b/include/asm-v850/sim85e2s.h @@ -0,0 +1,28 @@ +/* + * include/asm-v850/sim85e2s.h -- Machine-dependent defs for + * V850E2 RTL simulator + * + * Copyright (C) 2003 NEC Electronics Corporation + * Copyright (C) 2003 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#ifndef __V850_SIM85E2S_H__ +#define __V850_SIM85E2S_H__ + +#include /* Use generic sim85e2 settings. */ +#if 0 +#include /* + cache */ +#endif + +#define CPU_MODEL "v850e2" +#define CPU_MODEL_LONG "NEC V850E2" +#define PLATFORM "sim85e2s" +#define PLATFORM_LONG "SIM85E2S V850E2 simulator" + +#endif /* __V850_SIM85E2S_H__ */ diff --git a/include/asm-v850/v850e2.h b/include/asm-v850/v850e2.h new file mode 100644 index 000000000000..48680408ab7e --- /dev/null +++ b/include/asm-v850/v850e2.h @@ -0,0 +1,69 @@ +/* + * include/asm-v850/v850e2.h -- Machine-dependent defs for V850E2 CPUs + * + * Copyright (C) 2002,03 NEC Electronics Corporation + * Copyright (C) 2002,03 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#ifndef __V850_V850E2_H__ +#define __V850_V850E2_H__ + +#include /* v850e-style interrupt system. */ + + +#define CPU_ARCH "v850e2" + + +/* Control registers. */ + +/* Chip area select control */ +#define V850E2_CSC_ADDR(n) (0xFFFFF060 + (n) * 2) +#define V850E2_CSC(n) (*(volatile u16 *)V850E2_CSC_ADDR(n)) +/* I/O area select control */ +#define V850E2_BPC_ADDR 0xFFFFF064 +#define V850E2_BPC (*(volatile u16 *)V850E2_BPC_ADDR) +/* Bus size configuration */ +#define V850E2_BSC_ADDR 0xFFFFF066 +#define V850E2_BSC (*(volatile u16 *)V850E2_BSC_ADDR) +/* Endian configuration */ +#define V850E2_BEC_ADDR 0xFFFFF068 +#define V850E2_BEC (*(volatile u16 *)V850E2_BEC_ADDR) +/* Cache configuration */ +#define V850E2_BHC_ADDR 0xFFFFF06A +#define V850E2_BHC (*(volatile u16 *)V850E2_BHC_ADDR) +/* NPB strobe-wait configuration */ +#define V850E2_VSWC_ADDR 0xFFFFF06E +#define V850E2_VSWC (*(volatile u16 *)V850E2_VSWC_ADDR) +/* Bus cycle type */ +#define V850E2_BCT_ADDR(n) (0xFFFFF480 + (n) * 2) +#define V850E2_BCT(n) (*(volatile u16 *)V850E2_BCT_ADDR(n)) +/* Data wait control */ +#define V850E2_DWC_ADDR(n) (0xFFFFF484 + (n) * 2) +#define V850E2_DWC(n) (*(volatile u16 *)V850E2_DWC_ADDR(n)) +/* Bus cycle control */ +#define V850E2_BCC_ADDR 0xFFFFF488 +#define V850E2_BCC (*(volatile u16 *)V850E2_BCC_ADDR) +/* Address wait control */ +#define V850E2_ASC_ADDR 0xFFFFF48A +#define V850E2_ASC (*(volatile u16 *)V850E2_ASC_ADDR) +/* Local bus sizing control */ +#define V850E2_LBS_ADDR 0xFFFFF48E +#define V850E2_LBS (*(volatile u16 *)V850E2_LBS_ADDR) +/* Line buffer control */ +#define V850E2_LBC_ADDR(n) (0xFFFFF490 + (n) * 2) +#define V850E2_LBC(n) (*(volatile u16 *)V850E2_LBC_ADDR(n)) +/* SDRAM configuration */ +#define V850E2_SCR_ADDR(n) (0xFFFFF4A0 + (n) * 4) +#define V850E2_SCR(n) (*(volatile u16 *)V850E2_SCR_ADDR(n)) +/* SDRAM refresh cycle control */ +#define V850E2_RFS_ADDR(n) (0xFFFFF4A2 + (n) * 4) +#define V850E2_RFS(n) (*(volatile u16 *)V850E2_RFS_ADDR(n)) + + +#endif /* __V850_V850E2_H__ */ diff --git a/include/asm-v850/v850e2_cache.h b/include/asm-v850/v850e2_cache.h new file mode 100644 index 000000000000..61acda1023e8 --- /dev/null +++ b/include/asm-v850/v850e2_cache.h @@ -0,0 +1,74 @@ +/* + * include/asm-v850/v850e2_cache_cache.h -- Cache control for V850E2 + * cache memories + * + * Copyright (C) 2003 NEC Electronics Corporation + * Copyright (C) 2003 Miles Bader + * + * 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. + * + * Written by Miles Bader + */ + +#ifndef __V850_V850E2_CACHE_H__ +#define __V850_V850E2_CACHE_H__ + +#include + + +/* Cache control registers. */ + +/* Bus Transaction Control */ +#define V850E2_CACHE_BTSC_ADDR 0xFFFFF070 +#define V850E2_CACHE_BTSC (*(volatile u16 *)V850E2_CACHE_BTSC_ADDR) +#define V850E2_CACHE_BTSC_ICM 0x0001 /* icache enable */ +#define V850E2_CACHE_BTSC_DCM0 0x0004 /* dcache enable, bit 0 */ +#define V850E2_CACHE_BTSC_DCM1 0x0008 /* dcache enable, bit 1 */ +#define V850E2_CACHE_BTSC_DCM_WT /* write-through */ \ + V850E2_CACHE_BTSC_DCM0 +#ifdef CONFIG_V850E2_V850E2S +# define V850E2_CACHE_BTSC_DCM_WB_NO_ALLOC /* write-back, non-alloc */ \ + V850E2_CACHE_BTSC_DCM1 +# define V850E2_CACHE_BTSC_DCM_WB_ALLOC /* write-back, non-alloc */ \ + (V850E2_CACHE_BTSC_DCM1 | V850E2_CACHE_BTSC_DCM0) +# define V850E2_CACHE_BTSC_ISEQ 0x0010 /* icache `address sequence mode' */ +# define V850E2_CACHE_BTSC_DSEQ 0x0020 /* dcache `address sequence mode' */ +# define V850E2_CACHE_BTSC_IRFC 0x0030 +# define V850E2_CACHE_BTSC_ILCD 0x4000 +# define V850E2_CACHE_BTSC_VABE 0x8000 +#endif /* CONFIG_V850E2_V850E2S */ + +/* Cache operation start address register (low-bits). */ +#define V850E2_CACHE_CADL_ADDR 0xFFFFF074 +#define V850E2_CACHE_CADL (*(volatile u16 *)V850E2_CACHE_CADL_ADDR) +/* Cache operation start address register (high-bits). */ +#define V850E2_CACHE_CADH_ADDR 0xFFFFF076 +#define V850E2_CACHE_CADH (*(volatile u16 *)V850E2_CACHE_CADH_ADDR) +/* Cache operation count register. */ +#define V850E2_CACHE_CCNT_ADDR 0xFFFFF078 +#define V850E2_CACHE_CCNT (*(volatile u16 *)V850E2_CACHE_CCNT_ADDR) +/* Cache operation specification register. */ +#define V850E2_CACHE_COPR_ADDR 0xFFFFF07A +#define V850E2_CACHE_COPR (*(volatile u16 *)V850E2_CACHE_COPR_ADDR) +#define V850E2_CACHE_COPR_STRT 0x0001 /* start cache operation */ +#define V850E2_CACHE_COPR_LBSL 0x0100 /* 0 = icache, 1 = dcache */ +#define V850E2_CACHE_COPR_WSLE 0x0200 /* operate on cache way */ +#define V850E2_CACHE_COPR_WSL(way) ((way) * 0x0400) /* way select */ +#define V850E2_CACHE_COPR_CFC(op) ((op) * 0x1000) /* cache function code */ + + +/* Size of a cache line in bytes. */ +#define V850E2_CACHE_LINE_SIZE_BITS 4 +#define V850E2_CACHE_LINE_SIZE (1 << V850E2_CACHE_LINE_SIZE_BITS) + +/* The size of each cache `way' in lines. */ +#define V850E2_CACHE_WAY_SIZE 256 + + +/* For */ +#define L1_CACHE_BYTES V850E2_CACHE_LINE_SIZE + + +#endif /* __V850_V850E2_CACHE_H__ */ -- cgit v1.2.3 From 992f6cd468e6a11ee3fd3e785032d72cbba67e64 Mon Sep 17 00:00:00 2001 From: Miles Bader Date: Thu, 17 Jul 2003 20:12:25 -0700 Subject: [PATCH] v850 miscellanea Some updated copyright noticed and an unnecessary variable deleted. --- arch/v850/kernel/gbus_int.c | 4 +--- include/asm-v850/asm.h | 2 +- include/asm-v850/processor.h | 2 +- include/asm-v850/ptrace.h | 2 +- include/asm-v850/stat.h | 2 +- include/asm-v850/system.h | 2 +- 6 files changed, 6 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/arch/v850/kernel/gbus_int.c b/arch/v850/kernel/gbus_int.c index 76533e757589..92918b8d89ef 100644 --- a/arch/v850/kernel/gbus_int.c +++ b/arch/v850/kernel/gbus_int.c @@ -113,9 +113,7 @@ static irqreturn_t gbus_int_handle_irq (int irq, void *dev_id, /* Only pay attention to enabled interrupts. */ status &= enable; if (status) { - unsigned base_irq - = IRQ_GBUS_INT (w * GBUS_INT_BITS_PER_WORD); - irq = base_irq; + irq = IRQ_GBUS_INT (w * GBUS_INT_BITS_PER_WORD); do { /* There's an active interrupt in word W, find out which one, and call its diff --git a/include/asm-v850/asm.h b/include/asm-v850/asm.h index 5b207f869017..bf1e785a5dde 100644 --- a/include/asm-v850/asm.h +++ b/include/asm-v850/asm.h @@ -1,7 +1,7 @@ /* * include/asm-v850/asm.h -- Macros for writing assembly code * - * Copyright (C) 2001,02,03 NEC Corporation + * Copyright (C) 2001,02,03 NEC Electronics Corporation * Copyright (C) 2001,02,03 Miles Bader * * This file is subject to the terms and conditions of the GNU General diff --git a/include/asm-v850/processor.h b/include/asm-v850/processor.h index 0d97022804ac..025202b4df7e 100644 --- a/include/asm-v850/processor.h +++ b/include/asm-v850/processor.h @@ -1,7 +1,7 @@ /* * include/asm-v850/processor.h * - * Copyright (C) 2001,02,03 NEC Corporation + * Copyright (C) 2001,02,03 NEC Electronics Corporation * Copyright (C) 2001,02,03 Miles Bader * * This file is subject to the terms and conditions of the GNU General diff --git a/include/asm-v850/ptrace.h b/include/asm-v850/ptrace.h index 8c7c759b42a3..62b2b3822d88 100644 --- a/include/asm-v850/ptrace.h +++ b/include/asm-v850/ptrace.h @@ -1,7 +1,7 @@ /* * include/asm-v850/ptrace.h -- Access to CPU registers * - * Copyright (C) 2001,02,03 NEC Corporation + * Copyright (C) 2001,02,03 NEC Electronics Corporation * Copyright (C) 2001,02,03 Miles Bader * * This file is subject to the terms and conditions of the GNU General diff --git a/include/asm-v850/stat.h b/include/asm-v850/stat.h index 09a7717eaed9..c68c60d06e2f 100644 --- a/include/asm-v850/stat.h +++ b/include/asm-v850/stat.h @@ -1,7 +1,7 @@ /* * include/asm-v850/stat.h -- v850 stat structure * - * Copyright (C) 2001,02,03 NEC Corporation + * Copyright (C) 2001,02,03 NEC Electronics Corporation * Copyright (C) 2001,02,03 Miles Bader * * This file is subject to the terms and conditions of the GNU General diff --git a/include/asm-v850/system.h b/include/asm-v850/system.h index a183308ec44d..072a997dc5a9 100644 --- a/include/asm-v850/system.h +++ b/include/asm-v850/system.h @@ -1,7 +1,7 @@ /* * include/asm-v850/system.h -- Low-level interrupt/thread ops * - * Copyright (C) 2001,02,03 NEC Corporation + * Copyright (C) 2001,02,03 NEC Electronics Corporation * Copyright (C) 2001,02,03 Miles Bader * * This file is subject to the terms and conditions of the GNU General -- cgit v1.2.3 From ae51f84cd5b1bb7715bfab828f6ee42081b665ba Mon Sep 17 00:00:00 2001 From: Miles Bader Date: Thu, 17 Jul 2003 20:12:33 -0700 Subject: [PATCH] Rename config option CONFIG_V850E_MA1_HIGHRES_TIMER on v850 This feature is not actually MA1-specific, so get rid of the `MA1' in the name. --- arch/v850/kernel/intv.S | 4 ++-- include/asm-v850/entry.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/arch/v850/kernel/intv.S b/arch/v850/kernel/intv.S index 3ccdd2beed8b..671e4c6150dd 100644 --- a/arch/v850/kernel/intv.S +++ b/arch/v850/kernel/intv.S @@ -16,7 +16,7 @@ #include #include -#ifdef CONFIG_V850E_MA1_HIGHRES_TIMER +#ifdef CONFIG_V850E_HIGHRES_TIMER #include #endif @@ -59,7 +59,7 @@ .section .intv.mach, "ax" .org 0x0 -#if defined (CONFIG_V850E_MA1_HIGHRES_TIMER) && defined (IRQ_INTCMD) +#if defined (CONFIG_V850E_HIGHRES_TIMER) && defined (IRQ_INTCMD) /* Interrupts before the highres timer interrupt. */ .rept IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT) diff --git a/include/asm-v850/entry.h b/include/asm-v850/entry.h index 7d239eb1cad0..d9df8ac48584 100644 --- a/include/asm-v850/entry.h +++ b/include/asm-v850/entry.h @@ -65,10 +65,10 @@ #define RESET_GUARD_ACTIVE 0xFAB4BEEF #endif /* CONFIG_RESET_GUARD */ -#ifdef CONFIG_V850E_MA1_HIGHRES_TIMER +#ifdef CONFIG_V850E_HIGHRES_TIMER #define HIGHRES_TIMER_SLOW_TICKS_ADDR (KERNEL_VAR_SPACE_ADDR + 32) #define HIGHRES_TIMER_SLOW_TICKS KERNEL_VAR (HIGHRES_TIMER_SLOW_TICKS_ADDR) -#endif /* CONFIG_V850E_MA1_HIGHRES_TIMER */ +#endif /* CONFIG_V850E_HIGHRES_TIMER */ #ifndef __ASSEMBLY__ -- cgit v1.2.3 From df038a2ec29da075bdd9c7d3214dca574dcc3305 Mon Sep 17 00:00:00 2001 From: Miles Bader Date: Thu, 17 Jul 2003 20:12:41 -0700 Subject: [PATCH] Update AS85EP1 port on v850 --- arch/v850/kernel/as85ep1.c | 6 ++---- include/asm-v850/as85ep1.h | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/arch/v850/kernel/as85ep1.c b/arch/v850/kernel/as85ep1.c index 94ea12259f3e..6529be52037a 100644 --- a/arch/v850/kernel/as85ep1.c +++ b/arch/v850/kernel/as85ep1.c @@ -98,8 +98,6 @@ void __init mach_setup (char **cmdline) AS85EP1_PORT_PMC (LEDS_PORT) = 0; /* Make the LEDs port an I/O port. */ AS85EP1_PORT_PM (LEDS_PORT) = 0; /* Make all the bits output pins. */ mach_tick = as85ep1_led_tick; - - ROOT_DEV = MKDEV (BLKMEM_MAJOR, 0); } void __init mach_get_physical_ram (unsigned long *ram_start, @@ -133,10 +131,10 @@ void __init mach_reserve_bootmem () root_fs_image_end - root_fs_image_start); } -void mach_gettimeofday (struct timeval *tv) +void mach_gettimeofday (struct timespec *tv) { tv->tv_sec = 0; - tv->tv_usec = 0; + tv->tv_nsec = 0; } void __init mach_sched_init (struct irqaction *timer_action) diff --git a/include/asm-v850/as85ep1.h b/include/asm-v850/as85ep1.h index ceeb5f09f703..659bc910ffd7 100644 --- a/include/asm-v850/as85ep1.h +++ b/include/asm-v850/as85ep1.h @@ -14,8 +14,9 @@ #ifndef __V850_AS85EP1_H__ #define __V850_AS85EP1_H__ +#include + -#define CPU_ARCH "v850e" #define CPU_MODEL "as85ep1" #define CPU_MODEL_LONG "NEC V850E/AS85EP1" #define PLATFORM "AS85EP1" @@ -86,9 +87,6 @@ #define AS85EP1_PORT_PMC(n) (*(volatile u8 *)AS85EP1_PORT_PMC_ADDR(n)) -/* NB85E-style interrupt system. */ -#include - /* Hardware-specific interrupt numbers (in the kernel IRQ namespace). */ #define IRQ_INTCCC(n) (0x0C + (n)) #define IRQ_INTCCC_NUM 8 -- cgit v1.2.3