diff options
Diffstat (limited to 'drivers')
108 files changed, 4428 insertions, 1300 deletions
diff --git a/drivers/base/Makefile b/drivers/base/Makefile index f12898d53078..e99471d3232b 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -8,6 +8,7 @@ obj-y += power/ obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_NUMA) += node.o obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o +obj-$(CONFIG_SMP) += topology.o ifeq ($(CONFIG_DEBUG_DRIVER),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/base/topology.c b/drivers/base/topology.c new file mode 100644 index 000000000000..915810f6237e --- /dev/null +++ b/drivers/base/topology.c @@ -0,0 +1,148 @@ +/* + * driver/base/topology.c - Populate sysfs with cpu topology information + * + * Written by: Zhang Yanmin, Intel Corporation + * + * Copyright (C) 2006, Intel Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include <linux/sysdev.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/cpu.h> +#include <linux/module.h> +#include <linux/topology.h> + +#define define_one_ro(_name) \ +static SYSDEV_ATTR(_name, 0444, show_##_name, NULL) + +#define define_id_show_func(name) \ +static ssize_t show_##name(struct sys_device *dev, char *buf) \ +{ \ + unsigned int cpu = dev->id; \ + return sprintf(buf, "%d\n", topology_##name(cpu)); \ +} + +#define define_siblings_show_func(name) \ +static ssize_t show_##name(struct sys_device *dev, char *buf) \ +{ \ + ssize_t len = -1; \ + unsigned int cpu = dev->id; \ + len = cpumask_scnprintf(buf, NR_CPUS+1, topology_##name(cpu)); \ + return (len + sprintf(buf + len, "\n")); \ +} + +#ifdef topology_physical_package_id +define_id_show_func(physical_package_id); +define_one_ro(physical_package_id); +#define ref_physical_package_id_attr &attr_physical_package_id.attr, +#else +#define ref_physical_package_id_attr +#endif + +#ifdef topology_core_id +define_id_show_func(core_id); +define_one_ro(core_id); +#define ref_core_id_attr &attr_core_id.attr, +#else +#define ref_core_id_attr +#endif + +#ifdef topology_thread_siblings +define_siblings_show_func(thread_siblings); +define_one_ro(thread_siblings); +#define ref_thread_siblings_attr &attr_thread_siblings.attr, +#else +#define ref_thread_siblings_attr +#endif + +#ifdef topology_core_siblings +define_siblings_show_func(core_siblings); +define_one_ro(core_siblings); +#define ref_core_siblings_attr &attr_core_siblings.attr, +#else +#define ref_core_siblings_attr +#endif + +static struct attribute *default_attrs[] = { + ref_physical_package_id_attr + ref_core_id_attr + ref_thread_siblings_attr + ref_core_siblings_attr + NULL +}; + +static struct attribute_group topology_attr_group = { + .attrs = default_attrs, + .name = "topology" +}; + +/* Add/Remove cpu_topology interface for CPU device */ +static int __cpuinit topology_add_dev(struct sys_device * sys_dev) +{ + sysfs_create_group(&sys_dev->kobj, &topology_attr_group); + return 0; +} + +static int __cpuinit topology_remove_dev(struct sys_device * sys_dev) +{ + sysfs_remove_group(&sys_dev->kobj, &topology_attr_group); + return 0; +} + +static int __cpuinit topology_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + struct sys_device *sys_dev; + + sys_dev = get_cpu_sysdev(cpu); + switch (action) { + case CPU_ONLINE: + topology_add_dev(sys_dev); + break; + case CPU_DEAD: + topology_remove_dev(sys_dev); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block topology_cpu_notifier = +{ + .notifier_call = topology_cpu_callback, +}; + +static int __cpuinit topology_sysfs_init(void) +{ + int i; + + for_each_online_cpu(i) { + topology_cpu_callback(&topology_cpu_notifier, CPU_ONLINE, + (void *)(long)i); + } + + register_cpu_notifier(&topology_cpu_notifier); + + return 0; +} + +device_initcall(topology_sysfs_init); + diff --git a/drivers/block/umem.c b/drivers/block/umem.c index a3614e6a68d0..4ada1268b40d 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -882,7 +882,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i card->card_number, dev->bus->number, dev->devfn); if (pci_set_dma_mask(dev, 0xffffffffffffffffLL) && - !pci_set_dma_mask(dev, 0xffffffffLL)) { + pci_set_dma_mask(dev, 0xffffffffLL)) { printk(KERN_WARNING "MM%d: NO suitable DMA found\n",num_cards); return -ENOMEM; } diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 39c61a71176e..cc7acf877dc0 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -1233,7 +1233,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) } info->idle_stats.recv_idle = jiffies; } - schedule_delayed_work(&tty->buf.work, 1); + tty_schedule_flip(tty); } /* end of service */ cy_writeb(base_addr+(CyRIR<<index), (save_xir & 0x3f)); @@ -1606,7 +1606,7 @@ cyz_handle_rx(struct cyclades_port *info, } #endif info->idle_stats.recv_idle = jiffies; - schedule_delayed_work(&tty->buf.work, 1); + tty_schedule_flip(tty); } /* Update rx_get */ cy_writel(&buf_ctrl->rx_get, new_rx_get); @@ -1809,7 +1809,7 @@ cyz_handle_cmd(struct cyclades_card *cinfo) if(delta_count) cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP); if(special_count) - schedule_delayed_work(&tty->buf.work, 1); + tty_schedule_flip(tty); } } diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c index 5485382cadec..bd7be09ea53d 100644 --- a/drivers/char/drm/ati_pcigart.c +++ b/drivers/char/drm/ati_pcigart.c @@ -59,17 +59,16 @@ static void *drm_ati_alloc_pcigart_table(void) int i; DRM_DEBUG("%s\n", __FUNCTION__); - address = __get_free_pages(GFP_KERNEL, ATI_PCIGART_TABLE_ORDER); + address = __get_free_pages(GFP_KERNEL | __GFP_COMP, + ATI_PCIGART_TABLE_ORDER); if (address == 0UL) { - return 0; + return NULL; } page = virt_to_page(address); - for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) { - get_page(page); + for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) SetPageReserved(page); - } DRM_DEBUG("%s: returning 0x%08lx\n", __FUNCTION__, address); return (void *)address; @@ -83,10 +82,8 @@ static void drm_ati_free_pcigart_table(void *address) page = virt_to_page((unsigned long)address); - for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) { - __put_page(page); + for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) ClearPageReserved(page); - } free_pages((unsigned long)address, ATI_PCIGART_TABLE_ORDER); } @@ -127,7 +124,7 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) if (gart_info->gart_table_location == DRM_ATI_GART_MAIN && gart_info->addr) { drm_ati_free_pcigart_table(gart_info->addr); - gart_info->addr = 0; + gart_info->addr = NULL; } return 1; @@ -168,7 +165,7 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) if (bus_address == 0) { DRM_ERROR("unable to map PCIGART pages!\n"); drm_ati_free_pcigart_table(address); - address = 0; + address = NULL; goto done; } } else { diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 54b561e69486..71b8b32b075f 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -57,6 +57,7 @@ #include <linux/smp_lock.h> /* For (un)lock_kernel */ #include <linux/mm.h> #include <linux/cdev.h> +#include <linux/mutex.h> #if defined(__alpha__) || defined(__powerpc__) #include <asm/pgtable.h> /* For pte_wrprotect */ #endif @@ -623,7 +624,7 @@ typedef struct drm_device { /** \name Locks */ /*@{ */ spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ - struct semaphore struct_sem; /**< For others */ + struct mutex struct_mutex; /**< For others */ /*@} */ /** \name Usage Counters */ @@ -658,7 +659,7 @@ typedef struct drm_device { /*@{ */ drm_ctx_list_t *ctxlist; /**< Linked list of context handles */ int ctx_count; /**< Number of context handles */ - struct semaphore ctxlist_sem; /**< For ctxlist */ + struct mutex ctxlist_mutex; /**< For ctxlist */ drm_map_t **context_sareas; /**< per-context SAREA's */ int max_context; diff --git a/drivers/char/drm/drm_auth.c b/drivers/char/drm/drm_auth.c index a47b502bc7cc..2a37586a7ee8 100644 --- a/drivers/char/drm/drm_auth.c +++ b/drivers/char/drm/drm_auth.c @@ -56,7 +56,7 @@ static int drm_hash_magic(drm_magic_t magic) * \param magic magic number. * * Searches in drm_device::magiclist within all files with the same hash key - * the one with matching magic number, while holding the drm_device::struct_sem + * the one with matching magic number, while holding the drm_device::struct_mutex * lock. */ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic) @@ -65,14 +65,14 @@ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic) drm_magic_entry_t *pt; int hash = drm_hash_magic(magic); - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); for (pt = dev->magiclist[hash].head; pt; pt = pt->next) { if (pt->magic == magic) { retval = pt->priv; break; } } - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return retval; } @@ -85,7 +85,7 @@ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic) * * Creates a drm_magic_entry structure and appends to the linked list * associated the magic number hash key in drm_device::magiclist, while holding - * the drm_device::struct_sem lock. + * the drm_device::struct_mutex lock. */ static int drm_add_magic(drm_device_t * dev, drm_file_t * priv, drm_magic_t magic) @@ -104,7 +104,7 @@ static int drm_add_magic(drm_device_t * dev, drm_file_t * priv, entry->priv = priv; entry->next = NULL; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); if (dev->magiclist[hash].tail) { dev->magiclist[hash].tail->next = entry; dev->magiclist[hash].tail = entry; @@ -112,7 +112,7 @@ static int drm_add_magic(drm_device_t * dev, drm_file_t * priv, dev->magiclist[hash].head = entry; dev->magiclist[hash].tail = entry; } - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return 0; } @@ -124,7 +124,7 @@ static int drm_add_magic(drm_device_t * dev, drm_file_t * priv, * \param magic magic number. * * Searches and unlinks the entry in drm_device::magiclist with the magic - * number hash key, while holding the drm_device::struct_sem lock. + * number hash key, while holding the drm_device::struct_mutex lock. */ static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic) { @@ -135,7 +135,7 @@ static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic) DRM_DEBUG("%d\n", magic); hash = drm_hash_magic(magic); - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) { if (pt->magic == magic) { if (dev->magiclist[hash].head == pt) { @@ -147,11 +147,11 @@ static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic) if (prev) { prev->next = pt->next; } - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return 0; } } - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index 1db12dcb6802..e2637b4d51de 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c @@ -255,14 +255,14 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, memset(list, 0, sizeof(*list)); list->map = map; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); list_add(&list->head, &dev->maplist->head); /* Assign a 32-bit handle */ - /* We do it here so that dev->struct_sem protects the increment */ + /* We do it here so that dev->struct_mutex protects the increment */ list->user_token = HandleID(map->type == _DRM_SHM ? (unsigned long)map->handle : map->offset, dev); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); *maplist = list; return 0; @@ -392,9 +392,9 @@ int drm_rmmap(drm_device_t *dev, drm_local_map_t *map) { int ret; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); ret = drm_rmmap_locked(dev, map); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -423,7 +423,7 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp, return -EFAULT; } - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); list_for_each(list, &dev->maplist->head) { drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head); @@ -439,7 +439,7 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp, * find anything. */ if (list == (&dev->maplist->head)) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return -EINVAL; } @@ -448,13 +448,13 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp, /* Register and framebuffer maps are permanent */ if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return 0; } ret = drm_rmmap_locked(dev, map); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -566,16 +566,16 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) atomic_inc(&dev->buf_alloc); spin_unlock(&dev->count_lock); - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); entry = &dma->bufs[order]; if (entry->buf_count) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; /* May only call once for each order */ } if (count < 0 || count > 4096) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -EINVAL; } @@ -583,7 +583,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) entry->buflist = drm_alloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS); if (!entry->buflist) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; } @@ -616,7 +616,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) /* Set count correctly so we free the proper amount. */ entry->buf_count = count; drm_cleanup_buf_error(dev, entry); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; } @@ -638,7 +638,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) if (!temp_buflist) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; } @@ -656,7 +656,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); request->count = entry->buf_count; request->size = size; @@ -722,16 +722,16 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) atomic_inc(&dev->buf_alloc); spin_unlock(&dev->count_lock); - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); entry = &dma->bufs[order]; if (entry->buf_count) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; /* May only call once for each order */ } if (count < 0 || count > 4096) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -EINVAL; } @@ -739,7 +739,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) entry->buflist = drm_alloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS); if (!entry->buflist) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; } @@ -750,7 +750,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) if (!entry->seglist) { drm_free(entry->buflist, count * sizeof(*entry->buflist), DRM_MEM_BUFS); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; } @@ -766,7 +766,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) count * sizeof(*entry->buflist), DRM_MEM_BUFS); drm_free(entry->seglist, count * sizeof(*entry->seglist), DRM_MEM_SEGS); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; } @@ -790,7 +790,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) drm_free(temp_pagelist, (dma->page_count + (count << page_order)) * sizeof(*dma->pagelist), DRM_MEM_PAGES); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; } @@ -831,7 +831,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) (count << page_order)) * sizeof(*dma->pagelist), DRM_MEM_PAGES); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; } @@ -853,7 +853,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) drm_free(temp_pagelist, (dma->page_count + (count << page_order)) * sizeof(*dma->pagelist), DRM_MEM_PAGES); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; } @@ -878,7 +878,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) dma->page_count += entry->seg_count << page_order; dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); request->count = entry->buf_count; request->size = size; @@ -948,16 +948,16 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request) atomic_inc(&dev->buf_alloc); spin_unlock(&dev->count_lock); - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); entry = &dma->bufs[order]; if (entry->buf_count) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; /* May only call once for each order */ } if (count < 0 || count > 4096) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -EINVAL; } @@ -965,7 +965,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request) entry->buflist = drm_alloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS); if (!entry->buflist) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; } @@ -999,7 +999,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request) /* Set count correctly so we free the proper amount. */ entry->buf_count = count; drm_cleanup_buf_error(dev, entry); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; } @@ -1022,7 +1022,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request) if (!temp_buflist) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; } @@ -1040,7 +1040,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request) DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); request->count = entry->buf_count; request->size = size; @@ -1110,16 +1110,16 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) atomic_inc(&dev->buf_alloc); spin_unlock(&dev->count_lock); - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); entry = &dma->bufs[order]; if (entry->buf_count) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; /* May only call once for each order */ } if (count < 0 || count > 4096) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -EINVAL; } @@ -1127,7 +1127,7 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) entry->buflist = drm_alloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS); if (!entry->buflist) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; } @@ -1160,7 +1160,7 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) /* Set count correctly so we free the proper amount. */ entry->buf_count = count; drm_cleanup_buf_error(dev, entry); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; } @@ -1182,7 +1182,7 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) if (!temp_buflist) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; } @@ -1200,7 +1200,7 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); request->count = entry->buf_count; request->size = size; diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c index f84254526949..83094c73da67 100644 --- a/drivers/char/drm/drm_context.c +++ b/drivers/char/drm/drm_context.c @@ -53,7 +53,7 @@ * \param ctx_handle context handle. * * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry - * in drm_device::context_sareas, while holding the drm_device::struct_sem + * in drm_device::context_sareas, while holding the drm_device::struct_mutex * lock. */ void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle) @@ -64,10 +64,10 @@ void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle) goto failed; if (ctx_handle < DRM_MAX_CTXBITMAP) { - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); clear_bit(ctx_handle, dev->ctx_bitmap); dev->context_sareas[ctx_handle] = NULL; - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return; } failed: @@ -83,7 +83,7 @@ void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle) * * Find the first zero bit in drm_device::ctx_bitmap and (re)allocates * drm_device::context_sareas to accommodate the new entry while holding the - * drm_device::struct_sem lock. + * drm_device::struct_mutex lock. */ static int drm_ctxbitmap_next(drm_device_t * dev) { @@ -92,7 +92,7 @@ static int drm_ctxbitmap_next(drm_device_t * dev) if (!dev->ctx_bitmap) return -1; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP); if (bit < DRM_MAX_CTXBITMAP) { set_bit(bit, dev->ctx_bitmap); @@ -113,7 +113,7 @@ static int drm_ctxbitmap_next(drm_device_t * dev) DRM_MEM_MAPS); if (!ctx_sareas) { clear_bit(bit, dev->ctx_bitmap); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return -1; } dev->context_sareas = ctx_sareas; @@ -126,16 +126,16 @@ static int drm_ctxbitmap_next(drm_device_t * dev) DRM_MEM_MAPS); if (!dev->context_sareas) { clear_bit(bit, dev->ctx_bitmap); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return -1; } dev->context_sareas[bit] = NULL; } } - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return bit; } - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return -1; } @@ -145,24 +145,24 @@ static int drm_ctxbitmap_next(drm_device_t * dev) * \param dev DRM device. * * Allocates and initialize drm_device::ctx_bitmap and drm_device::context_sareas, while holding - * the drm_device::struct_sem lock. + * the drm_device::struct_mutex lock. */ int drm_ctxbitmap_init(drm_device_t * dev) { int i; int temp; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); dev->ctx_bitmap = (unsigned long *)drm_alloc(PAGE_SIZE, DRM_MEM_CTXBITMAP); if (dev->ctx_bitmap == NULL) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return -ENOMEM; } memset((void *)dev->ctx_bitmap, 0, PAGE_SIZE); dev->context_sareas = NULL; dev->max_context = -1; - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { temp = drm_ctxbitmap_next(dev); @@ -178,17 +178,17 @@ int drm_ctxbitmap_init(drm_device_t * dev) * \param dev DRM device. * * Frees drm_device::ctx_bitmap and drm_device::context_sareas, while holding - * the drm_device::struct_sem lock. + * the drm_device::struct_mutex lock. */ void drm_ctxbitmap_cleanup(drm_device_t * dev) { - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); if (dev->context_sareas) drm_free(dev->context_sareas, sizeof(*dev->context_sareas) * dev->max_context, DRM_MEM_MAPS); drm_free((void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); } /*@}*/ @@ -222,15 +222,15 @@ int drm_getsareactx(struct inode *inode, struct file *filp, if (copy_from_user(&request, argp, sizeof(request))) return -EFAULT; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); if (dev->max_context < 0 || request.ctx_id >= (unsigned)dev->max_context) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return -EINVAL; } map = dev->context_sareas[request.ctx_id]; - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); request.handle = NULL; list_for_each_entry(_entry, &dev->maplist->head, head) { @@ -274,7 +274,7 @@ int drm_setsareactx(struct inode *inode, struct file *filp, (drm_ctx_priv_map_t __user *) arg, sizeof(request))) return -EFAULT; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); list_for_each(list, &dev->maplist->head) { r_list = list_entry(list, drm_map_list_t, head); if (r_list->map @@ -282,7 +282,7 @@ int drm_setsareactx(struct inode *inode, struct file *filp, goto found; } bad: - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return -EINVAL; found: @@ -294,7 +294,7 @@ int drm_setsareactx(struct inode *inode, struct file *filp, if (request.ctx_id >= (unsigned)dev->max_context) goto bad; dev->context_sareas[request.ctx_id] = map; - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return 0; } @@ -448,10 +448,10 @@ int drm_addctx(struct inode *inode, struct file *filp, ctx_entry->handle = ctx.handle; ctx_entry->tag = priv; - down(&dev->ctxlist_sem); + mutex_lock(&dev->ctxlist_mutex); list_add(&ctx_entry->head, &dev->ctxlist->head); ++dev->ctx_count; - up(&dev->ctxlist_sem); + mutex_unlock(&dev->ctxlist_mutex); if (copy_to_user(argp, &ctx, sizeof(ctx))) return -EFAULT; @@ -574,7 +574,7 @@ int drm_rmctx(struct inode *inode, struct file *filp, drm_ctxbitmap_free(dev, ctx.handle); } - down(&dev->ctxlist_sem); + mutex_lock(&dev->ctxlist_mutex); if (!list_empty(&dev->ctxlist->head)) { drm_ctx_list_t *pos, *n; @@ -586,7 +586,7 @@ int drm_rmctx(struct inode *inode, struct file *filp, } } } - up(&dev->ctxlist_sem); + mutex_unlock(&dev->ctxlist_mutex); return 0; } diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c index c4fa5a29582b..dc6bbe8a18dc 100644 --- a/drivers/char/drm/drm_drv.c +++ b/drivers/char/drm/drm_drv.c @@ -151,7 +151,7 @@ int drm_lastclose(drm_device_t * dev) if (dev->irq_enabled) drm_irq_uninstall(dev); - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); del_timer(&dev->timer); /* Clear pid list */ @@ -231,7 +231,7 @@ int drm_lastclose(drm_device_t * dev) dev->lock.filp = NULL; wake_up_interruptible(&dev->lock.lock_queue); } - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); DRM_DEBUG("lastclose completed\n"); return 0; diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index 403f44a1bf01..641f7633878c 100644 --- a/drivers/char/drm/drm_fops.c +++ b/drivers/char/drm/drm_fops.c @@ -262,7 +262,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, goto out_free; } - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); if (!dev->file_last) { priv->next = NULL; priv->prev = NULL; @@ -276,7 +276,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, dev->file_last->next = priv; dev->file_last = priv; } - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); #ifdef __alpha__ /* @@ -413,7 +413,7 @@ int drm_release(struct inode *inode, struct file *filp) drm_fasync(-1, filp, 0); - down(&dev->ctxlist_sem); + mutex_lock(&dev->ctxlist_mutex); if (dev->ctxlist && (!list_empty(&dev->ctxlist->head))) { drm_ctx_list_t *pos, *n; @@ -432,9 +432,9 @@ int drm_release(struct inode *inode, struct file *filp) } } } - up(&dev->ctxlist_sem); + mutex_unlock(&dev->ctxlist_mutex); - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); if (priv->remove_auth_on_close == 1) { drm_file_t *temp = dev->file_first; while (temp) { @@ -452,7 +452,7 @@ int drm_release(struct inode *inode, struct file *filp) } else { dev->file_last = priv->prev; } - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); if (dev->driver->postclose) dev->driver->postclose(dev, priv); diff --git a/drivers/char/drm/drm_ioctl.c b/drivers/char/drm/drm_ioctl.c index bcd4e604d3ec..555f323b8a32 100644 --- a/drivers/char/drm/drm_ioctl.c +++ b/drivers/char/drm/drm_ioctl.c @@ -194,9 +194,9 @@ int drm_getmap(struct inode *inode, struct file *filp, return -EFAULT; idx = map.offset; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); if (idx < 0) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return -EINVAL; } @@ -209,7 +209,7 @@ int drm_getmap(struct inode *inode, struct file *filp, i++; } if (!r_list || !r_list->map) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return -EINVAL; } @@ -219,7 +219,7 @@ int drm_getmap(struct inode *inode, struct file *filp, map.flags = r_list->map->flags; map.handle = (void *)(unsigned long)r_list->user_token; map.mtrr = r_list->map->mtrr; - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); if (copy_to_user(argp, &map, sizeof(map))) return -EFAULT; @@ -253,11 +253,11 @@ int drm_getclient(struct inode *inode, struct file *filp, if (copy_from_user(&client, argp, sizeof(client))) return -EFAULT; idx = client.idx; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); for (i = 0, pt = dev->file_first; i < idx && pt; i++, pt = pt->next) ; if (!pt) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return -EINVAL; } client.auth = pt->authenticated; @@ -265,7 +265,7 @@ int drm_getclient(struct inode *inode, struct file *filp, client.uid = pt->uid; client.magic = pt->magic; client.iocs = pt->ioctl_count; - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); if (copy_to_user(argp, &client, sizeof(client))) return -EFAULT; @@ -292,7 +292,7 @@ int drm_getstats(struct inode *inode, struct file *filp, memset(&stats, 0, sizeof(stats)); - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); for (i = 0; i < dev->counters; i++) { if (dev->types[i] == _DRM_STAT_LOCK) @@ -305,7 +305,7 @@ int drm_getstats(struct inode *inode, struct file *filp, stats.count = dev->counters; - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); if (copy_to_user((drm_stats_t __user *) arg, &stats, sizeof(stats))) return -EFAULT; diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c index b0d4b236e837..611a1173091d 100644 --- a/drivers/char/drm/drm_irq.c +++ b/drivers/char/drm/drm_irq.c @@ -98,20 +98,20 @@ static int drm_irq_install(drm_device_t * dev) if (dev->irq == 0) return -EINVAL; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); /* Driver must have been initialized */ if (!dev->dev_private) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return -EINVAL; } if (dev->irq_enabled) { - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return -EBUSY; } dev->irq_enabled = 1; - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); DRM_DEBUG("%s: irq=%d\n", __FUNCTION__, dev->irq); @@ -135,9 +135,9 @@ static int drm_irq_install(drm_device_t * dev) ret = request_irq(dev->irq, dev->driver->irq_handler, sh_flags, dev->devname, dev); if (ret < 0) { - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); dev->irq_enabled = 0; - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -161,10 +161,10 @@ int drm_irq_uninstall(drm_device_t * dev) if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return -EINVAL; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); irq_enabled = dev->irq_enabled; dev->irq_enabled = 0; - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); if (!irq_enabled) return -EINVAL; diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h index 5b1d3a04458d..8fd6357a48da 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h @@ -3,6 +3,7 @@ Please contact dri-devel@lists.sf.net to add new cards to this list */ #define radeon_PCI_IDS \ + {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350},\ {0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP}, \ {0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \ {0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ @@ -242,5 +243,6 @@ {0x8086, 0x2582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0, 0, 0} diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c index 6f943e3309ef..362a270af0f1 100644 --- a/drivers/char/drm/drm_proc.c +++ b/drivers/char/drm/drm_proc.c @@ -258,7 +258,7 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request, } /** - * Simply calls _vm_info() while holding the drm_device::struct_sem lock. + * Simply calls _vm_info() while holding the drm_device::struct_mutex lock. */ static int drm_vm_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) @@ -266,9 +266,9 @@ static int drm_vm_info(char *buf, char **start, off_t offset, int request, drm_device_t *dev = (drm_device_t *) data; int ret; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); ret = drm__vm_info(buf, start, offset, request, eof, data); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -331,7 +331,7 @@ static int drm__queues_info(char *buf, char **start, off_t offset, } /** - * Simply calls _queues_info() while holding the drm_device::struct_sem lock. + * Simply calls _queues_info() while holding the drm_device::struct_mutex lock. */ static int drm_queues_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) @@ -339,9 +339,9 @@ static int drm_queues_info(char *buf, char **start, off_t offset, int request, drm_device_t *dev = (drm_device_t *) data; int ret; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); ret = drm__queues_info(buf, start, offset, request, eof, data); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -403,7 +403,7 @@ static int drm__bufs_info(char *buf, char **start, off_t offset, int request, } /** - * Simply calls _bufs_info() while holding the drm_device::struct_sem lock. + * Simply calls _bufs_info() while holding the drm_device::struct_mutex lock. */ static int drm_bufs_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) @@ -411,9 +411,9 @@ static int drm_bufs_info(char *buf, char **start, off_t offset, int request, drm_device_t *dev = (drm_device_t *) data; int ret; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); ret = drm__bufs_info(buf, start, offset, request, eof, data); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -459,7 +459,7 @@ static int drm__clients_info(char *buf, char **start, off_t offset, } /** - * Simply calls _clients_info() while holding the drm_device::struct_sem lock. + * Simply calls _clients_info() while holding the drm_device::struct_mutex lock. */ static int drm_clients_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) @@ -467,9 +467,9 @@ static int drm_clients_info(char *buf, char **start, off_t offset, drm_device_t *dev = (drm_device_t *) data; int ret; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); ret = drm__clients_info(buf, start, offset, request, eof, data); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -540,9 +540,9 @@ static int drm_vma_info(char *buf, char **start, off_t offset, int request, drm_device_t *dev = (drm_device_t *) data; int ret; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); ret = drm__vma_info(buf, start, offset, request, eof, data); - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); return ret; } #endif diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c index 42d766359caa..7a9263ff3007 100644 --- a/drivers/char/drm/drm_stub.c +++ b/drivers/char/drm/drm_stub.c @@ -61,8 +61,8 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, spin_lock_init(&dev->count_lock); init_timer(&dev->timer); - sema_init(&dev->struct_sem, 1); - sema_init(&dev->ctxlist_sem, 1); + mutex_init(&dev->struct_mutex); + mutex_init(&dev->ctxlist_mutex); dev->pdev = pdev; diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c index 3f73aa774c80..0291cd62c69f 100644 --- a/drivers/char/drm/drm_vm.c +++ b/drivers/char/drm/drm_vm.c @@ -188,7 +188,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma) map = vma->vm_private_data; - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); for (pt = dev->vmalist, prev = NULL; pt; pt = next) { next = pt->next; if (pt->vma->vm_private_data == map) @@ -248,7 +248,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma) drm_free(map, sizeof(*map), DRM_MEM_MAPS); } } - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); } /** @@ -404,12 +404,12 @@ static void drm_vm_open(struct vm_area_struct *vma) vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS); if (vma_entry) { - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); vma_entry->vma = vma; vma_entry->next = dev->vmalist; vma_entry->pid = current->pid; dev->vmalist = vma_entry; - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); } } @@ -431,7 +431,7 @@ static void drm_vm_close(struct vm_area_struct *vma) vma->vm_start, vma->vm_end - vma->vm_start); atomic_dec(&dev->vma_count); - down(&dev->struct_sem); + mutex_lock(&dev->struct_mutex); for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) { if (pt->vma == vma) { if (prev) { @@ -443,7 +443,7 @@ static void drm_vm_close(struct vm_area_struct *vma) break; } } - up(&dev->struct_sem); + mutex_unlock(&dev->struct_mutex); } /** diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c index cc1b89086876..ae0aa6d7e0bb 100644 --- a/drivers/char/drm/i810_dma.c +++ b/drivers/char/drm/i810_dma.c @@ -958,7 +958,7 @@ static int i810_flush_queue(drm_device_t * dev) } /* Must be called with the lock held */ -void i810_reclaim_buffers(drm_device_t * dev, struct file *filp) +static void i810_reclaim_buffers(drm_device_t * dev, struct file *filp) { drm_device_dma_t *dma = dev->dma; int i; diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h index a18b80d91920..e8cf3ff606f0 100644 --- a/drivers/char/drm/i810_drv.h +++ b/drivers/char/drm/i810_drv.h @@ -113,8 +113,6 @@ typedef struct drm_i810_private { } drm_i810_private_t; /* i810_dma.c */ -extern void i810_reclaim_buffers(drm_device_t * dev, struct file *filp); - extern int i810_driver_dma_quiescent(drm_device_t * dev); extern void i810_driver_reclaim_buffers_locked(drm_device_t * dev, struct file *filp); diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c index 4fea32aed6d2..163f2cbfe60d 100644 --- a/drivers/char/drm/i830_dma.c +++ b/drivers/char/drm/i830_dma.c @@ -1239,7 +1239,7 @@ static int i830_flush_queue(drm_device_t * dev) } /* Must be called with the lock held */ -void i830_reclaim_buffers(drm_device_t * dev, struct file *filp) +static void i830_reclaim_buffers(drm_device_t * dev, struct file *filp) { drm_device_dma_t *dma = dev->dma; int i; diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h index bf9075b576bd..85bc5be6f916 100644 --- a/drivers/char/drm/i830_drv.h +++ b/drivers/char/drm/i830_drv.h @@ -123,9 +123,6 @@ typedef struct drm_i830_private { extern drm_ioctl_desc_t i830_ioctls[]; extern int i830_max_ioctl; -/* i830_dma.c */ -extern void i830_reclaim_buffers(drm_device_t * dev, struct file *filp); - /* i830_irq.c */ extern int i830_irq_emit(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index 9140703da1ba..1ff4c7ca0bff 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c @@ -344,18 +344,20 @@ static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords) int i; RING_LOCALS; + if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8) + return DRM_ERR(EINVAL); + + BEGIN_LP_RING(((dwords+1)&~1)); + for (i = 0; i < dwords;) { int cmd, sz; if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd))) return DRM_ERR(EINVAL); -/* printk("%d/%d ", i, dwords); */ - if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords) return DRM_ERR(EINVAL); - BEGIN_LP_RING(sz); OUT_RING(cmd); while (++i, --sz) { @@ -365,9 +367,13 @@ static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords) } OUT_RING(cmd); } - ADVANCE_LP_RING(); } + if (dwords & 1) + OUT_RING(0); + + ADVANCE_LP_RING(); + return 0; } @@ -401,6 +407,21 @@ static int i915_emit_box(drm_device_t * dev, return 0; } +static void i915_emit_breadcrumb(drm_device_t *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; + + BEGIN_LP_RING(4); + OUT_RING(CMD_STORE_DWORD_IDX); + OUT_RING(20); + OUT_RING(dev_priv->counter); + OUT_RING(0); + ADVANCE_LP_RING(); +} + static int i915_dispatch_cmdbuffer(drm_device_t * dev, drm_i915_cmdbuffer_t * cmd) { @@ -429,6 +450,7 @@ static int i915_dispatch_cmdbuffer(drm_device_t * dev, return ret; } + i915_emit_breadcrumb(dev); return 0; } @@ -475,12 +497,7 @@ static int i915_dispatch_batchbuffer(drm_device_t * dev, dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; - BEGIN_LP_RING(4); - OUT_RING(CMD_STORE_DWORD_IDX); - OUT_RING(20); - OUT_RING(dev_priv->counter); - OUT_RING(0); - ADVANCE_LP_RING(); + i915_emit_breadcrumb(dev); return 0; } @@ -657,7 +674,7 @@ static int i915_getparam(DRM_IOCTL_ARGS) value = READ_BREADCRUMB(dev_priv); break; default: - DRM_ERROR("Unkown parameter %d\n", param.param); + DRM_ERROR("Unknown parameter %d\n", param.param); return DRM_ERR(EINVAL); } @@ -742,7 +759,8 @@ drm_ioctl_desc_t i915_ioctls[] = { [DRM_IOCTL_NR(DRM_I915_ALLOC)] = {i915_mem_alloc, DRM_AUTH}, [DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, DRM_AUTH}, [DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, DRM_AUTH} + [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY } }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h index 77412ddac007..4cb3da578330 100644 --- a/drivers/char/drm/i915_drm.h +++ b/drivers/char/drm/i915_drm.h @@ -74,6 +74,30 @@ typedef struct _drm_i915_sarea { int pf_active; int pf_current_page; /* which buffer is being displayed? */ int perf_boxes; /* performance boxes to be displayed */ + int width, height; /* screen size in pixels */ + + drm_handle_t front_handle; + int front_offset; + int front_size; + + drm_handle_t back_handle; + int back_offset; + int back_size; + + drm_handle_t depth_handle; + int depth_offset; + int depth_size; + + drm_handle_t tex_handle; + int tex_offset; + int tex_size; + int log_tex_granularity; + int pitch; + int rotation; /* 0, 90, 180 or 270 */ + int rotated_offset; + int rotated_size; + int rotated_pitch; + int virtualX, virtualY; } drm_i915_sarea_t; /* Flags for perf_boxes @@ -99,6 +123,7 @@ typedef struct _drm_i915_sarea { #define DRM_I915_FREE 0x09 #define DRM_I915_INIT_HEAP 0x0a #define DRM_I915_CMDBUFFER 0x0b +#define DRM_I915_DESTROY_HEAP 0x0c #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -112,6 +137,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_FREE, drm_i915_mem_free_t) #define DRM_IOCTL_I915_INIT_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT_HEAP, drm_i915_mem_init_heap_t) #define DRM_IOCTL_I915_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_CMDBUFFER, drm_i915_cmdbuffer_t) +#define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t) /* Allow drivers to submit batchbuffers directly to hardware, relying * on the security mechanisms provided by hardware. @@ -191,4 +217,11 @@ typedef struct drm_i915_mem_init_heap { int start; } drm_i915_mem_init_heap_t; +/* Allow memory manager to be torn down and re-initialized (eg on + * rotate): + */ +typedef struct drm_i915_mem_destroy_heap { + int region; +} drm_i915_mem_destroy_heap_t; + #endif /* _I915_DRM_H_ */ diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index c6c71b45f101..7a65666899e4 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h @@ -37,16 +37,17 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20051209" +#define DRIVER_DATE "20060119" /* Interface history: * * 1.1: Original. * 1.2: Add Power Management * 1.3: Add vblank support + * 1.4: Fix cmdbuffer path, add heap destroy */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 3 +#define DRIVER_MINOR 4 #define DRIVER_PATCHLEVEL 0 typedef struct _drm_i915_ring_buffer { @@ -123,6 +124,7 @@ extern void i915_driver_irq_uninstall(drm_device_t * dev); extern int i915_mem_alloc(DRM_IOCTL_ARGS); extern int i915_mem_free(DRM_IOCTL_ARGS); extern int i915_mem_init_heap(DRM_IOCTL_ARGS); +extern int i915_mem_destroy_heap(DRM_IOCTL_ARGS); extern void i915_mem_takedown(struct mem_block **heap); extern void i915_mem_release(drm_device_t * dev, DRMFILE filp, struct mem_block *heap); diff --git a/drivers/char/drm/i915_mem.c b/drivers/char/drm/i915_mem.c index ba87ff17ff64..52c67324df58 100644 --- a/drivers/char/drm/i915_mem.c +++ b/drivers/char/drm/i915_mem.c @@ -365,3 +365,34 @@ int i915_mem_init_heap(DRM_IOCTL_ARGS) return init_heap(heap, initheap.start, initheap.size); } + +int i915_mem_destroy_heap( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_mem_destroy_heap_t destroyheap; + struct mem_block **heap; + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL( destroyheap, (drm_i915_mem_destroy_heap_t *)data, + sizeof(destroyheap) ); + + heap = get_heap( dev_priv, destroyheap.region ); + if (!heap) { + DRM_ERROR("get_heap failed"); + return DRM_ERR(EFAULT); + } + + if (!*heap) { + DRM_ERROR("heap not initialized?"); + return DRM_ERR(EFAULT); + } + + i915_mem_takedown( heap ); + return 0; +} + diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index 915665c7fe7c..9bb8ae0c1c27 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c @@ -1640,7 +1640,7 @@ static int radeon_do_cleanup_cp(drm_device_t * dev) if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB) { drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev); - dev_priv->gart_info.addr = 0; + dev_priv->gart_info.addr = NULL; } } /* only clear to the start of flags */ diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c index 0d426deeefec..59c7520bf9a2 100644 --- a/drivers/char/drm/savage_bci.c +++ b/drivers/char/drm/savage_bci.c @@ -32,6 +32,8 @@ #define SAVAGE_EVENT_USEC_TIMEOUT 5000000 /* 5s */ #define SAVAGE_FREELIST_DEBUG 0 +static int savage_do_cleanup_bci(drm_device_t *dev); + static int savage_bci_wait_fifo_shadow(drm_savage_private_t * dev_priv, unsigned int n) { @@ -895,7 +897,7 @@ static int savage_do_init_bci(drm_device_t * dev, drm_savage_init_t * init) return 0; } -int savage_do_cleanup_bci(drm_device_t * dev) +static int savage_do_cleanup_bci(drm_device_t * dev) { drm_savage_private_t *dev_priv = dev->dev_private; diff --git a/drivers/char/drm/savage_drv.h b/drivers/char/drm/savage_drv.h index dd46cb85439c..8f04b3d82292 100644 --- a/drivers/char/drm/savage_drv.h +++ b/drivers/char/drm/savage_drv.h @@ -212,7 +212,6 @@ extern int savage_driver_load(drm_device_t *dev, unsigned long chipset); extern int savage_driver_firstopen(drm_device_t *dev); extern void savage_driver_lastclose(drm_device_t *dev); extern int savage_driver_unload(drm_device_t *dev); -extern int savage_do_cleanup_bci(drm_device_t * dev); extern void savage_reclaim_buffers(drm_device_t * dev, DRMFILE filp); /* state functions */ diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c index 593c0b8f650a..a691ae74129d 100644 --- a/drivers/char/drm/via_dma.c +++ b/drivers/char/drm/via_dma.c @@ -222,7 +222,7 @@ static int via_initialize(drm_device_t * dev, return 0; } -int via_dma_init(DRM_IOCTL_ARGS) +static int via_dma_init(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; @@ -321,7 +321,7 @@ int via_driver_dma_quiescent(drm_device_t * dev) return 0; } -int via_flush_ioctl(DRM_IOCTL_ARGS) +static int via_flush_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; @@ -330,7 +330,7 @@ int via_flush_ioctl(DRM_IOCTL_ARGS) return via_driver_dma_quiescent(dev); } -int via_cmdbuffer(DRM_IOCTL_ARGS) +static int via_cmdbuffer(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_via_cmdbuffer_t cmdbuf; @@ -375,7 +375,7 @@ static int via_dispatch_pci_cmdbuffer(drm_device_t * dev, return ret; } -int via_pci_cmdbuffer(DRM_IOCTL_ARGS) +static int via_pci_cmdbuffer(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_via_cmdbuffer_t cmdbuf; @@ -665,7 +665,7 @@ static void via_cmdbuf_reset(drm_via_private_t * dev_priv) * User interface to the space and lag functions. */ -int via_cmdbuf_size(DRM_IOCTL_ARGS) +static int via_cmdbuf_size(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_via_cmdbuf_size_t d_siz; diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c index 9d5e027dae0e..b7f17457b424 100644 --- a/drivers/char/drm/via_dmablit.c +++ b/drivers/char/drm/via_dmablit.c @@ -108,7 +108,7 @@ via_map_blit_for_device(struct pci_dev *pdev, int num_desc = 0; int cur_line; dma_addr_t next = 0 | VIA_DMA_DPR_EC; - drm_via_descriptor_t *desc_ptr = 0; + drm_via_descriptor_t *desc_ptr = NULL; if (mode == 1) desc_ptr = vsg->desc_pages[cur_descriptor_page]; @@ -167,7 +167,7 @@ via_map_blit_for_device(struct pci_dev *pdev, */ -void +static void via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg) { struct page *page; @@ -581,7 +581,7 @@ via_build_sg_info(drm_device_t *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t * int ret = 0; vsg->direction = (draw) ? DMA_TO_DEVICE : DMA_FROM_DEVICE; - vsg->bounce_buffer = 0; + vsg->bounce_buffer = NULL; vsg->state = dr_via_sg_init; diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h index aad4f99f5405..52bcc7b1ba45 100644 --- a/drivers/char/drm/via_drv.h +++ b/drivers/char/drm/via_drv.h @@ -110,11 +110,6 @@ extern int via_mem_free(DRM_IOCTL_ARGS); extern int via_agp_init(DRM_IOCTL_ARGS); extern int via_map_init(DRM_IOCTL_ARGS); extern int via_decoder_futex(DRM_IOCTL_ARGS); -extern int via_dma_init(DRM_IOCTL_ARGS); -extern int via_cmdbuffer(DRM_IOCTL_ARGS); -extern int via_flush_ioctl(DRM_IOCTL_ARGS); -extern int via_pci_cmdbuffer(DRM_IOCTL_ARGS); -extern int via_cmdbuf_size(DRM_IOCTL_ARGS); extern int via_wait_irq(DRM_IOCTL_ARGS); extern int via_dma_blit_sync( DRM_IOCTL_ARGS ); extern int via_dma_blit( DRM_IOCTL_ARGS ); @@ -139,8 +134,6 @@ extern int via_driver_dma_quiescent(drm_device_t * dev); extern void via_init_futex(drm_via_private_t * dev_priv); extern void via_cleanup_futex(drm_via_private_t * dev_priv); extern void via_release_futex(drm_via_private_t * dev_priv, int context); -extern int via_driver_irq_wait(drm_device_t * dev, unsigned int irq, - int force_sequence, unsigned int *sequence); extern void via_dmablit_handler(drm_device_t *dev, int engine, int from_irq); extern void via_init_dmablit(drm_device_t *dev); diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c index 56d7e3daea12..6152415644e9 100644 --- a/drivers/char/drm/via_irq.c +++ b/drivers/char/drm/via_irq.c @@ -190,7 +190,7 @@ int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence) return ret; } -int +static int via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence, unsigned int *sequence) { diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 3f3ac039f4d9..57539d8f9f7c 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -359,7 +359,7 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes) } } - schedule_delayed_work(&tty->buf.work, 1); + tty_schedule_flip(tty); info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; release_pio_buffer(pio_buf); @@ -426,7 +426,7 @@ static inline void receive_chars_dma_done(struct esp_struct *info, } tty_insert_flip_char(tty, dma_buffer[num_bytes - 1], statflag); } - schedule_delayed_work(&tty->buf.work, 1); + tty_schedule_flip(tty); } if (dma_bytes != num_bytes) { diff --git a/drivers/char/ip2/i2cmd.c b/drivers/char/ip2/i2cmd.c index cb8f4198e9a3..e7af647800b6 100644 --- a/drivers/char/ip2/i2cmd.c +++ b/drivers/char/ip2/i2cmd.c @@ -139,7 +139,6 @@ static UCHAR ct79[] = { 2, BYP, 0x4F,0 }; // XMIT_NOW //static UCHAR ct86[]={ 2, BTH, 0x56,0 }; // RCV_ENABLE static UCHAR ct87[] = { 1, BYP, 0x57 }; // HW_TEST //static UCHAR ct88[]={ 3, BTH, 0x58,0,0 }; // RCV_THRESHOLD -static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW //static UCHAR ct90[]={ 3, BYP, 0x5A,0,0 }; // Set SILO //static UCHAR ct91[]={ 2, BYP, 0x5B,0 }; // timed break diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c index 56e93a5a1e24..48fcfba37bfa 100644 --- a/drivers/char/ip2main.c +++ b/drivers/char/ip2main.c @@ -2906,65 +2906,16 @@ ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg ) rc = -EINVAL; break; case 3: // Trace device - if ( cmd == 1 ) { - rc = put_user(iiSendPendingMail, pIndex++ ); - rc = put_user(i2InitChannels, pIndex++ ); - rc = put_user(i2QueueNeeds, pIndex++ ); - rc = put_user(i2QueueCommands, pIndex++ ); - rc = put_user(i2GetStatus, pIndex++ ); - rc = put_user(i2Input, pIndex++ ); - rc = put_user(i2InputFlush, pIndex++ ); - rc = put_user(i2Output, pIndex++ ); - rc = put_user(i2FlushOutput, pIndex++ ); - rc = put_user(i2DrainWakeup, pIndex++ ); - rc = put_user(i2DrainOutput, pIndex++ ); - rc = put_user(i2OutputFree, pIndex++ ); - rc = put_user(i2StripFifo, pIndex++ ); - rc = put_user(i2StuffFifoBypass, pIndex++ ); - rc = put_user(i2StuffFifoFlow, pIndex++ ); - rc = put_user(i2StuffFifoInline, pIndex++ ); - rc = put_user(i2ServiceBoard, pIndex++ ); - rc = put_user(serviceOutgoingFifo, pIndex++ ); - // rc = put_user(ip2_init, pIndex++ ); - rc = put_user(ip2_init_board, pIndex++ ); - rc = put_user(find_eisa_board, pIndex++ ); - rc = put_user(set_irq, pIndex++ ); - rc = put_user(ip2_interrupt, pIndex++ ); - rc = put_user(ip2_poll, pIndex++ ); - rc = put_user(service_all_boards, pIndex++ ); - rc = put_user(do_input, pIndex++ ); - rc = put_user(do_status, pIndex++ ); -#ifndef IP2DEBUG_OPEN - rc = put_user(0, pIndex++ ); -#else - rc = put_user(open_sanity_check, pIndex++ ); -#endif - rc = put_user(ip2_open, pIndex++ ); - rc = put_user(ip2_close, pIndex++ ); - rc = put_user(ip2_hangup, pIndex++ ); - rc = put_user(ip2_write, pIndex++ ); - rc = put_user(ip2_putchar, pIndex++ ); - rc = put_user(ip2_flush_chars, pIndex++ ); - rc = put_user(ip2_write_room, pIndex++ ); - rc = put_user(ip2_chars_in_buf, pIndex++ ); - rc = put_user(ip2_flush_buffer, pIndex++ ); - - //rc = put_user(ip2_wait_until_sent, pIndex++ ); - rc = put_user(0, pIndex++ ); - - rc = put_user(ip2_throttle, pIndex++ ); - rc = put_user(ip2_unthrottle, pIndex++ ); - rc = put_user(ip2_ioctl, pIndex++ ); - rc = put_user(0, pIndex++ ); - rc = put_user(get_serial_info, pIndex++ ); - rc = put_user(set_serial_info, pIndex++ ); - rc = put_user(ip2_set_termios, pIndex++ ); - rc = put_user(ip2_set_line_discipline, pIndex++ ); - rc = put_user(set_params, pIndex++ ); - } else { + /* + * akpm: This used to write a whole bunch of function addresses + * to userspace, which generated lots of put_user() warnings. + * I killed it all. Just return "success" and don't do + * anything. + */ + if (cmd == 1) + rc = 0; + else rc = -EINVAL; - } - break; default: diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 0097f06fa67b..d745004281d0 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -481,7 +481,7 @@ int ipmi_validate_addr(struct ipmi_addr *addr, int len) } if ((addr->channel == IPMI_BMC_CHANNEL) - || (addr->channel >= IPMI_NUM_CHANNELS) + || (addr->channel >= IPMI_MAX_CHANNELS) || (addr->channel < 0)) return -EINVAL; @@ -1321,7 +1321,7 @@ static int i_ipmi_request(ipmi_user_t user, unsigned char ipmb_seq; long seqid; - if (addr->channel >= IPMI_NUM_CHANNELS) { + if (addr->channel >= IPMI_MAX_CHANNELS) { spin_lock_irqsave(&intf->counter_lock, flags); intf->sent_invalid_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 6ed213bd702c..e59b638766ef 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1270,36 +1270,36 @@ static int try_init_port(int intf_num, struct smi_info **new_info) return 0; } -static unsigned char mem_inb(struct si_sm_io *io, unsigned int offset) +static unsigned char intf_mem_inb(struct si_sm_io *io, unsigned int offset) { return readb((io->addr)+(offset * io->regspacing)); } -static void mem_outb(struct si_sm_io *io, unsigned int offset, +static void intf_mem_outb(struct si_sm_io *io, unsigned int offset, unsigned char b) { writeb(b, (io->addr)+(offset * io->regspacing)); } -static unsigned char mem_inw(struct si_sm_io *io, unsigned int offset) +static unsigned char intf_mem_inw(struct si_sm_io *io, unsigned int offset) { return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift) && 0xff; } -static void mem_outw(struct si_sm_io *io, unsigned int offset, +static void intf_mem_outw(struct si_sm_io *io, unsigned int offset, unsigned char b) { writeb(b << io->regshift, (io->addr)+(offset * io->regspacing)); } -static unsigned char mem_inl(struct si_sm_io *io, unsigned int offset) +static unsigned char intf_mem_inl(struct si_sm_io *io, unsigned int offset) { return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift) && 0xff; } -static void mem_outl(struct si_sm_io *io, unsigned int offset, +static void intf_mem_outl(struct si_sm_io *io, unsigned int offset, unsigned char b) { writel(b << io->regshift, (io->addr)+(offset * io->regspacing)); @@ -1349,16 +1349,16 @@ static int mem_setup(struct smi_info *info) upon the register size. */ switch (info->io.regsize) { case 1: - info->io.inputb = mem_inb; - info->io.outputb = mem_outb; + info->io.inputb = intf_mem_inb; + info->io.outputb = intf_mem_outb; break; case 2: - info->io.inputb = mem_inw; - info->io.outputb = mem_outw; + info->io.inputb = intf_mem_inw; + info->io.outputb = intf_mem_outw; break; case 4: - info->io.inputb = mem_inl; - info->io.outputb = mem_outl; + info->io.inputb = intf_mem_inl; + info->io.outputb = intf_mem_outl; break; #ifdef readq case 8: diff --git a/drivers/char/rio/cirrus.h b/drivers/char/rio/cirrus.h index 217ff09f2fa1..89bd94eb45be 100644 --- a/drivers/char/rio/cirrus.h +++ b/drivers/char/rio/cirrus.h @@ -40,148 +40,6 @@ #endif #define _cirrus_h 1 -#ifdef RTA -#define TO_UART RX -#define TO_DRIVER TX -#endif - -#ifdef HOST -#define TO_UART TX -#define TO_DRIVER RX -#endif -#ifdef RTA -/* Miscellaneous defines for CIRRUS addresses and related logic for - interrupts etc. -*/ -#define MAP(a) ((short *)(cirrus_base + (a))) -#define outp(a,b) (*MAP (a) =(b)) -#define inp(a) ((*MAP (a)) & 0xff) -#define CIRRUS_FIRST (short*)0x7300 -#define CIRRUS_SECOND (short*)0x7200 -#define CIRRUS_THIRD (short*)0x7100 -#define CIRRUS_FOURTH (short*)0x7000 -#define PORTS_ON_CIRRUS 4 -#define CIRRUS_FIFO_SIZE 12 -#define SPACE 0x20 -#define TAB 0x09 -#define LINE_FEED 0x0a -#define CARRIAGE_RETURN 0x0d -#define BACKSPACE 0x08 -#define SPACES_IN_TABS 8 -#define SEND_ESCAPE 0x00 -#define START_BREAK 0x81 -#define TIMER_TICK 0x82 -#define STOP_BREAK 0x83 -#define BASE(a) ((a) < 4 ? (short*)CIRRUS_FIRST : ((a) < 8 ? (short *)CIRRUS_SECOND : ((a) < 12 ? (short*)CIRRUS_THIRD : (short *)CIRRUS_FOURTH))) -#define txack1 ((short *)0x7104) -#define rxack1 ((short *)0x7102) -#define mdack1 ((short *)0x7106) -#define txack2 ((short *)0x7006) -#define rxack2 ((short *)0x7004) -#define mdack2 ((short *)0x7100) -#define int_latch ((short *) 0x7800) -#define int_status ((short *) 0x7c00) -#define tx1_pending 0x20 -#define rx1_pending 0x10 -#define md1_pending 0x40 -#define tx2_pending 0x02 -#define rx2_pending 0x01 -#define md2_pending 0x40 -#define module1_bits 0x07 -#define module1_modern 0x08 -#define module2_bits 0x70 -#define module2_modern 0x80 -#define module_blank 0xf -#define rs232_d25 0x0 -#define rs232_rj45 0x1 -#define rs422_d25 0x3 -#define parallel 0x5 - -#define CLK0 0x00 -#define CLK1 0x01 -#define CLK2 0x02 -#define CLK3 0x03 -#define CLK4 0x04 - -#define CIRRUS_REVC 0x42 -#define CIRRUS_REVE 0x44 - -#define TURNON 1 -#define TURNOFF 0 - -/* The list of CIRRUS registers. - NB. These registers are relative values on 8 bit boundaries whereas - on the RTA's the CIRRUS registers are on word boundaries. Use pointer - arithmetic (short *) to obtain the real addresses required */ -#define ccr 0x05 /* Channel Command Register */ -#define ier 0x06 /* Interrupt Enable Register */ -#define cor1 0x08 /* Channel Option Register 1 */ -#define cor2 0x09 /* Channel Option Register 2 */ -#define cor3 0x0a /* Channel Option Register 3 */ -#define cor4 0x1e /* Channel Option Register 4 */ -#define cor5 0x1f /* Channel Option Register 5 */ - -#define ccsr 0x0b /* Channel Control Status Register */ -#define rdcr 0x0e /* Receive Data Count Register */ -#define tdcr 0x12 /* Transmit Data Count Register */ -#define mcor1 0x15 /* Modem Change Option Register 1 */ -#define mcor2 0x16 /* Modem Change Option Regsiter 2 */ - -#define livr 0x18 /* Local Interrupt Vector Register */ -#define schr1 0x1a /* Special Character Register 1 */ -#define schr2 0x1b /* Special Character Register 2 */ -#define schr3 0x1c /* Special Character Register 3 */ -#define schr4 0x1d /* Special Character Register 4 */ - -#define rtr 0x20 /* Receive Timer Register */ -#define rtpr 0x21 /* Receive Timeout Period Register */ -#define lnc 0x24 /* Lnext character */ - -#define rivr 0x43 /* Receive Interrupt Vector Register */ -#define tivr 0x42 /* Transmit Interrupt Vector Register */ -#define mivr 0x41 /* Modem Interrupt Vector Register */ -#define gfrcr 0x40 /* Global Firmware Revision code Reg */ -#define ricr 0x44 /* Receive Interrupting Channel Reg */ -#define ticr 0x45 /* Transmit Interrupting Channel Reg */ -#define micr 0x46 /* Modem Interrupting Channel Register */ - -#define gcr 0x4b /* Global configuration register */ -#define misr 0x4c /* Modem interrupt status register */ - -#define rbusr 0x59 -#define tbusr 0x5a -#define mbusr 0x5b - -#define eoir 0x60 /* End Of Interrupt Register */ -#define rdsr 0x62 /* Receive Data / Status Register */ -#define tdr 0x63 /* Transmit Data Register */ -#define svrr 0x67 /* Service Request Register */ - -#define car 0x68 /* Channel Access Register */ -#define mir 0x69 /* Modem Interrupt Register */ -#define tir 0x6a /* Transmit Interrupt Register */ -#define rir 0x6b /* Receive Interrupt Register */ -#define msvr1 0x6c /* Modem Signal Value Register 1 */ -#define msvr2 0x6d /* Modem Signal Value Register 2 */ -#define psvr 0x6f /* Printer Signal Value Register */ - -#define tbpr 0x72 /* Transmit Baud Rate Period Register */ -#define tcor 0x76 /* Transmit Clock Option Register */ - -#define rbpr 0x78 /* Receive Baud Rate Period Register */ -#define rber 0x7a /* Receive Baud Rate Extension Register */ -#define rcor 0x7c /* Receive Clock Option Register */ -#define ppr 0x7e /* Prescalar Period Register */ - -/* Misc registers used for forcing the 1400 out of its reset woes */ -#define airl 0x6d -#define airm 0x6e -#define airh 0x6f -#define btcr 0x66 -#define mtcr 0x6c -#define tber 0x74 - -#endif /* #ifdef RTA */ /* Bit fields for particular registers */ diff --git a/drivers/char/rio/defaults.h b/drivers/char/rio/defaults.h index 5b600c32ac02..d55c2f6a9877 100644 --- a/drivers/char/rio/defaults.h +++ b/drivers/char/rio/defaults.h @@ -45,13 +45,6 @@ static char *_rio_defaults_h_sccs = "@(#)defaults.h 1.1"; #define MILLISECOND (int) (1000/64) /* 15.625 low ticks */ #define SECOND (int) 15625 /* Low priority ticks */ -#ifdef RTA -#define RX_LIMIT (ushort) 3 -#endif -#ifdef HOST -#define RX_LIMIT (ushort) 1 -#endif - #define LINK_TIMEOUT (int) (POLL_PERIOD / 2) diff --git a/drivers/char/rio/link.h b/drivers/char/rio/link.h index bfba5b0c033e..48d68ca7f825 100644 --- a/drivers/char/rio/link.h +++ b/drivers/char/rio/link.h @@ -102,30 +102,14 @@ /* ** LED stuff */ -#if defined(RTA) -#define LED_OFF ((ushort) 0) /* LED off */ -#define LED_RED ((ushort) 1) /* LED Red */ -#define LED_GREEN ((ushort) 2) /* LED Green */ -#define LED_ORANGE ((ushort) 4) /* LED Orange */ -#define LED_1TO8_OPEN ((ushort) 1) /* Port 1->8 LED on */ -#define LED_9TO16_OPEN ((ushort) 2) /* Port 9->16 LED on */ -#define LED_SET_COLOUR(colour) (link->led = (colour)) -#define LED_OR_COLOUR(colour) (link->led |= (colour)) -#define LED_TIMEOUT(time) (link->led_timeout = RioTimePlus(RioTime(),(time))) -#else #define LED_SET_COLOUR(colour) #define LED_OR_COLOUR(colour) #define LED_TIMEOUT(time) -#endif /* RTA */ struct LPB { WORD link_number; /* Link Number */ Channel_ptr in_ch; /* Link In Channel */ Channel_ptr out_ch; /* Link Out Channel */ -#ifdef RTA - uchar stat_led; /* Port open leds */ - uchar led; /* True, light led! */ -#endif BYTE attached_serial[4]; /* Attached serial number */ BYTE attached_host_serial[4]; /* Serial number of Host who @@ -144,30 +128,12 @@ struct LPB { WORD WaitNoBoot; /* Secs to hold off booting */ PKT_ptr add_packet_list; /* Add packets to here */ PKT_ptr remove_packet_list; /* Send packets from here */ -#ifdef RTA -#ifdef DCIRRUS -#define QBUFS_PER_REDIRECT (4 / PKTS_PER_BUFFER + 1) -#else -#define QBUFS_PER_REDIRECT (8 / PKTS_PER_BUFFER + 1) -#endif - PKT_ptr_ptr rd_add; /* Add a new Packet here */ - Q_BUF_ptr rd_add_qb; /* Pointer to the add Q buf */ - PKT_ptr_ptr rd_add_st_qbb; /* Pointer to start of the Q's buf */ - PKT_ptr_ptr rd_add_end_qbb; /* Pointer to the end of the Q's buf */ - PKT_ptr_ptr rd_remove; /* Remove a Packet here */ - Q_BUF_ptr rd_remove_qb; /* Pointer to the remove Q buf */ - PKT_ptr_ptr rd_remove_st_qbb; /* Pointer to the start of the Q buf */ - PKT_ptr_ptr rd_remove_end_qbb; /* Pointer to the end of the Q buf */ - ushort pkts_in_q; /* Packets in queue */ -#endif Channel_ptr lrt_fail_chan; /* Lrt's failure channel */ Channel_ptr ltt_fail_chan; /* Ltt's failure channel */ -#if defined (HOST) || defined (INKERNEL) /* RUP structure for HOST to driver communications */ struct RUP rup; -#endif struct RUP link_rup; /* RUP for the link (POLL, topology etc.) */ WORD attached_link; /* Number of attached link */ diff --git a/drivers/char/rio/list.h b/drivers/char/rio/list.h index 36aad4c9cb3a..79b853140ae5 100644 --- a/drivers/char/rio/list.h +++ b/drivers/char/rio/list.h @@ -44,8 +44,6 @@ static char *_rio_list_h_sccs = "@(#)list.h 1.9"; #define PKT_IN_USE 0x1 -#ifdef INKERNEL - #define ZERO_PTR (ushort) 0x8000 #define CaD PortP->Caddr @@ -54,143 +52,5 @@ static char *_rio_list_h_sccs = "@(#)list.h 1.9"; ** to by the TxAdd pointer has PKT_IN_USE clear in its address. */ -#ifndef linux -#if defined( MIPS ) && !defined( MIPSEISA ) -/* May the shoes of the Devil dance on your grave for creating this */ -#define can_add_transmit(PacketP,PortP) \ - (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,RINDW(PortP->TxAdd))) \ - & (PKT_IN_USE<<2))) - -#elif defined(MIPSEISA) || defined(nx6000) || \ - defined(drs6000) || defined(UWsparc) - -#define can_add_transmit(PacketP,PortP) \ - (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,RINDW(PortP->TxAdd))) \ - & PKT_IN_USE)) - -#else -#define can_add_transmit(PacketP,PortP) \ - (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,*PortP->TxAdd)) \ - & PKT_IN_USE)) -#endif - -/* -** To add a packet to the queue, you set the PKT_IN_USE bit in the address, -** and then move the TxAdd pointer along one position to point to the next -** packet pointer. You must wrap the pointer from the end back to the start. -*/ -#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc) -# define add_transmit(PortP) \ - WINDW(PortP->TxAdd,RINDW(PortP->TxAdd) | PKT_IN_USE);\ - if (PortP->TxAdd == PortP->TxEnd)\ - PortP->TxAdd = PortP->TxStart;\ - else\ - PortP->TxAdd++;\ - WWORD(PortP->PhbP->tx_add , RIO_OFF(CaD,PortP->TxAdd)); -#elif defined(AIX) -# define add_transmit(PortP) \ - {\ - register ushort *TxAddP = (ushort *)RIO_PTR(Cad,PortP->TxAddO);\ - WINDW( TxAddP, RINDW( TxAddP ) | PKT_IN_USE );\ - if (PortP->TxAddO == PortP->TxEndO )\ - PortP->TxAddO = PortP->TxStartO;\ - else\ - PortP->TxAddO += sizeof(ushort);\ - WWORD(((PHB *)RIO_PTR(Cad,PortP->PhbO))->tx_add , PortP->TxAddO );\ - } -#else -# define add_transmit(PortP) \ - *PortP->TxAdd |= PKT_IN_USE;\ - if (PortP->TxAdd == PortP->TxEnd)\ - PortP->TxAdd = PortP->TxStart;\ - else\ - PortP->TxAdd++;\ - PortP->PhbP->tx_add = RIO_OFF(CaD,PortP->TxAdd); -#endif - -/* -** can_remove_receive( PacketP, PortP ) returns non-zero if PKT_IN_USE is set -** for the next packet on the queue. It will also set PacketP to point to the -** relevant packet, [having cleared the PKT_IN_USE bit]. If PKT_IN_USE is clear, -** then can_remove_receive() returns 0. -*/ -#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc) -# define can_remove_receive(PacketP,PortP) \ - ((RINDW(PortP->RxRemove) & PKT_IN_USE) ? \ - (PacketP=(struct PKT *)RIO_PTR(CaD,(RINDW(PortP->RxRemove) & ~PKT_IN_USE))):0) -#elif defined(AIX) -# define can_remove_receive(PacketP,PortP) \ - ((RINDW((ushort *)RIO_PTR(Cad,PortP->RxRemoveO)) & PKT_IN_USE) ? \ - (PacketP=(struct PKT *)RIO_PTR(Cad,RINDW((ushort *)RIO_PTR(Cad,PortP->RxRemoveO)) & ~PKT_IN_USE)):0) -#else -# define can_remove_receive(PacketP,PortP) \ - ((*PortP->RxRemove & PKT_IN_USE) ? \ - (PacketP=(struct PKT *)RIO_PTR(CaD,(*PortP->RxRemove & ~PKT_IN_USE))):0) -#endif - - -/* -** Will God see it within his heart to forgive us for this thing that -** we have created? To remove a packet from the receive queue you clear -** its PKT_IN_USE bit, and then bump the pointers. Once the pointers -** get to the end, they must be wrapped back to the start. -*/ -#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc) -# define remove_receive(PortP) \ - WINDW(PortP->RxRemove, (RINDW(PortP->RxRemove) & ~PKT_IN_USE));\ - if (PortP->RxRemove == PortP->RxEnd)\ - PortP->RxRemove = PortP->RxStart;\ - else\ - PortP->RxRemove++;\ - WWORD(PortP->PhbP->rx_remove , RIO_OFF(CaD,PortP->RxRemove)); -#elif defined(AIX) -# define remove_receive(PortP) \ - {\ - register ushort *RxRemoveP = (ushort *)RIO_PTR(Cad,PortP->RxRemoveO);\ - WINDW( RxRemoveP, RINDW( RxRemoveP ) & ~PKT_IN_USE );\ - if (PortP->RxRemoveO == PortP->RxEndO)\ - PortP->RxRemoveO = PortP->RxStartO;\ - else\ - PortP->RxRemoveO += sizeof(ushort);\ - WWORD(((PHB *)RIO_PTR(Cad,PortP->PhbO))->rx_remove, PortP->RxRemoveO );\ - } -#else -# define remove_receive(PortP) \ - *PortP->RxRemove &= ~PKT_IN_USE;\ - if (PortP->RxRemove == PortP->RxEnd)\ - PortP->RxRemove = PortP->RxStart;\ - else\ - PortP->RxRemove++;\ - PortP->PhbP->rx_remove = RIO_OFF(CaD,PortP->RxRemove); -#endif -#endif - - -#else /* !IN_KERNEL */ - -#define ZERO_PTR NULL - - -#ifdef HOST -/* #define can_remove_transmit(pkt,phb) ((((char*)pkt = (*(char**)(phb->tx_remove))-1) || 1)) && (*phb->u3.s2.tx_remove_ptr & PKT_IN_USE)) */ -#define remove_transmit(phb) *phb->u3.s2.tx_remove_ptr &= ~(ushort)PKT_IN_USE;\ - if (phb->tx_remove == phb->tx_end)\ - phb->tx_remove = phb->tx_start;\ - else\ - phb->tx_remove++; -#define can_add_receive(phb) !(*phb->u4.s2.rx_add_ptr & PKT_IN_USE) -#define add_receive(pkt,phb) *phb->rx_add = pkt;\ - *phb->u4.s2.rx_add_ptr |= PKT_IN_USE;\ - if (phb->rx_add == phb->rx_end)\ - phb->rx_add = phb->rx_start;\ - else\ - phb->rx_add++; -#endif -#endif - -#ifdef RTA -#define splx(oldspl) if ((oldspl) == 0) spl0() -#endif - #endif /* ifndef _list.h */ /*********** end of file ***********/ diff --git a/drivers/char/rio/parmmap.h b/drivers/char/rio/parmmap.h index fe4e00567065..e24acc1d1844 100644 --- a/drivers/char/rio/parmmap.h +++ b/drivers/char/rio/parmmap.h @@ -78,14 +78,9 @@ struct PARM_MAP { WORD idle_count; /* Idle time counter */ WORD busy_count; /* Busy counter */ WORD idle_control; /* Control Idle Process */ -#if defined(HOST) || defined(INKERNEL) WORD tx_intr; /* TX interrupt pending */ WORD rx_intr; /* RX interrupt pending */ WORD rup_intr; /* RUP interrupt pending */ -#endif -#if defined(RTA) - WORD dying_count; /* Count of processes dead */ -#endif }; #endif diff --git a/drivers/char/rio/phb.h b/drivers/char/rio/phb.h index 3baebf8513af..2663ca0306e2 100644 --- a/drivers/char/rio/phb.h +++ b/drivers/char/rio/phb.h @@ -44,17 +44,6 @@ #endif - /************************************************* - * Set the LIMIT values. - ************************************************/ -#ifdef RTA -#define RX_LIMIT (ushort) 3 -#endif -#ifdef HOST -#define RX_LIMIT (ushort) 1 -#endif - - /************************************************* * Handshake asserted. Deasserted by the LTT(s) ************************************************/ @@ -69,11 +58,7 @@ /************************************************* * Maximum number of PHB's ************************************************/ -#if defined (HOST) || defined (INKERNEL) #define MAX_PHB ((ushort) 128) /* range 0-127 */ -#else -#define MAX_PHB ((ushort) 8) /* range 0-7 */ -#endif /************************************************* * Defines for the mode fields @@ -139,141 +124,23 @@ * the start. The pointer tx_add points to a SPACE to put a Packet. * The pointer tx_remove points to the next Packet to remove *************************************************************************/ -#ifndef INKERNEL -#define src_unit u2.s2.unit -#define src_port u2.s2.port -#define dest_unit u1.s1.unit -#define dest_port u1.s1.port -#endif -#ifdef HOST -#define tx_start u3.s1.tx_start_ptr_ptr -#define tx_add u3.s1.tx_add_ptr_ptr -#define tx_end u3.s1.tx_end_ptr_ptr -#define tx_remove u3.s1.tx_remove_ptr_ptr -#define rx_start u4.s1.rx_start_ptr_ptr -#define rx_add u4.s1.rx_add_ptr_ptr -#define rx_end u4.s1.rx_end_ptr_ptr -#define rx_remove u4.s1.rx_remove_ptr_ptr -#endif typedef struct PHB PHB; struct PHB { -#ifdef RTA - ushort port; -#endif -#ifdef INKERNEL WORD source; -#else - union { - ushort source; /* Complete source */ - struct { - unsigned char unit; /* Source unit */ - unsigned char port; /* Source port */ - } s2; - } u2; -#endif WORD handshake; WORD status; NUMBER timeout; /* Maximum of 1.9 seconds */ WORD link; /* Send down this link */ -#ifdef INKERNEL WORD destination; -#else - union { - ushort destination; /* Complete destination */ - struct { - unsigned char unit; /* Destination unit */ - unsigned char port; /* Destination port */ - } s1; - } u1; -#endif -#ifdef RTA - ushort tx_pkts_added; - ushort tx_pkts_removed; - Q_BUF_ptr tx_q_start; /* Start of the Q list chain */ - short num_tx_q_bufs; /* Number of Q buffers in the chain */ - PKT_ptr_ptr tx_add; /* Add a new Packet here */ - Q_BUF_ptr tx_add_qb; /* Pointer to the add Q buf */ - PKT_ptr_ptr tx_add_st_qbb; /* Pointer to start of the Q's buf */ - PKT_ptr_ptr tx_add_end_qbb; /* Pointer to the end of the Q's buf */ - PKT_ptr_ptr tx_remove; /* Remove a Packet here */ - Q_BUF_ptr tx_remove_qb; /* Pointer to the remove Q buf */ - PKT_ptr_ptr tx_remove_st_qbb; /* Pointer to the start of the Q buf */ - PKT_ptr_ptr tx_remove_end_qbb; /* Pointer to the end of the Q buf */ -#endif -#ifdef INKERNEL PKT_ptr_ptr tx_start; PKT_ptr_ptr tx_end; PKT_ptr_ptr tx_add; PKT_ptr_ptr tx_remove; -#endif -#ifdef HOST - union { - struct { - PKT_ptr_ptr tx_start_ptr_ptr; - PKT_ptr_ptr tx_end_ptr_ptr; - PKT_ptr_ptr tx_add_ptr_ptr; - PKT_ptr_ptr tx_remove_ptr_ptr; - } s1; - struct { - ushort *tx_start_ptr; - ushort *tx_end_ptr; - ushort *tx_add_ptr; - ushort *tx_remove_ptr; - } s2; - } u3; -#endif -#ifdef RTA - ushort rx_pkts_added; - ushort rx_pkts_removed; - Q_BUF_ptr rx_q_start; /* Start of the Q list chain */ - short num_rx_q_bufs; /* Number of Q buffers in the chain */ - PKT_ptr_ptr rx_add; /* Add a new Packet here */ - Q_BUF_ptr rx_add_qb; /* Pointer to the add Q buf */ - PKT_ptr_ptr rx_add_st_qbb; /* Pointer to start of the Q's buf */ - PKT_ptr_ptr rx_add_end_qbb; /* Pointer to the end of the Q's buf */ - PKT_ptr_ptr rx_remove; /* Remove a Packet here */ - Q_BUF_ptr rx_remove_qb; /* Pointer to the remove Q buf */ - PKT_ptr_ptr rx_remove_st_qbb; /* Pointer to the start of the Q buf */ - PKT_ptr_ptr rx_remove_end_qbb; /* Pointer to the end of the Q buf */ -#endif -#ifdef INKERNEL PKT_ptr_ptr rx_start; PKT_ptr_ptr rx_end; PKT_ptr_ptr rx_add; PKT_ptr_ptr rx_remove; -#endif -#ifdef HOST - union { - struct { - PKT_ptr_ptr rx_start_ptr_ptr; - PKT_ptr_ptr rx_end_ptr_ptr; - PKT_ptr_ptr rx_add_ptr_ptr; - PKT_ptr_ptr rx_remove_ptr_ptr; - } s1; - struct { - ushort *rx_start_ptr; - ushort *rx_end_ptr; - ushort *rx_add_ptr; - ushort *rx_remove_ptr; - } s2; - } u4; -#endif - -#ifdef RTA /* some fields for the remotes */ - ushort flush_count; /* Count of write flushes */ - ushort txmode; /* Modes for tx */ - ushort rxmode; /* Modes for rx */ - ushort portmode; /* Generic modes */ - ushort column; /* TAB3 column count */ - ushort tx_subscript; /* (TX) Subscript into data field */ - ushort rx_subscript; /* (RX) Subscript into data field */ - PKT_ptr rx_incomplete; /* Hold an incomplete packet here */ - ushort modem_bits; /* Modem bits to mask */ - ushort lastModem; /* Modem control lines. */ - ushort addr; /* Address for sub commands */ - ushort MonitorTstate; /* TRUE if monitoring tstop */ -#endif }; diff --git a/drivers/char/rio/pkt.h b/drivers/char/rio/pkt.h index 882fd429ac2e..7011e52e82db 100644 --- a/drivers/char/rio/pkt.h +++ b/drivers/char/rio/pkt.h @@ -70,39 +70,12 @@ #define CONTROL_DATA_WNDW (DATA_WNDW << 8) struct PKT { -#ifdef INKERNEL BYTE dest_unit; /* Destination Unit Id */ BYTE dest_port; /* Destination POrt */ BYTE src_unit; /* Source Unit Id */ BYTE src_port; /* Source POrt */ -#else - union { - ushort destination; /* Complete destination */ - struct { - unsigned char unit; /* Destination unit */ - unsigned char port; /* Destination port */ - } s1; - } u1; - union { - ushort source; /* Complete source */ - struct { - unsigned char unit; /* Source unit */ - unsigned char port; /* Source port */ - } s2; - } u2; -#endif -#ifdef INKERNEL BYTE len; BYTE control; -#else - union { - ushort control; - struct { - unsigned char len; - unsigned char control; - } s3; - } u3; -#endif BYTE data[PKT_MAX_DATA_LEN]; /* Actual data :-) */ WORD csum; /* C-SUM */ diff --git a/drivers/char/rio/qbuf.h b/drivers/char/rio/qbuf.h index acd9e8e5307d..391ffc335535 100644 --- a/drivers/char/rio/qbuf.h +++ b/drivers/char/rio/qbuf.h @@ -46,11 +46,7 @@ static char *_rio_qbuf_h_sccs = "@(#)qbuf.h 1.1"; -#ifdef HOST -#define PKTS_PER_BUFFER 1 -#else #define PKTS_PER_BUFFER (220 / PKT_LENGTH) -#endif typedef struct Q_BUF Q_BUF; struct Q_BUF { diff --git a/drivers/char/rio/riotypes.h b/drivers/char/rio/riotypes.h index 9b67e2468bec..46084d5c7e98 100644 --- a/drivers/char/rio/riotypes.h +++ b/drivers/char/rio/riotypes.h @@ -43,9 +43,6 @@ #endif #endif -#ifdef INKERNEL - -#if !defined(MIPSAT) typedef unsigned short NUMBER_ptr; typedef unsigned short WORD_ptr; typedef unsigned short BYTE_ptr; @@ -65,69 +62,6 @@ typedef unsigned short RUP_ptr; typedef unsigned short short_ptr; typedef unsigned short u_short_ptr; typedef unsigned short ushort_ptr; -#else -/* MIPSAT types */ -typedef char RIO_POINTER[8]; -typedef RIO_POINTER NUMBER_ptr; -typedef RIO_POINTER WORD_ptr; -typedef RIO_POINTER BYTE_ptr; -typedef RIO_POINTER char_ptr; -typedef RIO_POINTER Channel_ptr; -typedef RIO_POINTER FREE_LIST_ptr_ptr; -typedef RIO_POINTER FREE_LIST_ptr; -typedef RIO_POINTER LPB_ptr; -typedef RIO_POINTER Process_ptr; -typedef RIO_POINTER PHB_ptr; -typedef RIO_POINTER PKT_ptr; -typedef RIO_POINTER PKT_ptr_ptr; -typedef RIO_POINTER Q_BUF_ptr; -typedef RIO_POINTER Q_BUF_ptr_ptr; -typedef RIO_POINTER ROUTE_STR_ptr; -typedef RIO_POINTER RUP_ptr; -typedef RIO_POINTER short_ptr; -typedef RIO_POINTER u_short_ptr; -typedef RIO_POINTER ushort_ptr; -#endif - -#else /* not INKERNEL */ -typedef unsigned char BYTE; -typedef unsigned short WORD; -typedef unsigned long DWORD; -typedef short NUMBER; -typedef short *NUMBER_ptr; -typedef unsigned short *WORD_ptr; -typedef unsigned char *BYTE_ptr; -typedef unsigned char uchar; -typedef unsigned short ushort; -typedef unsigned int uint; -typedef unsigned long ulong; -typedef unsigned char u_char; -typedef unsigned short u_short; -typedef unsigned int u_int; -typedef unsigned long u_long; -typedef unsigned short ERROR; -typedef unsigned long ID; -typedef char *char_ptr; -typedef Channel *Channel_ptr; -typedef struct FREE_LIST *FREE_LIST_ptr; -typedef struct FREE_LIST **FREE_LIST_ptr_ptr; -typedef struct LPB *LPB_ptr; -typedef struct Process *Process_ptr; -typedef struct PHB *PHB_ptr; -typedef struct PKT *PKT_ptr; -typedef struct PKT **PKT_ptr_ptr; -typedef struct Q_BUF *Q_BUF_ptr; -typedef struct Q_BUF **Q_BUF_ptr_ptr; -typedef struct ROUTE_STR *ROUTE_STR_ptr; -typedef struct RUP *RUP_ptr; -typedef short *short_ptr; -typedef u_short *u_short_ptr; -typedef ushort *ushort_ptr; -typedef struct PKT PKT; -typedef struct LPB LPB; -typedef struct RUP RUP; -#endif - #endif /* __riotypes__ */ diff --git a/drivers/char/rio/rup.h b/drivers/char/rio/rup.h index 8d44fec91dd5..f74f67c6f702 100644 --- a/drivers/char/rio/rup.h +++ b/drivers/char/rio/rup.h @@ -43,12 +43,7 @@ #endif #endif -#if defined( HOST ) || defined( INKERNEL ) #define MAX_RUP ((short) 16) -#endif -#ifdef RTA -#define MAX_RUP ((short) 1) -#endif #define PKTS_PER_RUP ((short) 2) /* They are always used in pairs */ diff --git a/drivers/char/rio/sam.h b/drivers/char/rio/sam.h index 31494054b213..6f754e19015d 100644 --- a/drivers/char/rio/sam.h +++ b/drivers/char/rio/sam.h @@ -43,10 +43,6 @@ #endif -#if !defined( HOST ) && !defined( INKERNEL ) -#define RTA 1 -#endif - #define NUM_FREE_LIST_UNITS 500 #ifndef FALSE diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 0949dcef0697..7edc6a4dbdc4 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -433,7 +433,7 @@ static void rp_do_receive(struct r_port *info, count += ToRecv; } /* Push the data up to the tty layer */ - ld->receive_buf(tty, cbuf, fbuf, count); + ld->receive_buf(tty, chead, fhead, count); done: tty_ldisc_deref(ld); } diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 64bf89cb574f..c2490e270f1f 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -931,7 +931,7 @@ static int sx_set_real_termios (void *ptr) case CS6:sx_write_channel_byte (port, hi_mask, 0x3f);break; case CS5:sx_write_channel_byte (port, hi_mask, 0x1f);break; default: - printk (KERN_INFO "sx: Invalid wordsize: %d\n", CFLAG & CSIZE); + printk (KERN_INFO "sx: Invalid wordsize: %u\n", CFLAG & CSIZE); break; } @@ -958,7 +958,7 @@ static int sx_set_real_termios (void *ptr) } else { set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags); } - sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ", + sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ", port->gs.tty->termios->c_iflag, I_OTHER(port->gs.tty)); @@ -973,7 +973,7 @@ static int sx_set_real_termios (void *ptr) } else { clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags); } - sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n", + sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n", port->gs.tty->termios->c_oflag, O_OTHER(port->gs.tty)); /* port->c_dcd = sx_get_CD (port); */ diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index eb8b5be4e249..076e07c1da38 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -253,6 +253,7 @@ static void tty_buffer_free_all(struct tty_struct *tty) static void tty_buffer_init(struct tty_struct *tty) { + spin_lock_init(&tty->buf.lock); tty->buf.head = NULL; tty->buf.tail = NULL; tty->buf.free = NULL; @@ -266,6 +267,7 @@ static struct tty_buffer *tty_buffer_alloc(size_t size) p->used = 0; p->size = size; p->next = NULL; + p->active = 0; p->char_buf_ptr = (char *)(p->data); p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; /* printk("Flip create %p\n", p); */ @@ -312,25 +314,36 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) int tty_buffer_request_room(struct tty_struct *tty, size_t size) { - struct tty_buffer *b = tty->buf.tail, *n; - int left = 0; + struct tty_buffer *b, *n; + int left; + unsigned long flags; + + spin_lock_irqsave(&tty->buf.lock, flags); /* OPTIMISATION: We could keep a per tty "zero" sized buffer to remove this conditional if its worth it. This would be invisible to the callers */ - if(b != NULL) + if ((b = tty->buf.tail) != NULL) { left = b->size - b->used; - if(left >= size) - return size; - /* This is the slow path - looking for new buffers to use */ - n = tty_buffer_find(tty, size); - if(n == NULL) - return left; - if(b != NULL) - b->next = n; - else - tty->buf.head = n; - tty->buf.tail = n; + b->active = 1; + } else + left = 0; + + if (left < size) { + /* This is the slow path - looking for new buffers to use */ + if ((n = tty_buffer_find(tty, size)) != NULL) { + if (b != NULL) { + b->next = n; + b->active = 0; + } else + tty->buf.head = n; + tty->buf.tail = n; + n->active = 1; + } else + size = left; + } + + spin_unlock_irqrestore(&tty->buf.lock, flags); return size; } @@ -396,10 +409,12 @@ EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags); int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) { int space = tty_buffer_request_room(tty, size); - struct tty_buffer *tb = tty->buf.tail; - *chars = tb->char_buf_ptr + tb->used; - memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); - tb->used += space; + if (likely(space)) { + struct tty_buffer *tb = tty->buf.tail; + *chars = tb->char_buf_ptr + tb->used; + memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); + tb->used += space; + } return space; } @@ -416,10 +431,12 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) { int space = tty_buffer_request_room(tty, size); - struct tty_buffer *tb = tty->buf.tail; - *chars = tb->char_buf_ptr + tb->used; - *flags = tb->flag_buf_ptr + tb->used; - tb->used += space; + if (likely(space)) { + struct tty_buffer *tb = tty->buf.tail; + *chars = tb->char_buf_ptr + tb->used; + *flags = tb->flag_buf_ptr + tb->used; + tb->used += space; + } return space; } @@ -2747,20 +2764,20 @@ static void flush_to_ldisc(void *private_) schedule_delayed_work(&tty->buf.work, 1); goto out; } - spin_lock_irqsave(&tty->read_lock, flags); - while((tbuf = tty->buf.head) != NULL) { + spin_lock_irqsave(&tty->buf.lock, flags); + while((tbuf = tty->buf.head) != NULL && !tbuf->active) { tty->buf.head = tbuf->next; if (tty->buf.head == NULL) tty->buf.tail = NULL; - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&tty->buf.lock, flags); /* printk("Process buffer %p for %d\n", tbuf, tbuf->used); */ disc->receive_buf(tty, tbuf->char_buf_ptr, tbuf->flag_buf_ptr, tbuf->used); - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&tty->buf.lock, flags); tty_buffer_free(tty, tbuf); } - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&tty->buf.lock, flags); out: tty_ldisc_deref(disc); } @@ -2852,6 +2869,12 @@ EXPORT_SYMBOL(tty_get_baud_rate); void tty_flip_buffer_push(struct tty_struct *tty) { + unsigned long flags; + spin_lock_irqsave(&tty->buf.lock, flags); + if (tty->buf.tail != NULL) + tty->buf.tail->active = 0; + spin_unlock_irqrestore(&tty->buf.lock, flags); + if (tty->low_latency) flush_to_ldisc((void *) tty); else diff --git a/drivers/char/watchdog/sbc_epx_c3.c b/drivers/char/watchdog/sbc_epx_c3.c index 951764614ebf..7a4dfb95d087 100644 --- a/drivers/char/watchdog/sbc_epx_c3.c +++ b/drivers/char/watchdog/sbc_epx_c3.c @@ -25,6 +25,7 @@ #include <linux/notifier.h> #include <linux/reboot.h> #include <linux/init.h> +#include <linux/ioport.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -181,11 +182,14 @@ static int __init watchdog_init(void) { int ret; + if (!request_region(EPXC3_WATCHDOG_CTL_REG, 2, "epxc3_watchdog")) + return -EBUSY; + ret = register_reboot_notifier(&epx_c3_notifier); if (ret) { printk(KERN_ERR PFX "cannot register reboot notifier " "(err=%d)\n", ret); - return ret; + goto out; } ret = misc_register(&epx_c3_miscdev); @@ -193,18 +197,23 @@ static int __init watchdog_init(void) printk(KERN_ERR PFX "cannot register miscdev on minor=%d " "(err=%d)\n", WATCHDOG_MINOR, ret); unregister_reboot_notifier(&epx_c3_notifier); - return ret; + goto out; } printk(banner); return 0; + +out: + release_region(EPXC3_WATCHDOG_CTL_REG, 2); + return ret; } static void __exit watchdog_exit(void) { misc_deregister(&epx_c3_miscdev); unregister_reboot_notifier(&epx_c3_notifier); + release_region(EPXC3_WATCHDOG_CTL_REG, 2); } module_init(watchdog_init); diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 4819e7fc00dd..d94331c1e5b0 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -46,7 +46,7 @@ config EDAC_MM_EDAC config EDAC_AMD76X tristate "AMD 76x (760, 762, 768)" - depends on EDAC_MM_EDAC && PCI + depends on EDAC_MM_EDAC && PCI && X86_32 help Support for error detection and correction on the AMD 76x series of chipsets used with the Athlon processor. diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index 770a5a633079..c454ded2b060 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -1039,10 +1039,10 @@ MODULE_DEVICE_TABLE(pci, e752x_pci_tbl); static struct pci_driver e752x_driver = { - name: BS_MOD_STR, - probe: e752x_init_one, - remove: __devexit_p(e752x_remove_one), - id_table: e752x_pci_tbl, + .name = BS_MOD_STR, + .probe = e752x_init_one, + .remove = __devexit_p(e752x_remove_one), + .id_table = e752x_pci_tbl, }; diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 4be9bd0a1267..b10ee4698b1d 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -14,7 +14,6 @@ #include <linux/config.h> -#include <linux/version.h> #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/kernel.h> diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 1c81174595b3..d633081fa4c5 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -52,9 +52,9 @@ config IDE if IDE -config IDE_MAX_HWIFS +config IDE_MAX_HWIFS int "Max IDE interfaces" - depends on ALPHA || SUPERH + depends on ALPHA || SUPERH || IA64 default 4 help This is the maximum number of IDE hardware interfaces that will @@ -162,8 +162,8 @@ config BLK_DEV_IDECS tristate "PCMCIA IDE support" depends on PCMCIA help - Support for outboard IDE disks, tape drives, and CD-ROM drives - connected through a PCMCIA card. + Support for Compact Flash cards, outboard IDE disks, tape drives, + and CD-ROM drives connected through a PCMCIA card. config BLK_DEV_IDECD tristate "Include IDE/ATAPI CDROM support" @@ -267,7 +267,7 @@ config IDE_TASK_IOCTL help This is a direct raw access to the media. It is a complex but elegant solution to test and validate the domain of the hardware and - perform below the driver data recover if needed. This is the most + perform below the driver data recovery if needed. This is the most basic form of media-forensics. If you are unsure, say N here. @@ -525,7 +525,7 @@ config BLK_DEV_CS5520 tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)" depends on EXPERIMENTAL help - Include support for PIO tuning an virtual DMA on the Cyrix MediaGX + Include support for PIO tuning and virtual DMA on the Cyrix MediaGX 5510/5520 chipset. This will automatically be detected and configured if found. @@ -662,7 +662,7 @@ config PDC202XX_BURST It was originally designed for the PDC20246/Ultra33, whose BIOS will only setup UDMA on the first two PDC20246 cards. It has also been - used succesfully on a PDC20265/Ultra100, allowing use of UDMA modes + used successfully on a PDC20265/Ultra100, allowing use of UDMA modes when the PDC20265 BIOS has been disabled (for faster boot up). Please read the comments at the top of @@ -673,13 +673,6 @@ config PDC202XX_BURST config BLK_DEV_PDC202XX_NEW tristate "PROMISE PDC202{68|69|70|71|75|76|77} support" -# FIXME - probably wants to be one for old and for new -config PDC202XX_FORCE - bool "Enable controller even if disabled by BIOS" - depends on BLK_DEV_PDC202XX_NEW - help - Enable the PDC202xx controller even if it has been disabled in the BIOS setup. - config BLK_DEV_SVWKS tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support" help @@ -722,7 +715,7 @@ config BLK_DEV_SIS5513 config BLK_DEV_SLC90E66 tristate "SLC90E66 chipset support" help - This driver ensures (U)DMA support for Victroy66 SouthBridges for + This driver ensures (U)DMA support for Victory66 SouthBridges for SMsC with Intel NorthBridges. This is an Ultra66 based chipset. The nice thing about it is that you can mix Ultra/DMA/PIO devices and it will handle timing cycles. Since this is an improved @@ -1060,7 +1053,7 @@ config IDEDMA_IVB in that mode with an 80c ribbon. If you are experiencing compatibility or performance problems, you - MAY try to answering Y here. However, it does not necessarily solve + MAY try to answer Y here. However, it does not necessarily solve any of your problems, it could even cause more of them. It is normally safe to answer Y; however, the default is N. diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index ca25f9e3d0f4..6c60a9d2afd8 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -776,7 +776,7 @@ static void update_ordered(ide_drive_t *drive) ide_id_has_flush_cache_ext(id)); printk(KERN_INFO "%s: cache flushes %ssupported\n", - drive->name, barrier ? "" : "not"); + drive->name, barrier ? "" : "not "); if (barrier) { ordered = QUEUE_ORDERED_DRAIN_FLUSH; @@ -889,11 +889,7 @@ static void idedisk_setup (ide_drive_t *drive) if (drive->id_read == 0) return; - /* - * CompactFlash cards and their brethern look just like hard drives - * to us, but they are removable and don't have a doorlock mechanism. - */ - if (drive->removable && !(drive->is_flash)) { + if (drive->removable) { /* * Removable disks (eg. SYQUEST); ignore 'WD' drives */ diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 8d50df4526a4..c01615dec202 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -55,8 +55,8 @@ #include <asm/io.h> #include <asm/bitops.h> -int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate, - int nr_sectors) +static int __ide_end_request(ide_drive_t *drive, struct request *rq, + int uptodate, int nr_sectors) { int ret = 1; @@ -91,7 +91,6 @@ int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate, return ret; } -EXPORT_SYMBOL(__ide_end_request); /** * ide_end_request - complete an IDE I/O diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index af7af958ab3e..b72dde70840a 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -1243,6 +1243,7 @@ int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout) */ if (stat == 0xff) return -ENODEV; + touch_softlockup_watchdog(); } return -EBUSY; } diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index e7425546b4b1..427d1c204174 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -125,45 +125,6 @@ static void ide_disk_init_mult_count(ide_drive_t *drive) } /** - * drive_is_flashcard - check for compact flash - * @drive: drive to check - * - * CompactFlash cards and their brethern pretend to be removable - * hard disks, except: - * (1) they never have a slave unit, and - * (2) they don't have doorlock mechanisms. - * This test catches them, and is invoked elsewhere when setting - * appropriate config bits. - * - * FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD) - * devices, so in linux 2.3.x we should change this to just treat all - * PCMCIA drives this way, and get rid of the model-name tests below - * (too big of an interface change for 2.4.x). - * At that time, we might also consider parameterizing the timeouts and - * retries, since these are MUCH faster than mechanical drives. -M.Lord - */ - -static inline int drive_is_flashcard (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - - if (drive->removable) { - if (id->config == 0x848a) return 1; /* CompactFlash */ - if (!strncmp(id->model, "KODAK ATA_FLASH", 15) /* Kodak */ - || !strncmp(id->model, "Hitachi CV", 10) /* Hitachi */ - || !strncmp(id->model, "SunDisk SDCFB", 13) /* old SanDisk */ - || !strncmp(id->model, "SanDisk SDCFB", 13) /* SanDisk */ - || !strncmp(id->model, "HAGIWARA HPC", 12) /* Hagiwara */ - || !strncmp(id->model, "LEXAR ATA_FLASH", 15) /* Lexar */ - || !strncmp(id->model, "ATA_FLASH", 9)) /* Simple Tech */ - { - return 1; /* yes, it is a flash memory card */ - } - } - return 0; /* no, it is not a flash memory card */ -} - -/** * do_identify - identify a drive * @drive: drive to identify * @cmd: command used @@ -278,13 +239,17 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd) /* * Not an ATAPI device: looks like a "regular" hard disk */ - if (id->config & (1<<7)) + + /* + * 0x848a = CompactFlash device + * These are *not* removable in Linux definition of the term + */ + + if ((id->config != 0x848a) && (id->config & (1<<7))) drive->removable = 1; - if (drive_is_flashcard(drive)) - drive->is_flash = 1; drive->media = ide_disk; - printk("%s DISK drive\n", (drive->is_flash) ? "CFA" : "ATA" ); + printk("%s DISK drive\n", (id->config == 0x848a) ? "CFA" : "ATA" ); QUIRK_LIST(drive); return; diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index afeb02bbb722..b2cc43702f65 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -242,7 +242,6 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index) drive->name[2] = 'a' + (index * MAX_DRIVES) + unit; drive->max_failures = IDE_DEFAULT_MAX_FAILURES; drive->using_dma = 0; - drive->is_flash = 0; drive->vdma = 0; INIT_LIST_HEAD(&drive->list); init_completion(&drive->gendev_rel_comp); diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c index a21b1e11eef4..c743e68c33aa 100644 --- a/drivers/ide/pci/aec62xx.c +++ b/drivers/ide/pci/aec62xx.c @@ -262,6 +262,21 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch else pci_set_drvdata(dev, (void *) aec6xxx_34_base); + /* These are necessary to get AEC6280 Macintosh cards to work */ + if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) || + (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) { + u8 reg49h = 0, reg4ah = 0; + /* Clear reset and test bits. */ + pci_read_config_byte(dev, 0x49, ®49h); + pci_write_config_byte(dev, 0x49, reg49h & ~0x30); + /* Enable chip interrupt output. */ + pci_read_config_byte(dev, 0x4a, ®4ah); + pci_write_config_byte(dev, 0x4a, reg4ah & ~0x01); + /* Enable burst mode. */ + pci_read_config_byte(dev, 0x4a, ®4ah); + pci_write_config_byte(dev, 0x4a, reg4ah | 0x80); + } + return dev->irq; } diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 7b589d948bf9..940bdd4c5784 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -1288,6 +1288,10 @@ static void __devinit hpt37x_clocking(ide_hwif_t *hwif) goto init_hpt37X_done; } } + if (!pci_get_drvdata(dev)) { + printk("No Clock Stabilization!!!\n"); + return; + } pll_recal: if (adjust & 1) pll -= (adjust >> 1); diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c index 108fda83fea4..38f41b377ff6 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/pci/it821x.c @@ -733,7 +733,7 @@ static void __devinit it8212_disable_raid(struct pci_dev *dev) pci_write_config_dword(dev,0x4C, 0x02040204); pci_write_config_byte(dev, 0x42, 0x36); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); } static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const char *name) diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index fe06ebb0e5bf..acd63173199b 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -420,9 +420,6 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = { .init_hwif = init_hwif_pdc202new, .channels = 2, .autodma = AUTODMA, -#ifndef CONFIG_PDC202XX_FORCE - .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, -#endif .bootable = OFF_BOARD, },{ /* 3 */ .name = "PDC20271", @@ -447,9 +444,6 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = { .init_hwif = init_hwif_pdc202new, .channels = 2, .autodma = AUTODMA, -#ifndef CONFIG_PDC202XX_FORCE - .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, -#endif .bootable = OFF_BOARD, },{ /* 6 */ .name = "PDC20277", diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index ad9d95817f95..6f8f8645b02c 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c @@ -786,9 +786,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = { .init_dma = init_dma_pdc202xx, .channels = 2, .autodma = AUTODMA, -#ifndef CONFIG_PDC202XX_FORCE - .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, -#endif .bootable = OFF_BOARD, .extra = 16, },{ /* 1 */ @@ -799,9 +796,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = { .init_dma = init_dma_pdc202xx, .channels = 2, .autodma = AUTODMA, -#ifndef CONFIG_PDC202XX_FORCE - .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, -#endif .bootable = OFF_BOARD, .extra = 48, .flags = IDEPCI_FLAG_FORCE_PDC, @@ -813,9 +807,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = { .init_dma = init_dma_pdc202xx, .channels = 2, .autodma = AUTODMA, -#ifndef CONFIG_PDC202XX_FORCE - .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, -#endif .bootable = OFF_BOARD, .extra = 48, },{ /* 3 */ @@ -826,9 +817,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = { .init_dma = init_dma_pdc202xx, .channels = 2, .autodma = AUTODMA, -#ifndef CONFIG_PDC202XX_FORCE - .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, -#endif .bootable = OFF_BOARD, .extra = 48, .flags = IDEPCI_FLAG_FORCE_PDC, @@ -840,9 +828,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = { .init_dma = init_dma_pdc202xx, .channels = 2, .autodma = AUTODMA, -#ifndef CONFIG_PDC202XX_FORCE - .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, -#endif .bootable = OFF_BOARD, .extra = 48, } diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index b3e77df63cef..e9b83e1a3028 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -135,6 +135,7 @@ static u8 piix_ratemask (ide_drive_t *drive) case PCI_DEVICE_ID_INTEL_ICH6_19: case PCI_DEVICE_ID_INTEL_ICH7_21: case PCI_DEVICE_ID_INTEL_ESB2_18: + case PCI_DEVICE_ID_INTEL_ICH8_6: mode = 3; break; /* UDMA 66 capable */ @@ -449,6 +450,7 @@ static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char case PCI_DEVICE_ID_INTEL_ICH6_19: case PCI_DEVICE_ID_INTEL_ICH7_21: case PCI_DEVICE_ID_INTEL_ESB2_18: + case PCI_DEVICE_ID_INTEL_ICH8_6: { unsigned int extra = 0; pci_read_config_dword(dev, 0x54, &extra); @@ -575,6 +577,7 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = { /* 21 */ DECLARE_PIIX_DEV("ICH7"), /* 22 */ DECLARE_PIIX_DEV("ICH4"), /* 23 */ DECLARE_PIIX_DEV("ESB2"), + /* 24 */ DECLARE_PIIX_DEV("ICH8M"), }; /** @@ -651,6 +654,7 @@ static struct pci_device_id piix_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 21}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 22}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 23}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 24}, { 0, }, }; MODULE_DEVICE_TABLE(pci, piix_pci_tbl); diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index 4ee597d08797..2b286e865163 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2003-2006 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -510,7 +510,7 @@ sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir) drive->name); goto use_pio_instead; } else { - u32 xcount, bcount = + u32 bcount = 0x10000 - (cur_addr & 0xffff); if (bcount > cur_len) @@ -525,8 +525,7 @@ sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir) *table = 0x0; table++; - xcount = bcount & 0xffff; - *table = cpu_to_be32(xcount); + *table = cpu_to_be32(bcount); table++; cur_addr += bcount; @@ -680,7 +679,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) return -EIO; /* Create /proc/ide entries */ - create_proc_ide_interfaces(); + create_proc_ide_interfaces(); return 0; } diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 1b85ce166af8..11fe537e2f6f 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -216,7 +216,7 @@ struct Layer1 { #define GROUP_TEI 127 #define TEI_SAPI 63 #define CTRL_SAPI 0 -#define PACKET_NOACK 250 +#define PACKET_NOACK 7 /* Layer2 Flags */ diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c index 3314a5a19854..94c9afb7017c 100644 --- a/drivers/isdn/sc/ioctl.c +++ b/drivers/isdn/sc/ioctl.c @@ -71,14 +71,14 @@ int sc_ioctl(int card, scs_ioctl *data) /* * Get the SRec from user space */ - if (copy_from_user(srec, data->dataptr, sizeof(srec))) { + if (copy_from_user(srec, data->dataptr, SCIOC_SRECSIZE)) { kfree(rcvmsg); kfree(srec); return -EFAULT; } status = send_and_receive(card, CMPID, cmReqType2, cmReqClass0, cmReqLoadProc, - 0, sizeof(srec), srec, rcvmsg, SAR_TIMEOUT); + 0, SCIOC_SRECSIZE, srec, rcvmsg, SAR_TIMEOUT); kfree(rcvmsg); kfree(srec); diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index 74039db846ba..d73779a42417 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c @@ -545,7 +545,8 @@ static int core_get_resync_work(struct dirty_log *log, region_t *region) return 0; do { - *region = find_next_zero_bit((unsigned long *) lc->sync_bits, + *region = ext2_find_next_zero_bit( + (unsigned long *) lc->sync_bits, lc->region_count, lc->sync_search); lc->sync_search = *region + 1; diff --git a/drivers/md/md.c b/drivers/md/md.c index 7145cd150f7b..d05e3125d298 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1024,7 +1024,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) rdev-> sb_size = (rdev->sb_size | bmask)+1; if (refdev == 0) - return 1; + ret = 1; else { __u64 ev1, ev2; struct mdp_superblock_1 *refsb = @@ -1044,7 +1044,9 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) ev2 = le64_to_cpu(refsb->events); if (ev1 > ev2) - return 1; + ret = 1; + else + ret = 0; } if (minor_version) rdev->size = ((rdev->bdev->bd_inode->i_size>>9) - le64_to_cpu(sb->data_offset)) / 2; @@ -1058,7 +1060,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) if (le32_to_cpu(sb->size) > rdev->size*2) return -EINVAL; - return 0; + return ret; } static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) @@ -1081,7 +1083,7 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) mddev->size = le64_to_cpu(sb->size)/2; mddev->events = le64_to_cpu(sb->events); mddev->bitmap_offset = 0; - mddev->default_bitmap_offset = 1024; + mddev->default_bitmap_offset = 1024 >> 9; mddev->recovery_cp = le64_to_cpu(sb->resync_offset); memcpy(mddev->uuid, sb->set_uuid, 16); @@ -1161,6 +1163,9 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) sb->cnt_corrected_read = atomic_read(&rdev->corrected_errors); + sb->raid_disks = cpu_to_le32(mddev->raid_disks); + sb->size = cpu_to_le64(mddev->size<<1); + if (mddev->bitmap && mddev->bitmap_file == NULL) { sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset); sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET); @@ -2686,14 +2691,6 @@ static int do_md_stop(mddev_t * mddev, int ro) set_disk_ro(disk, 1); } - bitmap_destroy(mddev); - if (mddev->bitmap_file) { - atomic_set(&mddev->bitmap_file->f_dentry->d_inode->i_writecount, 1); - fput(mddev->bitmap_file); - mddev->bitmap_file = NULL; - } - mddev->bitmap_offset = 0; - /* * Free resources if final stop */ @@ -2703,6 +2700,14 @@ static int do_md_stop(mddev_t * mddev, int ro) struct gendisk *disk; printk(KERN_INFO "md: %s stopped.\n", mdname(mddev)); + bitmap_destroy(mddev); + if (mddev->bitmap_file) { + atomic_set(&mddev->bitmap_file->f_dentry->d_inode->i_writecount, 1); + fput(mddev->bitmap_file); + mddev->bitmap_file = NULL; + } + mddev->bitmap_offset = 0; + ITERATE_RDEV(mddev,rdev,tmp) if (rdev->raid_disk >= 0) { char nm[20]; @@ -2939,6 +2944,8 @@ static int get_array_info(mddev_t * mddev, void __user * arg) info.ctime = mddev->ctime; info.level = mddev->level; info.size = mddev->size; + if (info.size != mddev->size) /* overflow */ + info.size = -1; info.nr_disks = nr; info.raid_disks = mddev->raid_disks; info.md_minor = mddev->md_minor; @@ -3465,7 +3472,7 @@ static int update_size(mddev_t *mddev, unsigned long size) bdev = bdget_disk(mddev->gendisk, 0); if (bdev) { mutex_lock(&bdev->bd_inode->i_mutex); - i_size_write(bdev->bd_inode, mddev->array_size << 10); + i_size_write(bdev->bd_inode, (loff_t)mddev->array_size << 10); mutex_unlock(&bdev->bd_inode->i_mutex); bdput(bdev); } @@ -3485,17 +3492,6 @@ static int update_raid_disks(mddev_t *mddev, int raid_disks) if (mddev->sync_thread) return -EBUSY; rv = mddev->pers->reshape(mddev, raid_disks); - if (!rv) { - struct block_device *bdev; - - bdev = bdget_disk(mddev->gendisk, 0); - if (bdev) { - mutex_lock(&bdev->bd_inode->i_mutex); - i_size_write(bdev->bd_inode, mddev->array_size << 10); - mutex_unlock(&bdev->bd_inode->i_mutex); - bdput(bdev); - } - } return rv; } @@ -3531,7 +3527,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info) ) return -EINVAL; /* Check there is only one change */ - if (mddev->size != info->size) cnt++; + if (info->size >= 0 && mddev->size != info->size) cnt++; if (mddev->raid_disks != info->raid_disks) cnt++; if (mddev->layout != info->layout) cnt++; if ((state ^ info->state) & (1<<MD_SB_BITMAP_PRESENT)) cnt++; @@ -3548,7 +3544,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info) else return mddev->pers->reconfig(mddev, info->layout, -1); } - if (mddev->size != info->size) + if (info->size >= 0 && mddev->size != info->size) rv = update_size(mddev, info->size); if (mddev->raid_disks != info->raid_disks) diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index d03f99cf4b7d..678f4dbbea1d 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -372,7 +372,7 @@ out_free_conf: kfree(conf); mddev->private = NULL; out: - return 1; + return -ENOMEM; } static int raid0_stop (mddev_t *mddev) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 9130d051b474..ab90a6d12020 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -565,6 +565,8 @@ rb_out: if (disk >= 0 && (rdev=rcu_dereference(conf->mirrors[disk].rdev))!= NULL) atomic_inc(&conf->mirrors[disk].rdev->nr_pending); + else + disk = -1; rcu_read_unlock(); return disk; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 25976bfb6f9c..2dba305daf3c 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -350,7 +350,8 @@ static void shrink_stripes(raid5_conf_t *conf) while (drop_one_stripe(conf)) ; - kmem_cache_destroy(conf->slab_cache); + if (conf->slab_cache) + kmem_cache_destroy(conf->slab_cache); conf->slab_cache = NULL; } diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index f618a53b98be..cd477ebf2ee4 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -115,7 +115,7 @@ static void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh) list_add_tail(&sh->lru, &conf->inactive_list); atomic_dec(&conf->active_stripes); if (!conf->inactive_blocked || - atomic_read(&conf->active_stripes) < (NR_STRIPES*3/4)) + atomic_read(&conf->active_stripes) < (conf->max_nr_stripes*3/4)) wake_up(&conf->wait_for_stripe); } } @@ -273,7 +273,8 @@ static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector conf->inactive_blocked = 1; wait_event_lock_irq(conf->wait_for_stripe, !list_empty(&conf->inactive_list) && - (atomic_read(&conf->active_stripes) < (NR_STRIPES *3/4) + (atomic_read(&conf->active_stripes) + < (conf->max_nr_stripes *3/4) || !conf->inactive_blocked), conf->device_lock, unplug_slaves(conf->mddev); @@ -302,9 +303,31 @@ static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector return sh; } -static int grow_stripes(raid6_conf_t *conf, int num) +static int grow_one_stripe(raid6_conf_t *conf) { struct stripe_head *sh; + sh = kmem_cache_alloc(conf->slab_cache, GFP_KERNEL); + if (!sh) + return 0; + memset(sh, 0, sizeof(*sh) + (conf->raid_disks-1)*sizeof(struct r5dev)); + sh->raid_conf = conf; + spin_lock_init(&sh->lock); + + if (grow_buffers(sh, conf->raid_disks)) { + shrink_buffers(sh, conf->raid_disks); + kmem_cache_free(conf->slab_cache, sh); + return 0; + } + /* we just created an active stripe so... */ + atomic_set(&sh->count, 1); + atomic_inc(&conf->active_stripes); + INIT_LIST_HEAD(&sh->lru); + release_stripe(sh); + return 1; +} + +static int grow_stripes(raid6_conf_t *conf, int num) +{ kmem_cache_t *sc; int devs = conf->raid_disks; @@ -316,45 +339,35 @@ static int grow_stripes(raid6_conf_t *conf, int num) if (!sc) return 1; conf->slab_cache = sc; - while (num--) { - sh = kmem_cache_alloc(sc, GFP_KERNEL); - if (!sh) - return 1; - memset(sh, 0, sizeof(*sh) + (devs-1)*sizeof(struct r5dev)); - sh->raid_conf = conf; - spin_lock_init(&sh->lock); - - if (grow_buffers(sh, conf->raid_disks)) { - shrink_buffers(sh, conf->raid_disks); - kmem_cache_free(sc, sh); + while (num--) + if (!grow_one_stripe(conf)) return 1; - } - /* we just created an active stripe so... */ - atomic_set(&sh->count, 1); - atomic_inc(&conf->active_stripes); - INIT_LIST_HEAD(&sh->lru); - release_stripe(sh); - } return 0; } -static void shrink_stripes(raid6_conf_t *conf) +static int drop_one_stripe(raid6_conf_t *conf) { struct stripe_head *sh; + spin_lock_irq(&conf->device_lock); + sh = get_free_stripe(conf); + spin_unlock_irq(&conf->device_lock); + if (!sh) + return 0; + if (atomic_read(&sh->count)) + BUG(); + shrink_buffers(sh, conf->raid_disks); + kmem_cache_free(conf->slab_cache, sh); + atomic_dec(&conf->active_stripes); + return 1; +} - while (1) { - spin_lock_irq(&conf->device_lock); - sh = get_free_stripe(conf); - spin_unlock_irq(&conf->device_lock); - if (!sh) - break; - if (atomic_read(&sh->count)) - BUG(); - shrink_buffers(sh, conf->raid_disks); - kmem_cache_free(conf->slab_cache, sh); - atomic_dec(&conf->active_stripes); - } - kmem_cache_destroy(conf->slab_cache); +static void shrink_stripes(raid6_conf_t *conf) +{ + while (drop_one_stripe(conf)) + ; + + if (conf->slab_cache) + kmem_cache_destroy(conf->slab_cache); conf->slab_cache = NULL; } @@ -1912,6 +1925,74 @@ static void raid6d (mddev_t *mddev) PRINTK("--- raid6d inactive\n"); } +static ssize_t +raid6_show_stripe_cache_size(mddev_t *mddev, char *page) +{ + raid6_conf_t *conf = mddev_to_conf(mddev); + if (conf) + return sprintf(page, "%d\n", conf->max_nr_stripes); + else + return 0; +} + +static ssize_t +raid6_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len) +{ + raid6_conf_t *conf = mddev_to_conf(mddev); + char *end; + int new; + if (len >= PAGE_SIZE) + return -EINVAL; + if (!conf) + return -ENODEV; + + new = simple_strtoul(page, &end, 10); + if (!*page || (*end && *end != '\n') ) + return -EINVAL; + if (new <= 16 || new > 32768) + return -EINVAL; + while (new < conf->max_nr_stripes) { + if (drop_one_stripe(conf)) + conf->max_nr_stripes--; + else + break; + } + while (new > conf->max_nr_stripes) { + if (grow_one_stripe(conf)) + conf->max_nr_stripes++; + else break; + } + return len; +} + +static struct md_sysfs_entry +raid6_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR, + raid6_show_stripe_cache_size, + raid6_store_stripe_cache_size); + +static ssize_t +stripe_cache_active_show(mddev_t *mddev, char *page) +{ + raid6_conf_t *conf = mddev_to_conf(mddev); + if (conf) + return sprintf(page, "%d\n", atomic_read(&conf->active_stripes)); + else + return 0; +} + +static struct md_sysfs_entry +raid6_stripecache_active = __ATTR_RO(stripe_cache_active); + +static struct attribute *raid6_attrs[] = { + &raid6_stripecache_size.attr, + &raid6_stripecache_active.attr, + NULL, +}; +static struct attribute_group raid6_attrs_group = { + .name = NULL, + .attrs = raid6_attrs, +}; + static int run(mddev_t *mddev) { raid6_conf_t *conf; @@ -2095,6 +2176,7 @@ static int stop (mddev_t *mddev) shrink_stripes(conf); kfree(conf->stripe_hashtbl); blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ + sysfs_remove_group(&mddev->kobj, &raid6_attrs_group); kfree(conf); mddev->private = NULL; return 0; diff --git a/drivers/message/i2o/core.h b/drivers/message/i2o/core.h index 90628562851e..184974cc734d 100644 --- a/drivers/message/i2o/core.h +++ b/drivers/message/i2o/core.h @@ -60,4 +60,7 @@ extern void i2o_iop_remove(struct i2o_controller *); #define I2O_IN_PORT 0x40 #define I2O_OUT_PORT 0x44 +/* Motorola/Freescale specific register offset */ +#define I2O_MOTOROLA_PORT_OFFSET 0x10400 + #define I2O_IRQ_OUTBOUND_POST 0x00000008 diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c index d698d7709c31..4f1515cae5dc 100644 --- a/drivers/message/i2o/pci.c +++ b/drivers/message/i2o/pci.c @@ -88,6 +88,11 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c) struct device *dev = &pdev->dev; int i; + if (pci_request_regions(pdev, OSM_DESCRIPTION)) { + printk(KERN_ERR "%s: device already claimed\n", c->name); + return -ENODEV; + } + for (i = 0; i < 6; i++) { /* Skip I/O spaces */ if (!(pci_resource_flags(pdev, i) & IORESOURCE_IO)) { @@ -163,6 +168,24 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c) c->in_port = c->base.virt + I2O_IN_PORT; c->out_port = c->base.virt + I2O_OUT_PORT; + /* Motorola/Freescale chip does not follow spec */ + if (pdev->vendor == PCI_VENDOR_ID_MOTOROLA && pdev->device == 0x18c0) { + /* Check if CPU is enabled */ + if (be32_to_cpu(readl(c->base.virt + 0x10000)) & 0x10000000) { + printk(KERN_INFO "%s: MPC82XX needs CPU running to " + "service I2O.\n", c->name); + i2o_pci_free(c); + return -ENODEV; + } else { + c->irq_status += I2O_MOTOROLA_PORT_OFFSET; + c->irq_mask += I2O_MOTOROLA_PORT_OFFSET; + c->in_port += I2O_MOTOROLA_PORT_OFFSET; + c->out_port += I2O_MOTOROLA_PORT_OFFSET; + printk(KERN_INFO "%s: MPC82XX workarounds activated.\n", + c->name); + } + } + if (i2o_dma_alloc(dev, &c->status, 8, GFP_KERNEL)) { i2o_pci_free(c); return -ENOMEM; @@ -298,7 +321,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev, struct i2o_controller *c; int rc; struct pci_dev *i960 = NULL; - int pci_dev_busy = 0; + int enabled = pdev->is_enabled; printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n"); @@ -308,16 +331,12 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev, return -ENODEV; } - if ((rc = pci_enable_device(pdev))) { - printk(KERN_WARNING "i2o: couldn't enable device %s\n", - pci_name(pdev)); - return rc; - } - - if (pci_request_regions(pdev, OSM_DESCRIPTION)) { - printk(KERN_ERR "i2o: device already claimed\n"); - return -ENODEV; - } + if (!enabled) + if ((rc = pci_enable_device(pdev))) { + printk(KERN_WARNING "i2o: couldn't enable device %s\n", + pci_name(pdev)); + return rc; + } if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { printk(KERN_WARNING "i2o: no suitable DMA found for %s\n", @@ -395,9 +414,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev, if ((rc = i2o_pci_alloc(c))) { printk(KERN_ERR "%s: DMA / IO allocation for I2O controller " - " failed\n", c->name); - if (rc == -ENODEV) - pci_dev_busy = 1; + "failed\n", c->name); goto free_controller; } @@ -425,7 +442,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev, i2o_iop_free(c); disable: - if (!pci_dev_busy) + if (!enabled) pci_disable_device(pdev); return rc; diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c index aaf04638054e..227c39a7c1b4 100644 --- a/drivers/mmc/au1xmmc.c +++ b/drivers/mmc/au1xmmc.c @@ -194,7 +194,7 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT); - switch(cmd->flags) { + switch (mmc_rsp_type(cmd->flags)) { case MMC_RSP_R1: mmccmd |= SD_CMD_RT_1; break; @@ -483,34 +483,35 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) cmd = mrq->cmd; cmd->error = MMC_ERR_NONE; - if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_SHORT) { - - /* Techincally, we should be getting all 48 bits of the response - * (SD_RESP1 + SD_RESP2), but because our response omits the CRC, - * our data ends up being shifted 8 bits to the right. In this case, - * that means that the OSR data starts at bit 31, so we can just - * read RESP0 and return that - */ - - cmd->resp[0] = au_readl(host->iobase + SD_RESP0); - } - else if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_LONG) { - u32 r[4]; - int i; - - r[0] = au_readl(host->iobase + SD_RESP3); - r[1] = au_readl(host->iobase + SD_RESP2); - r[2] = au_readl(host->iobase + SD_RESP1); - r[3] = au_readl(host->iobase + SD_RESP0); - - /* The CRC is omitted from the response, so really we only got - * 120 bytes, but the engine expects 128 bits, so we have to shift - * things up - */ - - for(i = 0; i < 4; i++) { - cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8; - if (i != 3) cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24; + if (cmd->flags & MMC_RSP_PRESENT) { + if (cmd->flags & MMC_RSP_136) { + u32 r[4]; + int i; + + r[0] = au_readl(host->iobase + SD_RESP3); + r[1] = au_readl(host->iobase + SD_RESP2); + r[2] = au_readl(host->iobase + SD_RESP1); + r[3] = au_readl(host->iobase + SD_RESP0); + + /* The CRC is omitted from the response, so really + * we only got 120 bytes, but the engine expects + * 128 bits, so we have to shift things up + */ + + for(i = 0; i < 4; i++) { + cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8; + if (i != 3) + cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24; + } + } else { + /* Techincally, we should be getting all 48 bits of + * the response (SD_RESP1 + SD_RESP2), but because + * our response omits the CRC, our data ends up + * being shifted 8 bits to the right. In this case, + * that means that the OSR data starts at bit 31, + * so we can just read RESP0 and return that + */ + cmd->resp[0] = au_readl(host->iobase + SD_RESP0); } } diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index bfca5c176e88..1888060c5e0c 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -211,7 +211,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca, appcmd.opcode = MMC_APP_CMD; appcmd.arg = rca << 16; - appcmd.flags = MMC_RSP_R1; + appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC; appcmd.retries = 0; memset(appcmd.resp, 0, sizeof(appcmd.resp)); appcmd.data = NULL; @@ -331,7 +331,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card) cmd.opcode = MMC_SELECT_CARD; cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); if (err != MMC_ERR_NONE) @@ -358,7 +358,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card) struct mmc_command cmd; cmd.opcode = SD_APP_SET_BUS_WIDTH; cmd.arg = SD_BUS_WIDTH_4; - cmd.flags = MMC_RSP_R1; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_app_cmd(host, card->rca, &cmd, CMD_RETRIES); @@ -386,7 +386,7 @@ static void mmc_deselect_cards(struct mmc_host *host) cmd.opcode = MMC_SELECT_CARD; cmd.arg = 0; - cmd.flags = MMC_RSP_NONE; + cmd.flags = MMC_RSP_NONE | MMC_CMD_AC; mmc_wait_for_cmd(host, &cmd, 0); } @@ -677,7 +677,7 @@ static void mmc_idle_cards(struct mmc_host *host) cmd.opcode = MMC_GO_IDLE_STATE; cmd.arg = 0; - cmd.flags = MMC_RSP_NONE; + cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; mmc_wait_for_cmd(host, &cmd, 0); @@ -738,7 +738,7 @@ static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) cmd.opcode = MMC_SEND_OP_COND; cmd.arg = ocr; - cmd.flags = MMC_RSP_R3; + cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; for (i = 100; i; i--) { err = mmc_wait_for_cmd(host, &cmd, 0); @@ -766,7 +766,7 @@ static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) cmd.opcode = SD_APP_OP_COND; cmd.arg = ocr; - cmd.flags = MMC_RSP_R3; + cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; for (i = 100; i; i--) { err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES); @@ -805,7 +805,7 @@ static void mmc_discover_cards(struct mmc_host *host) cmd.opcode = MMC_ALL_SEND_CID; cmd.arg = 0; - cmd.flags = MMC_RSP_R2; + cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); if (err == MMC_ERR_TIMEOUT) { @@ -835,7 +835,7 @@ static void mmc_discover_cards(struct mmc_host *host) cmd.opcode = SD_SEND_RELATIVE_ADDR; cmd.arg = 0; - cmd.flags = MMC_RSP_R6; + cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); if (err != MMC_ERR_NONE) @@ -856,7 +856,7 @@ static void mmc_discover_cards(struct mmc_host *host) } else { cmd.opcode = MMC_SET_RELATIVE_ADDR; cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); if (err != MMC_ERR_NONE) @@ -878,7 +878,7 @@ static void mmc_read_csds(struct mmc_host *host) cmd.opcode = MMC_SEND_CSD; cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R2; + cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); if (err != MMC_ERR_NONE) { @@ -920,7 +920,7 @@ static void mmc_read_scrs(struct mmc_host *host) cmd.opcode = MMC_APP_CMD; cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(host, &cmd, 0); if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) { @@ -932,7 +932,7 @@ static void mmc_read_scrs(struct mmc_host *host) cmd.opcode = SD_APP_SEND_SCR; cmd.arg = 0; - cmd.flags = MMC_RSP_R1; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; memset(&data, 0, sizeof(struct mmc_data)); @@ -1003,7 +1003,7 @@ static void mmc_check_cards(struct mmc_host *host) cmd.opcode = MMC_SEND_STATUS; cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); if (err == MMC_ERR_NONE) diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index 5b014c370e80..8eb2a2ede64b 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -171,14 +171,14 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.mrq.data = &brq.data; brq.cmd.arg = req->sector << 9; - brq.cmd.flags = MMC_RSP_R1; + brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; brq.data.timeout_ns = card->csd.tacc_ns * 10; brq.data.timeout_clks = card->csd.tacc_clks * 10; brq.data.blksz_bits = md->block_bits; brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); brq.stop.opcode = MMC_STOP_TRANSMISSION; brq.stop.arg = 0; - brq.stop.flags = MMC_RSP_R1B; + brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC; if (rq_data_dir(req) == READ) { brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK; @@ -223,7 +223,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) cmd.opcode = MMC_SEND_STATUS; cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 5); if (err) { printk(KERN_ERR "%s: error %d requesting status\n", @@ -430,7 +430,7 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) mmc_card_claim_host(card); cmd.opcode = MMC_SET_BLOCKLEN; cmd.arg = 1 << md->block_bits; - cmd.flags = MMC_RSP_R1; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 5); mmc_card_release_host(card); diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 634ef53e85a5..37ee7f8dc82f 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -124,15 +124,10 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) } c |= cmd->opcode | MCI_CPSM_ENABLE; - switch (cmd->flags & MMC_RSP_MASK) { - case MMC_RSP_NONE: - default: - break; - case MMC_RSP_LONG: - c |= MCI_CPSM_LONGRSP; - case MMC_RSP_SHORT: + if (cmd->flags & MMC_RSP_PRESENT) { + if (cmd->flags & MMC_RSP_136) + c |= MCI_CPSM_LONGRSP; c |= MCI_CPSM_RESPONSE; - break; } if (/*interrupt*/0) c |= MCI_CPSM_INTERRUPT; diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index ee8f8a0420d1..285d7d068097 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -178,14 +178,15 @@ static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, if (cmd->flags & MMC_RSP_BUSY) cmdat |= CMDAT_BUSY; - switch (cmd->flags & (MMC_RSP_MASK | MMC_RSP_CRC)) { - case MMC_RSP_SHORT | MMC_RSP_CRC: +#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) + switch (RSP_TYPE(mmc_resp_type(cmd))) { + case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6 */ cmdat |= CMDAT_RESP_SHORT; break; - case MMC_RSP_SHORT: + case RSP_TYPE(MMC_RSP_R3): cmdat |= CMDAT_RESP_R3; break; - case MMC_RSP_LONG | MMC_RSP_CRC: + case RSP_TYPE(MMC_RSP_R2): cmdat |= CMDAT_RESP_R2; break; default: diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index f25757625361..3be397d436fa 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -459,7 +459,7 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd) /* * Do we expect a reply? */ - if ((cmd->flags & MMC_RSP_MASK) != MMC_RSP_NONE) { + if (cmd->flags & MMC_RSP_PRESENT) { /* * Read back status. */ @@ -476,10 +476,10 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd) cmd->error = MMC_ERR_BADCRC; /* All ok */ else { - if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_SHORT) - wbsd_get_short_reply(host, cmd); - else + if (cmd->flags & MMC_RSP_136) wbsd_get_long_reply(host, cmd); + else + wbsd_get_short_reply(host, cmd); } } diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c index 701620b6baed..8b3784e2de89 100644 --- a/drivers/mtd/maps/dc21285.c +++ b/drivers/mtd/maps/dc21285.c @@ -110,8 +110,9 @@ static void dc21285_copy_to_32(struct map_info *map, unsigned long to, const voi { while (len > 0) { map_word d; - d.x[0] = *((uint32_t*)from)++; + d.x[0] = *((uint32_t*)from); dc21285_write32(map, d, to); + from += 4; to += 4; len -= 4; } @@ -121,8 +122,9 @@ static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const voi { while (len > 0) { map_word d; - d.x[0] = *((uint16_t*)from)++; + d.x[0] = *((uint16_t*)from); dc21285_write16(map, d, to); + from += 2; to += 2; len -= 2; } @@ -131,8 +133,9 @@ static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const voi static void dc21285_copy_to_8(struct map_info *map, unsigned long to, const void *from, ssize_t len) { map_word d; - d.x[0] = *((uint8_t*)from)++; + d.x[0] = *((uint8_t*)from); dc21285_write8(map, d, to); + from++; to++; len--; } diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 7488ee7f7caf..7f47124f118d 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -753,9 +753,11 @@ enum tx_desc_status { enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 }; struct vortex_extra_stats { - unsigned long tx_deferred; - unsigned long tx_multiple_collisions; - unsigned long rx_bad_ssd; + unsigned long tx_deferred; + unsigned long tx_max_collisions; + unsigned long tx_multiple_collisions; + unsigned long tx_single_collisions; + unsigned long rx_bad_ssd; }; struct vortex_private { @@ -863,12 +865,14 @@ static struct { const char str[ETH_GSTRING_LEN]; } ethtool_stats_keys[] = { { "tx_deferred" }, + { "tx_max_collisions" }, { "tx_multiple_collisions" }, + { "tx_single_collisions" }, { "rx_bad_ssd" }, }; /* number of ETHTOOL_GSTATS u64's */ -#define VORTEX_NUM_STATS 3 +#define VORTEX_NUM_STATS 5 static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq, int chip_idx, int card_idx); @@ -2108,9 +2112,12 @@ vortex_error(struct net_device *dev, int status) iowrite8(0, ioaddr + TxStatus); if (tx_status & 0x30) { /* txJabber or txUnderrun */ do_tx_reset = 1; - } else if ((tx_status & 0x08) && (vp->drv_flags & MAX_COLLISION_RESET)) { /* maxCollisions */ - do_tx_reset = 1; - reset_mask = 0x0108; /* Reset interface logic, but not download logic */ + } else if (tx_status & 0x08) { /* maxCollisions */ + vp->xstats.tx_max_collisions++; + if (vp->drv_flags & MAX_COLLISION_RESET) { + do_tx_reset = 1; + reset_mask = 0x0108; /* Reset interface logic, but not download logic */ + } } else { /* Merely re-enable the transmitter. */ iowrite16(TxEnable, ioaddr + EL3_CMD); } @@ -2926,7 +2933,6 @@ static void update_stats(void __iomem *ioaddr, struct net_device *dev) EL3WINDOW(6); vp->stats.tx_carrier_errors += ioread8(ioaddr + 0); vp->stats.tx_heartbeat_errors += ioread8(ioaddr + 1); - vp->stats.collisions += ioread8(ioaddr + 3); vp->stats.tx_window_errors += ioread8(ioaddr + 4); vp->stats.rx_fifo_errors += ioread8(ioaddr + 5); vp->stats.tx_packets += ioread8(ioaddr + 6); @@ -2939,10 +2945,15 @@ static void update_stats(void __iomem *ioaddr, struct net_device *dev) vp->stats.tx_bytes += ioread16(ioaddr + 12); /* Extra stats for get_ethtool_stats() */ vp->xstats.tx_multiple_collisions += ioread8(ioaddr + 2); + vp->xstats.tx_single_collisions += ioread8(ioaddr + 3); vp->xstats.tx_deferred += ioread8(ioaddr + 8); EL3WINDOW(4); vp->xstats.rx_bad_ssd += ioread8(ioaddr + 12); + vp->stats.collisions = vp->xstats.tx_multiple_collisions + + vp->xstats.tx_single_collisions + + vp->xstats.tx_max_collisions; + { u8 up = ioread8(ioaddr + 13); vp->stats.rx_bytes += (up & 0x0f) << 16; @@ -3036,8 +3047,10 @@ static void vortex_get_ethtool_stats(struct net_device *dev, spin_unlock_irqrestore(&vp->lock, flags); data[0] = vp->xstats.tx_deferred; - data[1] = vp->xstats.tx_multiple_collisions; - data[2] = vp->xstats.rx_bad_ssd; + data[1] = vp->xstats.tx_max_collisions; + data[2] = vp->xstats.tx_multiple_collisions; + data[3] = vp->xstats.tx_single_collisions; + data[4] = vp->xstats.rx_bad_ssd; } diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f2d1dafde087..e7dc653d5bd6 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -69,8 +69,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.48" -#define DRV_MODULE_RELDATE "Jan 16, 2006" +#define DRV_MODULE_VERSION "3.49" +#define DRV_MODULE_RELDATE "Feb 2, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -3482,6 +3482,17 @@ static void tg3_reset_task(void *_data) struct tg3 *tp = _data; unsigned int restart_timer; + tg3_full_lock(tp, 0); + tp->tg3_flags |= TG3_FLAG_IN_RESET_TASK; + + if (!netif_running(tp->dev)) { + tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK; + tg3_full_unlock(tp); + return; + } + + tg3_full_unlock(tp); + tg3_netif_stop(tp); tg3_full_lock(tp, 1); @@ -3494,10 +3505,12 @@ static void tg3_reset_task(void *_data) tg3_netif_start(tp); - tg3_full_unlock(tp); - if (restart_timer) mod_timer(&tp->timer, jiffies + 1); + + tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK; + + tg3_full_unlock(tp); } static void tg3_tx_timeout(struct net_device *dev) @@ -6786,6 +6799,13 @@ static int tg3_close(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); + /* Calling flush_scheduled_work() may deadlock because + * linkwatch_event() may be on the workqueue and it will try to get + * the rtnl_lock which we are holding. + */ + while (tp->tg3_flags & TG3_FLAG_IN_RESET_TASK) + msleep(1); + netif_stop_queue(dev); del_timer_sync(&tp->timer); @@ -10880,6 +10900,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) if (dev) { struct tg3 *tp = netdev_priv(dev); + flush_scheduled_work(); unregister_netdev(dev); if (tp->regs) { iounmap(tp->regs); @@ -10901,6 +10922,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) if (!netif_running(dev)) return 0; + flush_scheduled_work(); tg3_netif_stop(tp); del_timer_sync(&tp->timer); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index e8243305f0e8..7f4b7f6ac40d 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2162,6 +2162,7 @@ struct tg3 { #define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000 #define TG3_FLAG_10_100_ONLY 0x01000000 #define TG3_FLAG_PAUSE_AUTONEG 0x02000000 +#define TG3_FLAG_IN_RESET_TASK 0x04000000 #define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 #define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000 #define TG3_FLAG_SPLIT_MODE 0x40000000 diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index f605dea57224..f63c387976cf 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -90,6 +90,15 @@ config PARPORT_ARC depends on ARM && PARPORT select PARPORT_NOT_PC +config PARPORT_IP32 + tristate "SGI IP32 builtin port (EXPERIMENTAL)" + depends on SGI_IP32 && PARPORT && EXPERIMENTAL + select PARPORT_NOT_PC + help + Say Y here if you need support for the parallel port on + SGI O2 machines. This code is also available as a module (say M), + called parport_ip32. If in doubt, saying N is the safe plan. + config PARPORT_AMIGA tristate "Amiga builtin port" depends on AMIGA && PARPORT diff --git a/drivers/parport/Makefile b/drivers/parport/Makefile index 5372212bb9d9..a19de35f8de2 100644 --- a/drivers/parport/Makefile +++ b/drivers/parport/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_PARPORT_MFC3) += parport_mfc3.o obj-$(CONFIG_PARPORT_ATARI) += parport_atari.o obj-$(CONFIG_PARPORT_SUNBPP) += parport_sunbpp.o obj-$(CONFIG_PARPORT_GSC) += parport_gsc.o +obj-$(CONFIG_PARPORT_IP32) += parport_ip32.o diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c index 5b887ba5aaf9..690b239ad3a7 100644 --- a/drivers/parport/ieee1284.c +++ b/drivers/parport/ieee1284.c @@ -61,10 +61,10 @@ static void timeout_waiting_on_port (unsigned long cookie) * set to zero, it returns immediately. * * If an interrupt occurs before the timeout period elapses, this - * function returns one immediately. If it times out, it returns - * a value greater than zero. An error code less than zero - * indicates an error (most likely a pending signal), and the - * calling code should finish what it's doing as soon as it can. + * function returns zero immediately. If it times out, it returns + * one. An error code less than zero indicates an error (most + * likely a pending signal), and the calling code should finish + * what it's doing as soon as it can. */ int parport_wait_event (struct parport *port, signed long timeout) @@ -110,7 +110,7 @@ int parport_wait_event (struct parport *port, signed long timeout) * * If the status lines take on the desired values before the * timeout period elapses, parport_poll_peripheral() returns zero - * immediately. A zero return value greater than zero indicates + * immediately. A return value greater than zero indicates * a timeout. An error code (less than zero) indicates an error, * most likely a signal that arrived, and the caller should * finish what it is doing as soon as possible. diff --git a/drivers/parport/parport_ip32.c b/drivers/parport/parport_ip32.c new file mode 100644 index 000000000000..46e06e596d73 --- /dev/null +++ b/drivers/parport/parport_ip32.c @@ -0,0 +1,2253 @@ +/* Low-level parallel port routines for built-in port on SGI IP32 + * + * Author: Arnaud Giersch <arnaud.giersch@free.fr> + * + * Based on parport_pc.c by + * Phil Blundell, Tim Waugh, Jose Renau, David Campbell, + * Andrea Arcangeli, et al. + * + * Thanks to Ilya A. Volynets-Evenbakh for his help. + * + * Copyright (C) 2005, 2006 Arnaud Giersch. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Current status: + * + * Basic SPP and PS2 modes are supported. + * Support for parallel port IRQ is present. + * Hardware SPP (a.k.a. compatibility), EPP, and ECP modes are + * supported. + * SPP/ECP FIFO can be driven in PIO or DMA mode. PIO mode can work with + * or without interrupt support. + * + * Hardware ECP mode is not fully implemented (ecp_read_data and + * ecp_write_addr are actually missing). + * + * To do: + * + * Fully implement ECP mode. + * EPP and ECP mode need to be tested. I currently do not own any + * peripheral supporting these extended mode, and cannot test them. + * If DMA mode works well, decide if support for PIO FIFO modes should be + * dropped. + * Use the io{read,write} family functions when they become available in + * the linux-mips.org tree. Note: the MIPS specific functions readsb() + * and writesb() are to be translated by ioread8_rep() and iowrite8_rep() + * respectively. + */ + +/* The built-in parallel port on the SGI 02 workstation (a.k.a. IP32) is an + * IEEE 1284 parallel port driven by a Texas Instrument TL16PIR552PH chip[1]. + * This chip supports SPP, bidirectional, EPP and ECP modes. It has a 16 byte + * FIFO buffer and supports DMA transfers. + * + * [1] http://focus.ti.com/docs/prod/folders/print/tl16pir552.html + * + * Theoretically, we could simply use the parport_pc module. It is however + * not so simple. The parport_pc code assumes that the parallel port + * registers are port-mapped. On the O2, they are memory-mapped. + * Furthermore, each register is replicated on 256 consecutive addresses (as + * it is for the built-in serial ports on the same chip). + */ + +/*--- Some configuration defines ---------------------------------------*/ + +/* DEBUG_PARPORT_IP32 + * 0 disable debug + * 1 standard level: pr_debug1 is enabled + * 2 parport_ip32_dump_state is enabled + * >=3 verbose level: pr_debug is enabled + */ +#if !defined(DEBUG_PARPORT_IP32) +# define DEBUG_PARPORT_IP32 0 /* 0 (disabled) for production */ +#endif + +/*----------------------------------------------------------------------*/ + +/* Setup DEBUG macros. This is done before any includes, just in case we + * activate pr_debug() with DEBUG_PARPORT_IP32 >= 3. + */ +#if DEBUG_PARPORT_IP32 == 1 +# warning DEBUG_PARPORT_IP32 == 1 +#elif DEBUG_PARPORT_IP32 == 2 +# warning DEBUG_PARPORT_IP32 == 2 +#elif DEBUG_PARPORT_IP32 >= 3 +# warning DEBUG_PARPORT_IP32 >= 3 +# if !defined(DEBUG) +# define DEBUG /* enable pr_debug() in kernel.h */ +# endif +#endif + +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/parport.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/stddef.h> +#include <linux/types.h> +#include <asm/io.h> +#include <asm/ip32/ip32_ints.h> +#include <asm/ip32/mace.h> + +/*--- Global variables -------------------------------------------------*/ + +/* Verbose probing on by default for debugging. */ +#if DEBUG_PARPORT_IP32 >= 1 +# define DEFAULT_VERBOSE_PROBING 1 +#else +# define DEFAULT_VERBOSE_PROBING 0 +#endif + +/* Default prefix for printk */ +#define PPIP32 "parport_ip32: " + +/* + * These are the module parameters: + * @features: bit mask of features to enable/disable + * (all enabled by default) + * @verbose_probing: log chit-chat during initialization + */ +#define PARPORT_IP32_ENABLE_IRQ (1U << 0) +#define PARPORT_IP32_ENABLE_DMA (1U << 1) +#define PARPORT_IP32_ENABLE_SPP (1U << 2) +#define PARPORT_IP32_ENABLE_EPP (1U << 3) +#define PARPORT_IP32_ENABLE_ECP (1U << 4) +static unsigned int features = ~0U; +static int verbose_probing = DEFAULT_VERBOSE_PROBING; + +/* We do not support more than one port. */ +static struct parport *this_port = NULL; + +/* Timing constants for FIFO modes. */ +#define FIFO_NFAULT_TIMEOUT 100 /* milliseconds */ +#define FIFO_POLLING_INTERVAL 50 /* microseconds */ + +/*--- I/O register definitions -----------------------------------------*/ + +/** + * struct parport_ip32_regs - virtual addresses of parallel port registers + * @data: Data Register + * @dsr: Device Status Register + * @dcr: Device Control Register + * @eppAddr: EPP Address Register + * @eppData0: EPP Data Register 0 + * @eppData1: EPP Data Register 1 + * @eppData2: EPP Data Register 2 + * @eppData3: EPP Data Register 3 + * @ecpAFifo: ECP Address FIFO + * @fifo: General FIFO register. The same address is used for: + * - cFifo, the Parallel Port DATA FIFO + * - ecpDFifo, the ECP Data FIFO + * - tFifo, the ECP Test FIFO + * @cnfgA: Configuration Register A + * @cnfgB: Configuration Register B + * @ecr: Extended Control Register + */ +struct parport_ip32_regs { + void __iomem *data; + void __iomem *dsr; + void __iomem *dcr; + void __iomem *eppAddr; + void __iomem *eppData0; + void __iomem *eppData1; + void __iomem *eppData2; + void __iomem *eppData3; + void __iomem *ecpAFifo; + void __iomem *fifo; + void __iomem *cnfgA; + void __iomem *cnfgB; + void __iomem *ecr; +}; + +/* Device Status Register */ +#define DSR_nBUSY (1U << 7) /* PARPORT_STATUS_BUSY */ +#define DSR_nACK (1U << 6) /* PARPORT_STATUS_ACK */ +#define DSR_PERROR (1U << 5) /* PARPORT_STATUS_PAPEROUT */ +#define DSR_SELECT (1U << 4) /* PARPORT_STATUS_SELECT */ +#define DSR_nFAULT (1U << 3) /* PARPORT_STATUS_ERROR */ +#define DSR_nPRINT (1U << 2) /* specific to TL16PIR552 */ +/* #define DSR_reserved (1U << 1) */ +#define DSR_TIMEOUT (1U << 0) /* EPP timeout */ + +/* Device Control Register */ +/* #define DCR_reserved (1U << 7) | (1U << 6) */ +#define DCR_DIR (1U << 5) /* direction */ +#define DCR_IRQ (1U << 4) /* interrupt on nAck */ +#define DCR_SELECT (1U << 3) /* PARPORT_CONTROL_SELECT */ +#define DCR_nINIT (1U << 2) /* PARPORT_CONTROL_INIT */ +#define DCR_AUTOFD (1U << 1) /* PARPORT_CONTROL_AUTOFD */ +#define DCR_STROBE (1U << 0) /* PARPORT_CONTROL_STROBE */ + +/* ECP Configuration Register A */ +#define CNFGA_IRQ (1U << 7) +#define CNFGA_ID_MASK ((1U << 6) | (1U << 5) | (1U << 4)) +#define CNFGA_ID_SHIFT 4 +#define CNFGA_ID_16 (00U << CNFGA_ID_SHIFT) +#define CNFGA_ID_8 (01U << CNFGA_ID_SHIFT) +#define CNFGA_ID_32 (02U << CNFGA_ID_SHIFT) +/* #define CNFGA_reserved (1U << 3) */ +#define CNFGA_nBYTEINTRANS (1U << 2) +#define CNFGA_PWORDLEFT ((1U << 1) | (1U << 0)) + +/* ECP Configuration Register B */ +#define CNFGB_COMPRESS (1U << 7) +#define CNFGB_INTRVAL (1U << 6) +#define CNFGB_IRQ_MASK ((1U << 5) | (1U << 4) | (1U << 3)) +#define CNFGB_IRQ_SHIFT 3 +#define CNFGB_DMA_MASK ((1U << 2) | (1U << 1) | (1U << 0)) +#define CNFGB_DMA_SHIFT 0 + +/* Extended Control Register */ +#define ECR_MODE_MASK ((1U << 7) | (1U << 6) | (1U << 5)) +#define ECR_MODE_SHIFT 5 +#define ECR_MODE_SPP (00U << ECR_MODE_SHIFT) +#define ECR_MODE_PS2 (01U << ECR_MODE_SHIFT) +#define ECR_MODE_PPF (02U << ECR_MODE_SHIFT) +#define ECR_MODE_ECP (03U << ECR_MODE_SHIFT) +#define ECR_MODE_EPP (04U << ECR_MODE_SHIFT) +/* #define ECR_MODE_reserved (05U << ECR_MODE_SHIFT) */ +#define ECR_MODE_TST (06U << ECR_MODE_SHIFT) +#define ECR_MODE_CFG (07U << ECR_MODE_SHIFT) +#define ECR_nERRINTR (1U << 4) +#define ECR_DMAEN (1U << 3) +#define ECR_SERVINTR (1U << 2) +#define ECR_F_FULL (1U << 1) +#define ECR_F_EMPTY (1U << 0) + +/*--- Private data -----------------------------------------------------*/ + +/** + * enum parport_ip32_irq_mode - operation mode of interrupt handler + * @PARPORT_IP32_IRQ_FWD: forward interrupt to the upper parport layer + * @PARPORT_IP32_IRQ_HERE: interrupt is handled locally + */ +enum parport_ip32_irq_mode { PARPORT_IP32_IRQ_FWD, PARPORT_IP32_IRQ_HERE }; + +/** + * struct parport_ip32_private - private stuff for &struct parport + * @regs: register addresses + * @dcr_cache: cached contents of DCR + * @dcr_writable: bit mask of writable DCR bits + * @pword: number of bytes per PWord + * @fifo_depth: number of PWords that FIFO will hold + * @readIntrThreshold: minimum number of PWords we can read + * if we get an interrupt + * @writeIntrThreshold: minimum number of PWords we can write + * if we get an interrupt + * @irq_mode: operation mode of interrupt handler for this port + * @irq_complete: mutex used to wait for an interrupt to occur + */ +struct parport_ip32_private { + struct parport_ip32_regs regs; + unsigned int dcr_cache; + unsigned int dcr_writable; + unsigned int pword; + unsigned int fifo_depth; + unsigned int readIntrThreshold; + unsigned int writeIntrThreshold; + enum parport_ip32_irq_mode irq_mode; + struct completion irq_complete; +}; + +/*--- Debug code -------------------------------------------------------*/ + +/* + * pr_debug1 - print debug messages + * + * This is like pr_debug(), but is defined for %DEBUG_PARPORT_IP32 >= 1 + */ +#if DEBUG_PARPORT_IP32 >= 1 +# define pr_debug1(...) printk(KERN_DEBUG __VA_ARGS__) +#else /* DEBUG_PARPORT_IP32 < 1 */ +# define pr_debug1(...) do { } while (0) +#endif + +/* + * pr_trace, pr_trace1 - trace function calls + * @p: pointer to &struct parport + * @fmt: printk format string + * @...: parameters for format string + * + * Macros used to trace function calls. The given string is formatted after + * function name. pr_trace() uses pr_debug(), and pr_trace1() uses + * pr_debug1(). __pr_trace() is the low-level macro and is not to be used + * directly. + */ +#define __pr_trace(pr, p, fmt, ...) \ + pr("%s: %s" fmt "\n", \ + ({ const struct parport *__p = (p); \ + __p ? __p->name : "parport_ip32"; }), \ + __func__ , ##__VA_ARGS__) +#define pr_trace(p, fmt, ...) __pr_trace(pr_debug, p, fmt , ##__VA_ARGS__) +#define pr_trace1(p, fmt, ...) __pr_trace(pr_debug1, p, fmt , ##__VA_ARGS__) + +/* + * __pr_probe, pr_probe - print message if @verbose_probing is true + * @p: pointer to &struct parport + * @fmt: printk format string + * @...: parameters for format string + * + * For new lines, use pr_probe(). Use __pr_probe() for continued lines. + */ +#define __pr_probe(...) \ + do { if (verbose_probing) printk(__VA_ARGS__); } while (0) +#define pr_probe(p, fmt, ...) \ + __pr_probe(KERN_INFO PPIP32 "0x%lx: " fmt, (p)->base , ##__VA_ARGS__) + +/* + * parport_ip32_dump_state - print register status of parport + * @p: pointer to &struct parport + * @str: string to add in message + * @show_ecp_config: shall we dump ECP configuration registers too? + * + * This function is only here for debugging purpose, and should be used with + * care. Reading the parallel port registers may have undesired side effects. + * Especially if @show_ecp_config is true, the parallel port is resetted. + * This function is only defined if %DEBUG_PARPORT_IP32 >= 2. + */ +#if DEBUG_PARPORT_IP32 >= 2 +static void parport_ip32_dump_state(struct parport *p, char *str, + unsigned int show_ecp_config) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + unsigned int i; + + printk(KERN_DEBUG PPIP32 "%s: state (%s):\n", p->name, str); + { + static const char ecr_modes[8][4] = {"SPP", "PS2", "PPF", + "ECP", "EPP", "???", + "TST", "CFG"}; + unsigned int ecr = readb(priv->regs.ecr); + printk(KERN_DEBUG PPIP32 " ecr=0x%02x", ecr); + printk(" %s", + ecr_modes[(ecr & ECR_MODE_MASK) >> ECR_MODE_SHIFT]); + if (ecr & ECR_nERRINTR) + printk(",nErrIntrEn"); + if (ecr & ECR_DMAEN) + printk(",dmaEn"); + if (ecr & ECR_SERVINTR) + printk(",serviceIntr"); + if (ecr & ECR_F_FULL) + printk(",f_full"); + if (ecr & ECR_F_EMPTY) + printk(",f_empty"); + printk("\n"); + } + if (show_ecp_config) { + unsigned int oecr, cnfgA, cnfgB; + oecr = readb(priv->regs.ecr); + writeb(ECR_MODE_PS2, priv->regs.ecr); + writeb(ECR_MODE_CFG, priv->regs.ecr); + cnfgA = readb(priv->regs.cnfgA); + cnfgB = readb(priv->regs.cnfgB); + writeb(ECR_MODE_PS2, priv->regs.ecr); + writeb(oecr, priv->regs.ecr); + printk(KERN_DEBUG PPIP32 " cnfgA=0x%02x", cnfgA); + printk(" ISA-%s", (cnfgA & CNFGA_IRQ) ? "Level" : "Pulses"); + switch (cnfgA & CNFGA_ID_MASK) { + case CNFGA_ID_8: + printk(",8 bits"); + break; + case CNFGA_ID_16: + printk(",16 bits"); + break; + case CNFGA_ID_32: + printk(",32 bits"); + break; + default: + printk(",unknown ID"); + break; + } + if (!(cnfgA & CNFGA_nBYTEINTRANS)) + printk(",ByteInTrans"); + if ((cnfgA & CNFGA_ID_MASK) != CNFGA_ID_8) + printk(",%d byte%s left", cnfgA & CNFGA_PWORDLEFT, + ((cnfgA & CNFGA_PWORDLEFT) > 1) ? "s" : ""); + printk("\n"); + printk(KERN_DEBUG PPIP32 " cnfgB=0x%02x", cnfgB); + printk(" irq=%u,dma=%u", + (cnfgB & CNFGB_IRQ_MASK) >> CNFGB_IRQ_SHIFT, + (cnfgB & CNFGB_DMA_MASK) >> CNFGB_DMA_SHIFT); + printk(",intrValue=%d", !!(cnfgB & CNFGB_INTRVAL)); + if (cnfgB & CNFGB_COMPRESS) + printk(",compress"); + printk("\n"); + } + for (i = 0; i < 2; i++) { + unsigned int dcr = i ? priv->dcr_cache : readb(priv->regs.dcr); + printk(KERN_DEBUG PPIP32 " dcr(%s)=0x%02x", + i ? "soft" : "hard", dcr); + printk(" %s", (dcr & DCR_DIR) ? "rev" : "fwd"); + if (dcr & DCR_IRQ) + printk(",ackIntEn"); + if (!(dcr & DCR_SELECT)) + printk(",nSelectIn"); + if (dcr & DCR_nINIT) + printk(",nInit"); + if (!(dcr & DCR_AUTOFD)) + printk(",nAutoFD"); + if (!(dcr & DCR_STROBE)) + printk(",nStrobe"); + printk("\n"); + } +#define sep (f++ ? ',' : ' ') + { + unsigned int f = 0; + unsigned int dsr = readb(priv->regs.dsr); + printk(KERN_DEBUG PPIP32 " dsr=0x%02x", dsr); + if (!(dsr & DSR_nBUSY)) + printk("%cBusy", sep); + if (dsr & DSR_nACK) + printk("%cnAck", sep); + if (dsr & DSR_PERROR) + printk("%cPError", sep); + if (dsr & DSR_SELECT) + printk("%cSelect", sep); + if (dsr & DSR_nFAULT) + printk("%cnFault", sep); + if (!(dsr & DSR_nPRINT)) + printk("%c(Print)", sep); + if (dsr & DSR_TIMEOUT) + printk("%cTimeout", sep); + printk("\n"); + } +#undef sep +} +#else /* DEBUG_PARPORT_IP32 < 2 */ +#define parport_ip32_dump_state(...) do { } while (0) +#endif + +/* + * CHECK_EXTRA_BITS - track and log extra bits + * @p: pointer to &struct parport + * @b: byte to inspect + * @m: bit mask of authorized bits + * + * This is used to track and log extra bits that should not be there in + * parport_ip32_write_control() and parport_ip32_frob_control(). It is only + * defined if %DEBUG_PARPORT_IP32 >= 1. + */ +#if DEBUG_PARPORT_IP32 >= 1 +#define CHECK_EXTRA_BITS(p, b, m) \ + do { \ + unsigned int __b = (b), __m = (m); \ + if (__b & ~__m) \ + pr_debug1(PPIP32 "%s: extra bits in %s(%s): " \ + "0x%02x/0x%02x\n", \ + (p)->name, __func__, #b, __b, __m); \ + } while (0) +#else /* DEBUG_PARPORT_IP32 < 1 */ +#define CHECK_EXTRA_BITS(...) do { } while (0) +#endif + +/*--- IP32 parallel port DMA operations --------------------------------*/ + +/** + * struct parport_ip32_dma_data - private data needed for DMA operation + * @dir: DMA direction (from or to device) + * @buf: buffer physical address + * @len: buffer length + * @next: address of next bytes to DMA transfer + * @left: number of bytes remaining + * @ctx: next context to write (0: context_a; 1: context_b) + * @irq_on: are the DMA IRQs currently enabled? + * @lock: spinlock to protect access to the structure + */ +struct parport_ip32_dma_data { + enum dma_data_direction dir; + dma_addr_t buf; + dma_addr_t next; + size_t len; + size_t left; + unsigned int ctx; + unsigned int irq_on; + spinlock_t lock; +}; +static struct parport_ip32_dma_data parport_ip32_dma; + +/** + * parport_ip32_dma_setup_context - setup next DMA context + * @limit: maximum data size for the context + * + * The alignment constraints must be verified in caller function, and the + * parameter @limit must be set accordingly. + */ +static void parport_ip32_dma_setup_context(unsigned int limit) +{ + unsigned long flags; + + spin_lock_irqsave(&parport_ip32_dma.lock, flags); + if (parport_ip32_dma.left > 0) { + /* Note: ctxreg is "volatile" here only because + * mace->perif.ctrl.parport.context_a and context_b are + * "volatile". */ + volatile u64 __iomem *ctxreg = (parport_ip32_dma.ctx == 0) ? + &mace->perif.ctrl.parport.context_a : + &mace->perif.ctrl.parport.context_b; + u64 count; + u64 ctxval; + if (parport_ip32_dma.left <= limit) { + count = parport_ip32_dma.left; + ctxval = MACEPAR_CONTEXT_LASTFLAG; + } else { + count = limit; + ctxval = 0; + } + + pr_trace(NULL, + "(%u): 0x%04x:0x%04x, %u -> %u%s", + limit, + (unsigned int)parport_ip32_dma.buf, + (unsigned int)parport_ip32_dma.next, + (unsigned int)count, + parport_ip32_dma.ctx, ctxval ? "*" : ""); + + ctxval |= parport_ip32_dma.next & + MACEPAR_CONTEXT_BASEADDR_MASK; + ctxval |= ((count - 1) << MACEPAR_CONTEXT_DATALEN_SHIFT) & + MACEPAR_CONTEXT_DATALEN_MASK; + writeq(ctxval, ctxreg); + parport_ip32_dma.next += count; + parport_ip32_dma.left -= count; + parport_ip32_dma.ctx ^= 1U; + } + /* If there is nothing more to send, disable IRQs to avoid to + * face an IRQ storm which can lock the machine. Disable them + * only once. */ + if (parport_ip32_dma.left == 0 && parport_ip32_dma.irq_on) { + pr_debug(PPIP32 "IRQ off (ctx)\n"); + disable_irq_nosync(MACEISA_PAR_CTXA_IRQ); + disable_irq_nosync(MACEISA_PAR_CTXB_IRQ); + parport_ip32_dma.irq_on = 0; + } + spin_unlock_irqrestore(&parport_ip32_dma.lock, flags); +} + +/** + * parport_ip32_dma_interrupt - DMA interrupt handler + * @irq: interrupt number + * @dev_id: unused + * @regs: pointer to &struct pt_regs + */ +static irqreturn_t parport_ip32_dma_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + if (parport_ip32_dma.left) + pr_trace(NULL, "(%d): ctx=%d", irq, parport_ip32_dma.ctx); + parport_ip32_dma_setup_context(MACEPAR_CONTEXT_DATA_BOUND); + return IRQ_HANDLED; +} + +#if DEBUG_PARPORT_IP32 +static irqreturn_t parport_ip32_merr_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + pr_trace1(NULL, "(%d)", irq); + return IRQ_HANDLED; +} +#endif + +/** + * parport_ip32_dma_start - begins a DMA transfer + * @dir: DMA direction: DMA_TO_DEVICE or DMA_FROM_DEVICE + * @addr: pointer to data buffer + * @count: buffer size + * + * Calls to parport_ip32_dma_start() and parport_ip32_dma_stop() must be + * correctly balanced. + */ +static int parport_ip32_dma_start(enum dma_data_direction dir, + void *addr, size_t count) +{ + unsigned int limit; + u64 ctrl; + + pr_trace(NULL, "(%d, %lu)", dir, (unsigned long)count); + + /* FIXME - add support for DMA_FROM_DEVICE. In this case, buffer must + * be 64 bytes aligned. */ + BUG_ON(dir != DMA_TO_DEVICE); + + /* Reset DMA controller */ + ctrl = MACEPAR_CTLSTAT_RESET; + writeq(ctrl, &mace->perif.ctrl.parport.cntlstat); + + /* DMA IRQs should normally be enabled */ + if (!parport_ip32_dma.irq_on) { + WARN_ON(1); + enable_irq(MACEISA_PAR_CTXA_IRQ); + enable_irq(MACEISA_PAR_CTXB_IRQ); + parport_ip32_dma.irq_on = 1; + } + + /* Prepare DMA pointers */ + parport_ip32_dma.dir = dir; + parport_ip32_dma.buf = dma_map_single(NULL, addr, count, dir); + parport_ip32_dma.len = count; + parport_ip32_dma.next = parport_ip32_dma.buf; + parport_ip32_dma.left = parport_ip32_dma.len; + parport_ip32_dma.ctx = 0; + + /* Setup DMA direction and first two contexts */ + ctrl = (dir == DMA_TO_DEVICE) ? 0 : MACEPAR_CTLSTAT_DIRECTION; + writeq(ctrl, &mace->perif.ctrl.parport.cntlstat); + /* Single transfer should not cross a 4K page boundary */ + limit = MACEPAR_CONTEXT_DATA_BOUND - + (parport_ip32_dma.next & (MACEPAR_CONTEXT_DATA_BOUND - 1)); + parport_ip32_dma_setup_context(limit); + parport_ip32_dma_setup_context(MACEPAR_CONTEXT_DATA_BOUND); + + /* Real start of DMA transfer */ + ctrl |= MACEPAR_CTLSTAT_ENABLE; + writeq(ctrl, &mace->perif.ctrl.parport.cntlstat); + + return 0; +} + +/** + * parport_ip32_dma_stop - ends a running DMA transfer + * + * Calls to parport_ip32_dma_start() and parport_ip32_dma_stop() must be + * correctly balanced. + */ +static void parport_ip32_dma_stop(void) +{ + u64 ctx_a; + u64 ctx_b; + u64 ctrl; + u64 diag; + size_t res[2]; /* {[0] = res_a, [1] = res_b} */ + + pr_trace(NULL, "()"); + + /* Disable IRQs */ + spin_lock_irq(&parport_ip32_dma.lock); + if (parport_ip32_dma.irq_on) { + pr_debug(PPIP32 "IRQ off (stop)\n"); + disable_irq_nosync(MACEISA_PAR_CTXA_IRQ); + disable_irq_nosync(MACEISA_PAR_CTXB_IRQ); + parport_ip32_dma.irq_on = 0; + } + spin_unlock_irq(&parport_ip32_dma.lock); + /* Force IRQ synchronization, even if the IRQs were disabled + * elsewhere. */ + synchronize_irq(MACEISA_PAR_CTXA_IRQ); + synchronize_irq(MACEISA_PAR_CTXB_IRQ); + + /* Stop DMA transfer */ + ctrl = readq(&mace->perif.ctrl.parport.cntlstat); + ctrl &= ~MACEPAR_CTLSTAT_ENABLE; + writeq(ctrl, &mace->perif.ctrl.parport.cntlstat); + + /* Adjust residue (parport_ip32_dma.left) */ + ctx_a = readq(&mace->perif.ctrl.parport.context_a); + ctx_b = readq(&mace->perif.ctrl.parport.context_b); + ctrl = readq(&mace->perif.ctrl.parport.cntlstat); + diag = readq(&mace->perif.ctrl.parport.diagnostic); + res[0] = (ctrl & MACEPAR_CTLSTAT_CTXA_VALID) ? + 1 + ((ctx_a & MACEPAR_CONTEXT_DATALEN_MASK) >> + MACEPAR_CONTEXT_DATALEN_SHIFT) : + 0; + res[1] = (ctrl & MACEPAR_CTLSTAT_CTXB_VALID) ? + 1 + ((ctx_b & MACEPAR_CONTEXT_DATALEN_MASK) >> + MACEPAR_CONTEXT_DATALEN_SHIFT) : + 0; + if (diag & MACEPAR_DIAG_DMACTIVE) + res[(diag & MACEPAR_DIAG_CTXINUSE) != 0] = + 1 + ((diag & MACEPAR_DIAG_CTRMASK) >> + MACEPAR_DIAG_CTRSHIFT); + parport_ip32_dma.left += res[0] + res[1]; + + /* Reset DMA controller, and re-enable IRQs */ + ctrl = MACEPAR_CTLSTAT_RESET; + writeq(ctrl, &mace->perif.ctrl.parport.cntlstat); + pr_debug(PPIP32 "IRQ on (stop)\n"); + enable_irq(MACEISA_PAR_CTXA_IRQ); + enable_irq(MACEISA_PAR_CTXB_IRQ); + parport_ip32_dma.irq_on = 1; + + dma_unmap_single(NULL, parport_ip32_dma.buf, parport_ip32_dma.len, + parport_ip32_dma.dir); +} + +/** + * parport_ip32_dma_get_residue - get residue from last DMA transfer + * + * Returns the number of bytes remaining from last DMA transfer. + */ +static inline size_t parport_ip32_dma_get_residue(void) +{ + return parport_ip32_dma.left; +} + +/** + * parport_ip32_dma_register - initialize DMA engine + * + * Returns zero for success. + */ +static int parport_ip32_dma_register(void) +{ + int err; + + spin_lock_init(&parport_ip32_dma.lock); + parport_ip32_dma.irq_on = 1; + + /* Reset DMA controller */ + writeq(MACEPAR_CTLSTAT_RESET, &mace->perif.ctrl.parport.cntlstat); + + /* Request IRQs */ + err = request_irq(MACEISA_PAR_CTXA_IRQ, parport_ip32_dma_interrupt, + 0, "parport_ip32", NULL); + if (err) + goto fail_a; + err = request_irq(MACEISA_PAR_CTXB_IRQ, parport_ip32_dma_interrupt, + 0, "parport_ip32", NULL); + if (err) + goto fail_b; +#if DEBUG_PARPORT_IP32 + /* FIXME - what is this IRQ for? */ + err = request_irq(MACEISA_PAR_MERR_IRQ, parport_ip32_merr_interrupt, + 0, "parport_ip32", NULL); + if (err) + goto fail_merr; +#endif + return 0; + +#if DEBUG_PARPORT_IP32 +fail_merr: + free_irq(MACEISA_PAR_CTXB_IRQ, NULL); +#endif +fail_b: + free_irq(MACEISA_PAR_CTXA_IRQ, NULL); +fail_a: + return err; +} + +/** + * parport_ip32_dma_unregister - release and free resources for DMA engine + */ +static void parport_ip32_dma_unregister(void) +{ +#if DEBUG_PARPORT_IP32 + free_irq(MACEISA_PAR_MERR_IRQ, NULL); +#endif + free_irq(MACEISA_PAR_CTXB_IRQ, NULL); + free_irq(MACEISA_PAR_CTXA_IRQ, NULL); +} + +/*--- Interrupt handlers and associates --------------------------------*/ + +/** + * parport_ip32_wakeup - wakes up code waiting for an interrupt + * @p: pointer to &struct parport + */ +static inline void parport_ip32_wakeup(struct parport *p) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + complete(&priv->irq_complete); +} + +/** + * parport_ip32_interrupt - interrupt handler + * @irq: interrupt number + * @dev_id: pointer to &struct parport + * @regs: pointer to &struct pt_regs + * + * Caught interrupts are forwarded to the upper parport layer if IRQ_mode is + * %PARPORT_IP32_IRQ_FWD. + */ +static irqreturn_t parport_ip32_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct parport * const p = dev_id; + struct parport_ip32_private * const priv = p->physport->private_data; + enum parport_ip32_irq_mode irq_mode = priv->irq_mode; + switch (irq_mode) { + case PARPORT_IP32_IRQ_FWD: + parport_generic_irq(irq, p, regs); + break; + case PARPORT_IP32_IRQ_HERE: + parport_ip32_wakeup(p); + break; + } + return IRQ_HANDLED; +} + +/*--- Some utility function to manipulate ECR register -----------------*/ + +/** + * parport_ip32_read_econtrol - read contents of the ECR register + * @p: pointer to &struct parport + */ +static inline unsigned int parport_ip32_read_econtrol(struct parport *p) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + return readb(priv->regs.ecr); +} + +/** + * parport_ip32_write_econtrol - write new contents to the ECR register + * @p: pointer to &struct parport + * @c: new value to write + */ +static inline void parport_ip32_write_econtrol(struct parport *p, + unsigned int c) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + writeb(c, priv->regs.ecr); +} + +/** + * parport_ip32_frob_econtrol - change bits from the ECR register + * @p: pointer to &struct parport + * @mask: bit mask of bits to change + * @val: new value for changed bits + * + * Read from the ECR, mask out the bits in @mask, exclusive-or with the bits + * in @val, and write the result to the ECR. + */ +static inline void parport_ip32_frob_econtrol(struct parport *p, + unsigned int mask, + unsigned int val) +{ + unsigned int c; + c = (parport_ip32_read_econtrol(p) & ~mask) ^ val; + parport_ip32_write_econtrol(p, c); +} + +/** + * parport_ip32_set_mode - change mode of ECP port + * @p: pointer to &struct parport + * @mode: new mode to write in ECR + * + * ECR is reset in a sane state (interrupts and DMA disabled), and placed in + * mode @mode. Go through PS2 mode if needed. + */ +static void parport_ip32_set_mode(struct parport *p, unsigned int mode) +{ + unsigned int omode; + + mode &= ECR_MODE_MASK; + omode = parport_ip32_read_econtrol(p) & ECR_MODE_MASK; + + if (!(mode == ECR_MODE_SPP || mode == ECR_MODE_PS2 + || omode == ECR_MODE_SPP || omode == ECR_MODE_PS2)) { + /* We have to go through PS2 mode */ + unsigned int ecr = ECR_MODE_PS2 | ECR_nERRINTR | ECR_SERVINTR; + parport_ip32_write_econtrol(p, ecr); + } + parport_ip32_write_econtrol(p, mode | ECR_nERRINTR | ECR_SERVINTR); +} + +/*--- Basic functions needed for parport -------------------------------*/ + +/** + * parport_ip32_read_data - return current contents of the DATA register + * @p: pointer to &struct parport + */ +static inline unsigned char parport_ip32_read_data(struct parport *p) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + return readb(priv->regs.data); +} + +/** + * parport_ip32_write_data - set new contents for the DATA register + * @p: pointer to &struct parport + * @d: new value to write + */ +static inline void parport_ip32_write_data(struct parport *p, unsigned char d) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + writeb(d, priv->regs.data); +} + +/** + * parport_ip32_read_status - return current contents of the DSR register + * @p: pointer to &struct parport + */ +static inline unsigned char parport_ip32_read_status(struct parport *p) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + return readb(priv->regs.dsr); +} + +/** + * __parport_ip32_read_control - return cached contents of the DCR register + * @p: pointer to &struct parport + */ +static inline unsigned int __parport_ip32_read_control(struct parport *p) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + return priv->dcr_cache; /* use soft copy */ +} + +/** + * __parport_ip32_write_control - set new contents for the DCR register + * @p: pointer to &struct parport + * @c: new value to write + */ +static inline void __parport_ip32_write_control(struct parport *p, + unsigned int c) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + CHECK_EXTRA_BITS(p, c, priv->dcr_writable); + c &= priv->dcr_writable; /* only writable bits */ + writeb(c, priv->regs.dcr); + priv->dcr_cache = c; /* update soft copy */ +} + +/** + * __parport_ip32_frob_control - change bits from the DCR register + * @p: pointer to &struct parport + * @mask: bit mask of bits to change + * @val: new value for changed bits + * + * This is equivalent to read from the DCR, mask out the bits in @mask, + * exclusive-or with the bits in @val, and write the result to the DCR. + * Actually, the cached contents of the DCR is used. + */ +static inline void __parport_ip32_frob_control(struct parport *p, + unsigned int mask, + unsigned int val) +{ + unsigned int c; + c = (__parport_ip32_read_control(p) & ~mask) ^ val; + __parport_ip32_write_control(p, c); +} + +/** + * parport_ip32_read_control - return cached contents of the DCR register + * @p: pointer to &struct parport + * + * The return value is masked so as to only return the value of %DCR_STROBE, + * %DCR_AUTOFD, %DCR_nINIT, and %DCR_SELECT. + */ +static inline unsigned char parport_ip32_read_control(struct parport *p) +{ + const unsigned int rm = + DCR_STROBE | DCR_AUTOFD | DCR_nINIT | DCR_SELECT; + return __parport_ip32_read_control(p) & rm; +} + +/** + * parport_ip32_write_control - set new contents for the DCR register + * @p: pointer to &struct parport + * @c: new value to write + * + * The value is masked so as to only change the value of %DCR_STROBE, + * %DCR_AUTOFD, %DCR_nINIT, and %DCR_SELECT. + */ +static inline void parport_ip32_write_control(struct parport *p, + unsigned char c) +{ + const unsigned int wm = + DCR_STROBE | DCR_AUTOFD | DCR_nINIT | DCR_SELECT; + CHECK_EXTRA_BITS(p, c, wm); + __parport_ip32_frob_control(p, wm, c & wm); +} + +/** + * parport_ip32_frob_control - change bits from the DCR register + * @p: pointer to &struct parport + * @mask: bit mask of bits to change + * @val: new value for changed bits + * + * This differs from __parport_ip32_frob_control() in that it only allows to + * change the value of %DCR_STROBE, %DCR_AUTOFD, %DCR_nINIT, and %DCR_SELECT. + */ +static inline unsigned char parport_ip32_frob_control(struct parport *p, + unsigned char mask, + unsigned char val) +{ + const unsigned int wm = + DCR_STROBE | DCR_AUTOFD | DCR_nINIT | DCR_SELECT; + CHECK_EXTRA_BITS(p, mask, wm); + CHECK_EXTRA_BITS(p, val, wm); + __parport_ip32_frob_control(p, mask & wm, val & wm); + return parport_ip32_read_control(p); +} + +/** + * parport_ip32_disable_irq - disable interrupts on the rising edge of nACK + * @p: pointer to &struct parport + */ +static inline void parport_ip32_disable_irq(struct parport *p) +{ + __parport_ip32_frob_control(p, DCR_IRQ, 0); +} + +/** + * parport_ip32_enable_irq - enable interrupts on the rising edge of nACK + * @p: pointer to &struct parport + */ +static inline void parport_ip32_enable_irq(struct parport *p) +{ + __parport_ip32_frob_control(p, DCR_IRQ, DCR_IRQ); +} + +/** + * parport_ip32_data_forward - enable host-to-peripheral communications + * @p: pointer to &struct parport + * + * Enable the data line drivers, for 8-bit host-to-peripheral communications. + */ +static inline void parport_ip32_data_forward(struct parport *p) +{ + __parport_ip32_frob_control(p, DCR_DIR, 0); +} + +/** + * parport_ip32_data_reverse - enable peripheral-to-host communications + * @p: pointer to &struct parport + * + * Place the data bus in a high impedance state, if @p->modes has the + * PARPORT_MODE_TRISTATE bit set. + */ +static inline void parport_ip32_data_reverse(struct parport *p) +{ + __parport_ip32_frob_control(p, DCR_DIR, DCR_DIR); +} + +/** + * parport_ip32_init_state - for core parport code + * @dev: pointer to &struct pardevice + * @s: pointer to &struct parport_state to initialize + */ +static void parport_ip32_init_state(struct pardevice *dev, + struct parport_state *s) +{ + s->u.ip32.dcr = DCR_SELECT | DCR_nINIT; + s->u.ip32.ecr = ECR_MODE_PS2 | ECR_nERRINTR | ECR_SERVINTR; +} + +/** + * parport_ip32_save_state - for core parport code + * @p: pointer to &struct parport + * @s: pointer to &struct parport_state to save state to + */ +static void parport_ip32_save_state(struct parport *p, + struct parport_state *s) +{ + s->u.ip32.dcr = __parport_ip32_read_control(p); + s->u.ip32.ecr = parport_ip32_read_econtrol(p); +} + +/** + * parport_ip32_restore_state - for core parport code + * @p: pointer to &struct parport + * @s: pointer to &struct parport_state to restore state from + */ +static void parport_ip32_restore_state(struct parport *p, + struct parport_state *s) +{ + parport_ip32_set_mode(p, s->u.ip32.ecr & ECR_MODE_MASK); + parport_ip32_write_econtrol(p, s->u.ip32.ecr); + __parport_ip32_write_control(p, s->u.ip32.dcr); +} + +/*--- EPP mode functions -----------------------------------------------*/ + +/** + * parport_ip32_clear_epp_timeout - clear Timeout bit in EPP mode + * @p: pointer to &struct parport + * + * Returns 1 if the Timeout bit is clear, and 0 otherwise. + */ +static unsigned int parport_ip32_clear_epp_timeout(struct parport *p) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + unsigned int cleared; + + if (!(parport_ip32_read_status(p) & DSR_TIMEOUT)) + cleared = 1; + else { + unsigned int r; + /* To clear timeout some chips require double read */ + parport_ip32_read_status(p); + r = parport_ip32_read_status(p); + /* Some reset by writing 1 */ + writeb(r | DSR_TIMEOUT, priv->regs.dsr); + /* Others by writing 0 */ + writeb(r & ~DSR_TIMEOUT, priv->regs.dsr); + + r = parport_ip32_read_status(p); + cleared = !(r & DSR_TIMEOUT); + } + + pr_trace(p, "(): %s", cleared ? "cleared" : "failed"); + return cleared; +} + +/** + * parport_ip32_epp_read - generic EPP read function + * @eppreg: I/O register to read from + * @p: pointer to &struct parport + * @buf: buffer to store read data + * @len: length of buffer @buf + * @flags: may be PARPORT_EPP_FAST + */ +static size_t parport_ip32_epp_read(void __iomem *eppreg, + struct parport *p, void *buf, + size_t len, int flags) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + size_t got; + parport_ip32_set_mode(p, ECR_MODE_EPP); + parport_ip32_data_reverse(p); + parport_ip32_write_control(p, DCR_nINIT); + if ((flags & PARPORT_EPP_FAST) && (len > 1)) { + readsb(eppreg, buf, len); + if (readb(priv->regs.dsr) & DSR_TIMEOUT) { + parport_ip32_clear_epp_timeout(p); + return -EIO; + } + got = len; + } else { + u8 *bufp = buf; + for (got = 0; got < len; got++) { + *bufp++ = readb(eppreg); + if (readb(priv->regs.dsr) & DSR_TIMEOUT) { + parport_ip32_clear_epp_timeout(p); + break; + } + } + } + parport_ip32_data_forward(p); + parport_ip32_set_mode(p, ECR_MODE_PS2); + return got; +} + +/** + * parport_ip32_epp_write - generic EPP write function + * @eppreg: I/O register to write to + * @p: pointer to &struct parport + * @buf: buffer of data to write + * @len: length of buffer @buf + * @flags: may be PARPORT_EPP_FAST + */ +static size_t parport_ip32_epp_write(void __iomem *eppreg, + struct parport *p, const void *buf, + size_t len, int flags) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + size_t written; + parport_ip32_set_mode(p, ECR_MODE_EPP); + parport_ip32_data_forward(p); + parport_ip32_write_control(p, DCR_nINIT); + if ((flags & PARPORT_EPP_FAST) && (len > 1)) { + writesb(eppreg, buf, len); + if (readb(priv->regs.dsr) & DSR_TIMEOUT) { + parport_ip32_clear_epp_timeout(p); + return -EIO; + } + written = len; + } else { + const u8 *bufp = buf; + for (written = 0; written < len; written++) { + writeb(*bufp++, eppreg); + if (readb(priv->regs.dsr) & DSR_TIMEOUT) { + parport_ip32_clear_epp_timeout(p); + break; + } + } + } + parport_ip32_set_mode(p, ECR_MODE_PS2); + return written; +} + +/** + * parport_ip32_epp_read_data - read a block of data in EPP mode + * @p: pointer to &struct parport + * @buf: buffer to store read data + * @len: length of buffer @buf + * @flags: may be PARPORT_EPP_FAST + */ +static size_t parport_ip32_epp_read_data(struct parport *p, void *buf, + size_t len, int flags) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + return parport_ip32_epp_read(priv->regs.eppData0, p, buf, len, flags); +} + +/** + * parport_ip32_epp_write_data - write a block of data in EPP mode + * @p: pointer to &struct parport + * @buf: buffer of data to write + * @len: length of buffer @buf + * @flags: may be PARPORT_EPP_FAST + */ +static size_t parport_ip32_epp_write_data(struct parport *p, const void *buf, + size_t len, int flags) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + return parport_ip32_epp_write(priv->regs.eppData0, p, buf, len, flags); +} + +/** + * parport_ip32_epp_read_addr - read a block of addresses in EPP mode + * @p: pointer to &struct parport + * @buf: buffer to store read data + * @len: length of buffer @buf + * @flags: may be PARPORT_EPP_FAST + */ +static size_t parport_ip32_epp_read_addr(struct parport *p, void *buf, + size_t len, int flags) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + return parport_ip32_epp_read(priv->regs.eppAddr, p, buf, len, flags); +} + +/** + * parport_ip32_epp_write_addr - write a block of addresses in EPP mode + * @p: pointer to &struct parport + * @buf: buffer of data to write + * @len: length of buffer @buf + * @flags: may be PARPORT_EPP_FAST + */ +static size_t parport_ip32_epp_write_addr(struct parport *p, const void *buf, + size_t len, int flags) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + return parport_ip32_epp_write(priv->regs.eppAddr, p, buf, len, flags); +} + +/*--- ECP mode functions (FIFO) ----------------------------------------*/ + +/** + * parport_ip32_fifo_wait_break - check if the waiting function should return + * @p: pointer to &struct parport + * @expire: timeout expiring date, in jiffies + * + * parport_ip32_fifo_wait_break() checks if the waiting function should return + * immediately or not. The break conditions are: + * - expired timeout; + * - a pending signal; + * - nFault asserted low. + * This function also calls cond_resched(). + */ +static unsigned int parport_ip32_fifo_wait_break(struct parport *p, + unsigned long expire) +{ + cond_resched(); + if (time_after(jiffies, expire)) { + pr_debug1(PPIP32 "%s: FIFO write timed out\n", p->name); + return 1; + } + if (signal_pending(current)) { + pr_debug1(PPIP32 "%s: Signal pending\n", p->name); + return 1; + } + if (!(parport_ip32_read_status(p) & DSR_nFAULT)) { + pr_debug1(PPIP32 "%s: nFault asserted low\n", p->name); + return 1; + } + return 0; +} + +/** + * parport_ip32_fwp_wait_polling - wait for FIFO to empty (polling) + * @p: pointer to &struct parport + * + * Returns the number of bytes that can safely be written in the FIFO. A + * return value of zero means that the calling function should terminate as + * fast as possible. + */ +static unsigned int parport_ip32_fwp_wait_polling(struct parport *p) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + struct parport * const physport = p->physport; + unsigned long expire; + unsigned int count; + unsigned int ecr; + + expire = jiffies + physport->cad->timeout; + count = 0; + while (1) { + if (parport_ip32_fifo_wait_break(p, expire)) + break; + + /* Check FIFO state. We do nothing when the FIFO is nor full, + * nor empty. It appears that the FIFO full bit is not always + * reliable, the FIFO state is sometimes wrongly reported, and + * the chip gets confused if we give it another byte. */ + ecr = parport_ip32_read_econtrol(p); + if (ecr & ECR_F_EMPTY) { + /* FIFO is empty, fill it up */ + count = priv->fifo_depth; + break; + } + + /* Wait a moment... */ + udelay(FIFO_POLLING_INTERVAL); + } /* while (1) */ + + return count; +} + +/** + * parport_ip32_fwp_wait_interrupt - wait for FIFO to empty (interrupt-driven) + * @p: pointer to &struct parport + * + * Returns the number of bytes that can safely be written in the FIFO. A + * return value of zero means that the calling function should terminate as + * fast as possible. + */ +static unsigned int parport_ip32_fwp_wait_interrupt(struct parport *p) +{ + static unsigned int lost_interrupt = 0; + struct parport_ip32_private * const priv = p->physport->private_data; + struct parport * const physport = p->physport; + unsigned long nfault_timeout; + unsigned long expire; + unsigned int count; + unsigned int ecr; + + nfault_timeout = min((unsigned long)physport->cad->timeout, + msecs_to_jiffies(FIFO_NFAULT_TIMEOUT)); + expire = jiffies + physport->cad->timeout; + count = 0; + while (1) { + if (parport_ip32_fifo_wait_break(p, expire)) + break; + + /* Initialize mutex used to take interrupts into account */ + INIT_COMPLETION(priv->irq_complete); + + /* Enable serviceIntr */ + parport_ip32_frob_econtrol(p, ECR_SERVINTR, 0); + + /* Enabling serviceIntr while the FIFO is empty does not + * always generate an interrupt, so check for emptiness + * now. */ + ecr = parport_ip32_read_econtrol(p); + if (!(ecr & ECR_F_EMPTY)) { + /* FIFO is not empty: wait for an interrupt or a + * timeout to occur */ + wait_for_completion_interruptible_timeout( + &priv->irq_complete, nfault_timeout); + ecr = parport_ip32_read_econtrol(p); + if ((ecr & ECR_F_EMPTY) && !(ecr & ECR_SERVINTR) + && !lost_interrupt) { + printk(KERN_WARNING PPIP32 + "%s: lost interrupt in %s\n", + p->name, __func__); + lost_interrupt = 1; + } + } + + /* Disable serviceIntr */ + parport_ip32_frob_econtrol(p, ECR_SERVINTR, ECR_SERVINTR); + + /* Check FIFO state */ + if (ecr & ECR_F_EMPTY) { + /* FIFO is empty, fill it up */ + count = priv->fifo_depth; + break; + } else if (ecr & ECR_SERVINTR) { + /* FIFO is not empty, but we know that can safely push + * writeIntrThreshold bytes into it */ + count = priv->writeIntrThreshold; + break; + } + /* FIFO is not empty, and we did not get any interrupt. + * Either it's time to check for nFault, or a signal is + * pending. This is verified in + * parport_ip32_fifo_wait_break(), so we continue the loop. */ + } /* while (1) */ + + return count; +} + +/** + * parport_ip32_fifo_write_block_pio - write a block of data (PIO mode) + * @p: pointer to &struct parport + * @buf: buffer of data to write + * @len: length of buffer @buf + * + * Uses PIO to write the contents of the buffer @buf into the parallel port + * FIFO. Returns the number of bytes that were actually written. It can work + * with or without the help of interrupts. The parallel port must be + * correctly initialized before calling parport_ip32_fifo_write_block_pio(). + */ +static size_t parport_ip32_fifo_write_block_pio(struct parport *p, + const void *buf, size_t len) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + const u8 *bufp = buf; + size_t left = len; + + priv->irq_mode = PARPORT_IP32_IRQ_HERE; + + while (left > 0) { + unsigned int count; + + count = (p->irq == PARPORT_IRQ_NONE) ? + parport_ip32_fwp_wait_polling(p) : + parport_ip32_fwp_wait_interrupt(p); + if (count == 0) + break; /* Transmission should be stopped */ + if (count > left) + count = left; + if (count == 1) { + writeb(*bufp, priv->regs.fifo); + bufp++, left--; + } else { + writesb(priv->regs.fifo, bufp, count); + bufp += count, left -= count; + } + } + + priv->irq_mode = PARPORT_IP32_IRQ_FWD; + + return len - left; +} + +/** + * parport_ip32_fifo_write_block_dma - write a block of data (DMA mode) + * @p: pointer to &struct parport + * @buf: buffer of data to write + * @len: length of buffer @buf + * + * Uses DMA to write the contents of the buffer @buf into the parallel port + * FIFO. Returns the number of bytes that were actually written. The + * parallel port must be correctly initialized before calling + * parport_ip32_fifo_write_block_dma(). + */ +static size_t parport_ip32_fifo_write_block_dma(struct parport *p, + const void *buf, size_t len) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + struct parport * const physport = p->physport; + unsigned long nfault_timeout; + unsigned long expire; + size_t written; + unsigned int ecr; + + priv->irq_mode = PARPORT_IP32_IRQ_HERE; + + parport_ip32_dma_start(DMA_TO_DEVICE, (void *)buf, len); + INIT_COMPLETION(priv->irq_complete); + parport_ip32_frob_econtrol(p, ECR_DMAEN | ECR_SERVINTR, ECR_DMAEN); + + nfault_timeout = min((unsigned long)physport->cad->timeout, + msecs_to_jiffies(FIFO_NFAULT_TIMEOUT)); + expire = jiffies + physport->cad->timeout; + while (1) { + if (parport_ip32_fifo_wait_break(p, expire)) + break; + wait_for_completion_interruptible_timeout(&priv->irq_complete, + nfault_timeout); + ecr = parport_ip32_read_econtrol(p); + if (ecr & ECR_SERVINTR) + break; /* DMA transfer just finished */ + } + parport_ip32_dma_stop(); + written = len - parport_ip32_dma_get_residue(); + + priv->irq_mode = PARPORT_IP32_IRQ_FWD; + + return written; +} + +/** + * parport_ip32_fifo_write_block - write a block of data + * @p: pointer to &struct parport + * @buf: buffer of data to write + * @len: length of buffer @buf + * + * Uses PIO or DMA to write the contents of the buffer @buf into the parallel + * p FIFO. Returns the number of bytes that were actually written. + */ +static size_t parport_ip32_fifo_write_block(struct parport *p, + const void *buf, size_t len) +{ + size_t written = 0; + if (len) + /* FIXME - Maybe some threshold value should be set for @len + * under which we revert to PIO mode? */ + written = (p->modes & PARPORT_MODE_DMA) ? + parport_ip32_fifo_write_block_dma(p, buf, len) : + parport_ip32_fifo_write_block_pio(p, buf, len); + return written; +} + +/** + * parport_ip32_drain_fifo - wait for FIFO to empty + * @p: pointer to &struct parport + * @timeout: timeout, in jiffies + * + * This function waits for FIFO to empty. It returns 1 when FIFO is empty, or + * 0 if the timeout @timeout is reached before, or if a signal is pending. + */ +static unsigned int parport_ip32_drain_fifo(struct parport *p, + unsigned long timeout) +{ + unsigned long expire = jiffies + timeout; + unsigned int polling_interval; + unsigned int counter; + + /* Busy wait for approx. 200us */ + for (counter = 0; counter < 40; counter++) { + if (parport_ip32_read_econtrol(p) & ECR_F_EMPTY) + break; + if (time_after(jiffies, expire)) + break; + if (signal_pending(current)) + break; + udelay(5); + } + /* Poll slowly. Polling interval starts with 1 millisecond, and is + * increased exponentially until 128. */ + polling_interval = 1; /* msecs */ + while (!(parport_ip32_read_econtrol(p) & ECR_F_EMPTY)) { + if (time_after_eq(jiffies, expire)) + break; + msleep_interruptible(polling_interval); + if (signal_pending(current)) + break; + if (polling_interval < 128) + polling_interval *= 2; + } + + return !!(parport_ip32_read_econtrol(p) & ECR_F_EMPTY); +} + +/** + * parport_ip32_get_fifo_residue - reset FIFO + * @p: pointer to &struct parport + * @mode: current operation mode (ECR_MODE_PPF or ECR_MODE_ECP) + * + * This function resets FIFO, and returns the number of bytes remaining in it. + */ +static unsigned int parport_ip32_get_fifo_residue(struct parport *p, + unsigned int mode) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + unsigned int residue; + unsigned int cnfga; + + /* FIXME - We are missing one byte if the printer is off-line. I + * don't know how to detect this. It looks that the full bit is not + * always reliable. For the moment, the problem is avoided in most + * cases by testing for BUSY in parport_ip32_compat_write_data(). + */ + if (parport_ip32_read_econtrol(p) & ECR_F_EMPTY) + residue = 0; + else { + pr_debug1(PPIP32 "%s: FIFO is stuck\n", p->name); + + /* Stop all transfers. + * + * Microsoft's document instructs to drive DCR_STROBE to 0, + * but it doesn't work (at least in Compatibility mode, not + * tested in ECP mode). Switching directly to Test mode (as + * in parport_pc) is not an option: it does confuse the port, + * ECP service interrupts are no more working after that. A + * hard reset is then needed to revert to a sane state. + * + * Let's hope that the FIFO is really stuck and that the + * peripheral doesn't wake up now. + */ + parport_ip32_frob_control(p, DCR_STROBE, 0); + + /* Fill up FIFO */ + for (residue = priv->fifo_depth; residue > 0; residue--) { + if (parport_ip32_read_econtrol(p) & ECR_F_FULL) + break; + writeb(0x00, priv->regs.fifo); + } + } + if (residue) + pr_debug1(PPIP32 "%s: %d PWord%s left in FIFO\n", + p->name, residue, + (residue == 1) ? " was" : "s were"); + + /* Now reset the FIFO */ + parport_ip32_set_mode(p, ECR_MODE_PS2); + + /* Host recovery for ECP mode */ + if (mode == ECR_MODE_ECP) { + parport_ip32_data_reverse(p); + parport_ip32_frob_control(p, DCR_nINIT, 0); + if (parport_wait_peripheral(p, DSR_PERROR, 0)) + pr_debug1(PPIP32 "%s: PEerror timeout 1 in %s\n", + p->name, __func__); + parport_ip32_frob_control(p, DCR_STROBE, DCR_STROBE); + parport_ip32_frob_control(p, DCR_nINIT, DCR_nINIT); + if (parport_wait_peripheral(p, DSR_PERROR, DSR_PERROR)) + pr_debug1(PPIP32 "%s: PEerror timeout 2 in %s\n", + p->name, __func__); + } + + /* Adjust residue if needed */ + parport_ip32_set_mode(p, ECR_MODE_CFG); + cnfga = readb(priv->regs.cnfgA); + if (!(cnfga & CNFGA_nBYTEINTRANS)) { + pr_debug1(PPIP32 "%s: cnfgA contains 0x%02x\n", + p->name, cnfga); + pr_debug1(PPIP32 "%s: Accounting for extra byte\n", + p->name); + residue++; + } + + /* Don't care about partial PWords since we do not support + * PWord != 1 byte. */ + + /* Back to forward PS2 mode. */ + parport_ip32_set_mode(p, ECR_MODE_PS2); + parport_ip32_data_forward(p); + + return residue; +} + +/** + * parport_ip32_compat_write_data - write a block of data in SPP mode + * @p: pointer to &struct parport + * @buf: buffer of data to write + * @len: length of buffer @buf + * @flags: ignored + */ +static size_t parport_ip32_compat_write_data(struct parport *p, + const void *buf, size_t len, + int flags) +{ + static unsigned int ready_before = 1; + struct parport_ip32_private * const priv = p->physport->private_data; + struct parport * const physport = p->physport; + size_t written = 0; + + /* Special case: a timeout of zero means we cannot call schedule(). + * Also if O_NONBLOCK is set then use the default implementation. */ + if (physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) + return parport_ieee1284_write_compat(p, buf, len, flags); + + /* Reset FIFO, go in forward mode, and disable ackIntEn */ + parport_ip32_set_mode(p, ECR_MODE_PS2); + parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT); + parport_ip32_data_forward(p); + parport_ip32_disable_irq(p); + parport_ip32_set_mode(p, ECR_MODE_PPF); + physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; + + /* Wait for peripheral to become ready */ + if (parport_wait_peripheral(p, DSR_nBUSY | DSR_nFAULT, + DSR_nBUSY | DSR_nFAULT)) { + /* Avoid to flood the logs */ + if (ready_before) + printk(KERN_INFO PPIP32 "%s: not ready in %s\n", + p->name, __func__); + ready_before = 0; + goto stop; + } + ready_before = 1; + + written = parport_ip32_fifo_write_block(p, buf, len); + + /* Wait FIFO to empty. Timeout is proportional to FIFO_depth. */ + parport_ip32_drain_fifo(p, physport->cad->timeout * priv->fifo_depth); + + /* Check for a potential residue */ + written -= parport_ip32_get_fifo_residue(p, ECR_MODE_PPF); + + /* Then, wait for BUSY to get low. */ + if (parport_wait_peripheral(p, DSR_nBUSY, DSR_nBUSY)) + printk(KERN_DEBUG PPIP32 "%s: BUSY timeout in %s\n", + p->name, __func__); + +stop: + /* Reset FIFO */ + parport_ip32_set_mode(p, ECR_MODE_PS2); + physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + + return written; +} + +/* + * FIXME - Insert here parport_ip32_ecp_read_data(). + */ + +/** + * parport_ip32_ecp_write_data - write a block of data in ECP mode + * @p: pointer to &struct parport + * @buf: buffer of data to write + * @len: length of buffer @buf + * @flags: ignored + */ +static size_t parport_ip32_ecp_write_data(struct parport *p, + const void *buf, size_t len, + int flags) +{ + static unsigned int ready_before = 1; + struct parport_ip32_private * const priv = p->physport->private_data; + struct parport * const physport = p->physport; + size_t written = 0; + + /* Special case: a timeout of zero means we cannot call schedule(). + * Also if O_NONBLOCK is set then use the default implementation. */ + if (physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) + return parport_ieee1284_ecp_write_data(p, buf, len, flags); + + /* Negotiate to forward mode if necessary. */ + if (physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) { + /* Event 47: Set nInit high. */ + parport_ip32_frob_control(p, DCR_nINIT | DCR_AUTOFD, + DCR_nINIT | DCR_AUTOFD); + + /* Event 49: PError goes high. */ + if (parport_wait_peripheral(p, DSR_PERROR, DSR_PERROR)) { + printk(KERN_DEBUG PPIP32 "%s: PError timeout in %s", + p->name, __func__); + physport->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN; + return 0; + } + } + + /* Reset FIFO, go in forward mode, and disable ackIntEn */ + parport_ip32_set_mode(p, ECR_MODE_PS2); + parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT); + parport_ip32_data_forward(p); + parport_ip32_disable_irq(p); + parport_ip32_set_mode(p, ECR_MODE_ECP); + physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; + + /* Wait for peripheral to become ready */ + if (parport_wait_peripheral(p, DSR_nBUSY | DSR_nFAULT, + DSR_nBUSY | DSR_nFAULT)) { + /* Avoid to flood the logs */ + if (ready_before) + printk(KERN_INFO PPIP32 "%s: not ready in %s\n", + p->name, __func__); + ready_before = 0; + goto stop; + } + ready_before = 1; + + written = parport_ip32_fifo_write_block(p, buf, len); + + /* Wait FIFO to empty. Timeout is proportional to FIFO_depth. */ + parport_ip32_drain_fifo(p, physport->cad->timeout * priv->fifo_depth); + + /* Check for a potential residue */ + written -= parport_ip32_get_fifo_residue(p, ECR_MODE_ECP); + + /* Then, wait for BUSY to get low. */ + if (parport_wait_peripheral(p, DSR_nBUSY, DSR_nBUSY)) + printk(KERN_DEBUG PPIP32 "%s: BUSY timeout in %s\n", + p->name, __func__); + +stop: + /* Reset FIFO */ + parport_ip32_set_mode(p, ECR_MODE_PS2); + physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + + return written; +} + +/* + * FIXME - Insert here parport_ip32_ecp_write_addr(). + */ + +/*--- Default parport operations ---------------------------------------*/ + +static __initdata struct parport_operations parport_ip32_ops = { + .write_data = parport_ip32_write_data, + .read_data = parport_ip32_read_data, + + .write_control = parport_ip32_write_control, + .read_control = parport_ip32_read_control, + .frob_control = parport_ip32_frob_control, + + .read_status = parport_ip32_read_status, + + .enable_irq = parport_ip32_enable_irq, + .disable_irq = parport_ip32_disable_irq, + + .data_forward = parport_ip32_data_forward, + .data_reverse = parport_ip32_data_reverse, + + .init_state = parport_ip32_init_state, + .save_state = parport_ip32_save_state, + .restore_state = parport_ip32_restore_state, + + .epp_write_data = parport_ieee1284_epp_write_data, + .epp_read_data = parport_ieee1284_epp_read_data, + .epp_write_addr = parport_ieee1284_epp_write_addr, + .epp_read_addr = parport_ieee1284_epp_read_addr, + + .ecp_write_data = parport_ieee1284_ecp_write_data, + .ecp_read_data = parport_ieee1284_ecp_read_data, + .ecp_write_addr = parport_ieee1284_ecp_write_addr, + + .compat_write_data = parport_ieee1284_write_compat, + .nibble_read_data = parport_ieee1284_read_nibble, + .byte_read_data = parport_ieee1284_read_byte, + + .owner = THIS_MODULE, +}; + +/*--- Device detection -------------------------------------------------*/ + +/** + * parport_ip32_ecp_supported - check for an ECP port + * @p: pointer to the &parport structure + * + * Returns 1 if an ECP port is found, and 0 otherwise. This function actually + * checks if an Extended Control Register seems to be present. On successful + * return, the port is placed in SPP mode. + */ +static __init unsigned int parport_ip32_ecp_supported(struct parport *p) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + unsigned int ecr; + + ecr = ECR_MODE_PS2 | ECR_nERRINTR | ECR_SERVINTR; + writeb(ecr, priv->regs.ecr); + if (readb(priv->regs.ecr) != (ecr | ECR_F_EMPTY)) + goto fail; + + pr_probe(p, "Found working ECR register\n"); + parport_ip32_set_mode(p, ECR_MODE_SPP); + parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT); + return 1; + +fail: + pr_probe(p, "ECR register not found\n"); + return 0; +} + +/** + * parport_ip32_fifo_supported - check for FIFO parameters + * @p: pointer to the &parport structure + * + * Check for FIFO parameters of an Extended Capabilities Port. Returns 1 on + * success, and 0 otherwise. Adjust FIFO parameters in the parport structure. + * On return, the port is placed in SPP mode. + */ +static __init unsigned int parport_ip32_fifo_supported(struct parport *p) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + unsigned int configa, configb; + unsigned int pword; + unsigned int i; + + /* Configuration mode */ + parport_ip32_set_mode(p, ECR_MODE_CFG); + configa = readb(priv->regs.cnfgA); + configb = readb(priv->regs.cnfgB); + + /* Find out PWord size */ + switch (configa & CNFGA_ID_MASK) { + case CNFGA_ID_8: + pword = 1; + break; + case CNFGA_ID_16: + pword = 2; + break; + case CNFGA_ID_32: + pword = 4; + break; + default: + pr_probe(p, "Unknown implementation ID: 0x%0x\n", + (configa & CNFGA_ID_MASK) >> CNFGA_ID_SHIFT); + goto fail; + break; + } + if (pword != 1) { + pr_probe(p, "Unsupported PWord size: %u\n", pword); + goto fail; + } + priv->pword = pword; + pr_probe(p, "PWord is %u bits\n", 8 * priv->pword); + + /* Check for compression support */ + writeb(configb | CNFGB_COMPRESS, priv->regs.cnfgB); + if (readb(priv->regs.cnfgB) & CNFGB_COMPRESS) + pr_probe(p, "Hardware compression detected (unsupported)\n"); + writeb(configb & ~CNFGB_COMPRESS, priv->regs.cnfgB); + + /* Reset FIFO and go in test mode (no interrupt, no DMA) */ + parport_ip32_set_mode(p, ECR_MODE_TST); + + /* FIFO must be empty now */ + if (!(readb(priv->regs.ecr) & ECR_F_EMPTY)) { + pr_probe(p, "FIFO not reset\n"); + goto fail; + } + + /* Find out FIFO depth. */ + priv->fifo_depth = 0; + for (i = 0; i < 1024; i++) { + if (readb(priv->regs.ecr) & ECR_F_FULL) { + /* FIFO full */ + priv->fifo_depth = i; + break; + } + writeb((u8)i, priv->regs.fifo); + } + if (i >= 1024) { + pr_probe(p, "Can't fill FIFO\n"); + goto fail; + } + if (!priv->fifo_depth) { + pr_probe(p, "Can't get FIFO depth\n"); + goto fail; + } + pr_probe(p, "FIFO is %u PWords deep\n", priv->fifo_depth); + + /* Enable interrupts */ + parport_ip32_frob_econtrol(p, ECR_SERVINTR, 0); + + /* Find out writeIntrThreshold: number of PWords we know we can write + * if we get an interrupt. */ + priv->writeIntrThreshold = 0; + for (i = 0; i < priv->fifo_depth; i++) { + if (readb(priv->regs.fifo) != (u8)i) { + pr_probe(p, "Invalid data in FIFO\n"); + goto fail; + } + if (!priv->writeIntrThreshold + && readb(priv->regs.ecr) & ECR_SERVINTR) + /* writeIntrThreshold reached */ + priv->writeIntrThreshold = i + 1; + if (i + 1 < priv->fifo_depth + && readb(priv->regs.ecr) & ECR_F_EMPTY) { + /* FIFO empty before the last byte? */ + pr_probe(p, "Data lost in FIFO\n"); + goto fail; + } + } + if (!priv->writeIntrThreshold) { + pr_probe(p, "Can't get writeIntrThreshold\n"); + goto fail; + } + pr_probe(p, "writeIntrThreshold is %u\n", priv->writeIntrThreshold); + + /* FIFO must be empty now */ + if (!(readb(priv->regs.ecr) & ECR_F_EMPTY)) { + pr_probe(p, "Can't empty FIFO\n"); + goto fail; + } + + /* Reset FIFO */ + parport_ip32_set_mode(p, ECR_MODE_PS2); + /* Set reverse direction (must be in PS2 mode) */ + parport_ip32_data_reverse(p); + /* Test FIFO, no interrupt, no DMA */ + parport_ip32_set_mode(p, ECR_MODE_TST); + /* Enable interrupts */ + parport_ip32_frob_econtrol(p, ECR_SERVINTR, 0); + + /* Find out readIntrThreshold: number of PWords we can read if we get + * an interrupt. */ + priv->readIntrThreshold = 0; + for (i = 0; i < priv->fifo_depth; i++) { + writeb(0xaa, priv->regs.fifo); + if (readb(priv->regs.ecr) & ECR_SERVINTR) { + /* readIntrThreshold reached */ + priv->readIntrThreshold = i + 1; + break; + } + } + if (!priv->readIntrThreshold) { + pr_probe(p, "Can't get readIntrThreshold\n"); + goto fail; + } + pr_probe(p, "readIntrThreshold is %u\n", priv->readIntrThreshold); + + /* Reset ECR */ + parport_ip32_set_mode(p, ECR_MODE_PS2); + parport_ip32_data_forward(p); + parport_ip32_set_mode(p, ECR_MODE_SPP); + return 1; + +fail: + priv->fifo_depth = 0; + parport_ip32_set_mode(p, ECR_MODE_SPP); + return 0; +} + +/*--- Initialization code ----------------------------------------------*/ + +/** + * parport_ip32_make_isa_registers - compute (ISA) register addresses + * @regs: pointer to &struct parport_ip32_regs to fill + * @base: base address of standard and EPP registers + * @base_hi: base address of ECP registers + * @regshift: how much to shift register offset by + * + * Compute register addresses, according to the ISA standard. The addresses + * of the standard and EPP registers are computed from address @base. The + * addresses of the ECP registers are computed from address @base_hi. + */ +static void __init +parport_ip32_make_isa_registers(struct parport_ip32_regs *regs, + void __iomem *base, void __iomem *base_hi, + unsigned int regshift) +{ +#define r_base(offset) ((u8 __iomem *)base + ((offset) << regshift)) +#define r_base_hi(offset) ((u8 __iomem *)base_hi + ((offset) << regshift)) + *regs = (struct parport_ip32_regs){ + .data = r_base(0), + .dsr = r_base(1), + .dcr = r_base(2), + .eppAddr = r_base(3), + .eppData0 = r_base(4), + .eppData1 = r_base(5), + .eppData2 = r_base(6), + .eppData3 = r_base(7), + .ecpAFifo = r_base(0), + .fifo = r_base_hi(0), + .cnfgA = r_base_hi(0), + .cnfgB = r_base_hi(1), + .ecr = r_base_hi(2) + }; +#undef r_base_hi +#undef r_base +} + +/** + * parport_ip32_probe_port - probe and register IP32 built-in parallel port + * + * Returns the new allocated &parport structure. On error, an error code is + * encoded in return value with the ERR_PTR function. + */ +static __init struct parport *parport_ip32_probe_port(void) +{ + struct parport_ip32_regs regs; + struct parport_ip32_private *priv = NULL; + struct parport_operations *ops = NULL; + struct parport *p = NULL; + int err; + + parport_ip32_make_isa_registers(®s, &mace->isa.parallel, + &mace->isa.ecp1284, 8 /* regshift */); + + ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL); + priv = kmalloc(sizeof(struct parport_ip32_private), GFP_KERNEL); + p = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, ops); + if (ops == NULL || priv == NULL || p == NULL) { + err = -ENOMEM; + goto fail; + } + p->base = MACE_BASE + offsetof(struct sgi_mace, isa.parallel); + p->base_hi = MACE_BASE + offsetof(struct sgi_mace, isa.ecp1284); + p->private_data = priv; + + *ops = parport_ip32_ops; + *priv = (struct parport_ip32_private){ + .regs = regs, + .dcr_writable = DCR_DIR | DCR_SELECT | DCR_nINIT | + DCR_AUTOFD | DCR_STROBE, + .irq_mode = PARPORT_IP32_IRQ_FWD, + }; + init_completion(&priv->irq_complete); + + /* Probe port. */ + if (!parport_ip32_ecp_supported(p)) { + err = -ENODEV; + goto fail; + } + parport_ip32_dump_state(p, "begin init", 0); + + /* We found what looks like a working ECR register. Simply assume + * that all modes are correctly supported. Enable basic modes. */ + p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT; + p->modes |= PARPORT_MODE_TRISTATE; + + if (!parport_ip32_fifo_supported(p)) { + printk(KERN_WARNING PPIP32 + "%s: error: FIFO disabled\n", p->name); + /* Disable hardware modes depending on a working FIFO. */ + features &= ~PARPORT_IP32_ENABLE_SPP; + features &= ~PARPORT_IP32_ENABLE_ECP; + /* DMA is not needed if FIFO is not supported. */ + features &= ~PARPORT_IP32_ENABLE_DMA; + } + + /* Request IRQ */ + if (features & PARPORT_IP32_ENABLE_IRQ) { + int irq = MACEISA_PARALLEL_IRQ; + if (request_irq(irq, parport_ip32_interrupt, 0, p->name, p)) { + printk(KERN_WARNING PPIP32 + "%s: error: IRQ disabled\n", p->name); + /* DMA cannot work without interrupts. */ + features &= ~PARPORT_IP32_ENABLE_DMA; + } else { + pr_probe(p, "Interrupt support enabled\n"); + p->irq = irq; + priv->dcr_writable |= DCR_IRQ; + } + } + + /* Allocate DMA resources */ + if (features & PARPORT_IP32_ENABLE_DMA) { + if (parport_ip32_dma_register()) + printk(KERN_WARNING PPIP32 + "%s: error: DMA disabled\n", p->name); + else { + pr_probe(p, "DMA support enabled\n"); + p->dma = 0; /* arbitrary value != PARPORT_DMA_NONE */ + p->modes |= PARPORT_MODE_DMA; + } + } + + if (features & PARPORT_IP32_ENABLE_SPP) { + /* Enable compatibility FIFO mode */ + p->ops->compat_write_data = parport_ip32_compat_write_data; + p->modes |= PARPORT_MODE_COMPAT; + pr_probe(p, "Hardware support for SPP mode enabled\n"); + } + if (features & PARPORT_IP32_ENABLE_EPP) { + /* Set up access functions to use EPP hardware. */ + p->ops->epp_read_data = parport_ip32_epp_read_data; + p->ops->epp_write_data = parport_ip32_epp_write_data; + p->ops->epp_read_addr = parport_ip32_epp_read_addr; + p->ops->epp_write_addr = parport_ip32_epp_write_addr; + p->modes |= PARPORT_MODE_EPP; + pr_probe(p, "Hardware support for EPP mode enabled\n"); + } + if (features & PARPORT_IP32_ENABLE_ECP) { + /* Enable ECP FIFO mode */ + p->ops->ecp_write_data = parport_ip32_ecp_write_data; + /* FIXME - not implemented */ +/* p->ops->ecp_read_data = parport_ip32_ecp_read_data; */ +/* p->ops->ecp_write_addr = parport_ip32_ecp_write_addr; */ + p->modes |= PARPORT_MODE_ECP; + pr_probe(p, "Hardware support for ECP mode enabled\n"); + } + + /* Initialize the port with sensible values */ + parport_ip32_set_mode(p, ECR_MODE_PS2); + parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT); + parport_ip32_data_forward(p); + parport_ip32_disable_irq(p); + parport_ip32_write_data(p, 0x00); + parport_ip32_dump_state(p, "end init", 0); + + /* Print out what we found */ + printk(KERN_INFO "%s: SGI IP32 at 0x%lx (0x%lx)", + p->name, p->base, p->base_hi); + if (p->irq != PARPORT_IRQ_NONE) + printk(", irq %d", p->irq); + printk(" ["); +#define printmode(x) if (p->modes & PARPORT_MODE_##x) \ + printk("%s%s", f++ ? "," : "", #x) + { + unsigned int f = 0; + printmode(PCSPP); + printmode(TRISTATE); + printmode(COMPAT); + printmode(EPP); + printmode(ECP); + printmode(DMA); + } +#undef printmode + printk("]\n"); + + parport_announce_port(p); + return p; + +fail: + if (p) + parport_put_port(p); + kfree(priv); + kfree(ops); + return ERR_PTR(err); +} + +/** + * parport_ip32_unregister_port - unregister a parallel port + * @p: pointer to the &struct parport + * + * Unregisters a parallel port and free previously allocated resources + * (memory, IRQ, ...). + */ +static __exit void parport_ip32_unregister_port(struct parport *p) +{ + struct parport_ip32_private * const priv = p->physport->private_data; + struct parport_operations *ops = p->ops; + + parport_remove_port(p); + if (p->modes & PARPORT_MODE_DMA) + parport_ip32_dma_unregister(); + if (p->irq != PARPORT_IRQ_NONE) + free_irq(p->irq, p); + parport_put_port(p); + kfree(priv); + kfree(ops); +} + +/** + * parport_ip32_init - module initialization function + */ +static int __init parport_ip32_init(void) +{ + pr_info(PPIP32 "SGI IP32 built-in parallel port driver v0.6\n"); + pr_debug1(PPIP32 "Compiled on %s, %s\n", __DATE__, __TIME__); + this_port = parport_ip32_probe_port(); + return IS_ERR(this_port) ? PTR_ERR(this_port) : 0; +} + +/** + * parport_ip32_exit - module termination function + */ +static void __exit parport_ip32_exit(void) +{ + parport_ip32_unregister_port(this_port); +} + +/*--- Module stuff -----------------------------------------------------*/ + +MODULE_AUTHOR("Arnaud Giersch <arnaud.giersch@free.fr>"); +MODULE_DESCRIPTION("SGI IP32 built-in parallel port driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.6"); /* update in parport_ip32_init() too */ + +module_init(parport_ip32_init); +module_exit(parport_ip32_exit); + +module_param(verbose_probing, bool, S_IRUGO); +MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialization"); + +module_param(features, uint, S_IRUGO); +MODULE_PARM_DESC(features, + "Bit mask of features to enable" + ", bit 0: IRQ support" + ", bit 1: DMA support" + ", bit 2: hardware SPP mode" + ", bit 3: hardware EPP mode" + ", bit 4: hardware ECP mode"); + +/*--- Inform (X)Emacs about preferred coding style ---------------------*/ +/* + * Local Variables: + * mode: c + * c-file-style: "linux" + * indent-tabs-mode: t + * tab-width: 8 + * fill-column: 78 + * ispell-local-dictionary: "american" + * End: + */ diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c index 76dd077e3184..166de3507780 100644 --- a/drivers/parport/parport_serial.c +++ b/drivers/parport/parport_serial.c @@ -329,9 +329,9 @@ static int __devinit parport_register (struct pci_dev *dev, if (priv->num_par == ARRAY_SIZE (priv->port)) { printk (KERN_WARNING - "parport_serial: %s: only %u parallel ports " + "parport_serial: %s: only %zu parallel ports " "supported (%d reported)\n", pci_name (dev), - ARRAY_SIZE (priv->port), card->numports); + ARRAY_SIZE(priv->port), card->numports); break; } diff --git a/drivers/parport/probe.c b/drivers/parport/probe.c index b62aee8de3cb..ea83b70e0de2 100644 --- a/drivers/parport/probe.c +++ b/drivers/parport/probe.c @@ -199,7 +199,7 @@ static ssize_t parport_read_device_id (struct parport *port, char *buffer, if (port->physport->ieee1284.phase != IEEE1284_PH_HBUSY_DAVAIL) { if (belen != len) { - printk (KERN_DEBUG "%s: Device ID was %d bytes" + printk (KERN_DEBUG "%s: Device ID was %zd bytes" " while device told it would be %d" " bytes\n", port->name, len, belen); @@ -214,7 +214,7 @@ static ssize_t parport_read_device_id (struct parport *port, char *buffer, if (buffer[len-1] == ';') { printk (KERN_DEBUG "%s: Device ID reading stopped" " before device told data not available. " - "Current idlen %d of %d, len bytes %02X %02X\n", + "Current idlen %u of %u, len bytes %02X %02X\n", port->name, current_idlen, numidlens, length[0], length[1]); goto done; diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig index 6f50cc9323d9..6912399d0937 100644 --- a/drivers/s390/block/Kconfig +++ b/drivers/s390/block/Kconfig @@ -55,13 +55,21 @@ config DASD_DIAG Disks under VM. If you are not running under VM or unsure what it is, say "N". +config DASD_EER + tristate "Extended error reporting (EER)" + depends on DASD + help + This driver provides a character device interface to the + DASD extended error reporting. This is only needed if you want to + use applications written for the EER facility. + config DASD_CMB tristate "Compatibility interface for DASD channel measurement blocks" depends on DASD help - This driver provides an additional interface to the channel measurement - facility, which is normally accessed though sysfs, with a set of - ioctl functions specific to the dasd driver. + This driver provides an additional interface to the channel + measurement facility, which is normally accessed though sysfs, with + a set of ioctl functions specific to the dasd driver. This is only needed if you want to use applications written for linux-2.4 dasd channel measurement facility interface. diff --git a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile index 58c6780134f7..0c0d871e8f51 100644 --- a/drivers/s390/block/Makefile +++ b/drivers/s390/block/Makefile @@ -5,6 +5,7 @@ dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o dasd_fba_mod-objs := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o dasd_diag_mod-objs := dasd_diag.o +dasd_eer_mod-objs := dasd_eer.o dasd_mod-objs := dasd.o dasd_ioctl.o dasd_proc.o dasd_devmap.o \ dasd_genhd.o dasd_erp.o @@ -13,5 +14,6 @@ obj-$(CONFIG_DASD_DIAG) += dasd_diag_mod.o obj-$(CONFIG_DASD_ECKD) += dasd_eckd_mod.o obj-$(CONFIG_DASD_FBA) += dasd_fba_mod.o obj-$(CONFIG_DASD_CMB) += dasd_cmb.o +obj-$(CONFIG_DASD_EER) += dasd_eer.o obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o obj-$(CONFIG_DCSSBLK) += dcssblk.o diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index abdf1ee633e7..08c88fcd8963 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -18,6 +18,7 @@ #include <linux/slab.h> #include <linux/buffer_head.h> #include <linux/hdreg.h> +#include <linux/notifier.h> #include <asm/ccwdev.h> #include <asm/ebcdic.h> @@ -57,6 +58,7 @@ static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); static void dasd_flush_ccw_queue(struct dasd_device *, int); static void dasd_tasklet(struct dasd_device *); static void do_kick_device(void *data); +static void dasd_disable_eer(struct dasd_device *device); /* * SECTION: Operations on the device structure. @@ -151,6 +153,8 @@ dasd_state_new_to_known(struct dasd_device *device) static inline void dasd_state_known_to_new(struct dasd_device * device) { + /* disable extended error reporting for this device */ + dasd_disable_eer(device); /* Forget the discipline information. */ device->discipline = NULL; device->state = DASD_STATE_NEW; @@ -867,6 +871,9 @@ dasd_handle_state_change_pending(struct dasd_device *device) struct dasd_ccw_req *cqr; struct list_head *l, *n; + /* first of all call extended error reporting */ + dasd_write_eer_trigger(DASD_EER_STATECHANGE, device, NULL); + device->stopped &= ~DASD_STOPPED_PENDING; /* restart all 'running' IO on queue */ @@ -1086,6 +1093,19 @@ restart: } goto restart; } + + /* first of all call extended error reporting */ + if (device->eer && cqr->status == DASD_CQR_FAILED) { + dasd_write_eer_trigger(DASD_EER_FATALERROR, + device, cqr); + + /* restart request */ + cqr->status = DASD_CQR_QUEUED; + cqr->retries = 255; + device->stopped |= DASD_STOPPED_QUIESCE; + goto restart; + } + /* Process finished ERP request. */ if (cqr->refers) { __dasd_process_erp(device, cqr); @@ -1223,7 +1243,8 @@ __dasd_start_head(struct dasd_device * device) cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); /* check FAILFAST */ if (device->stopped & ~DASD_STOPPED_PENDING && - test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags)) { + test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && + (!device->eer)) { cqr->status = DASD_CQR_FAILED; dasd_schedule_bh(device); } @@ -1965,6 +1986,9 @@ dasd_generic_notify(struct ccw_device *cdev, int event) switch (event) { case CIO_GONE: case CIO_NO_PATH: + /* first of all call extended error reporting */ + dasd_write_eer_trigger(DASD_EER_NOPATH, device, NULL); + if (device->state < DASD_STATE_BASIC) break; /* Device is active. We want to keep it. */ @@ -2022,6 +2046,51 @@ dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver) put_driver(drv); } +/* + * notifications for extended error reports + */ +static struct notifier_block *dasd_eer_chain; + +int +dasd_register_eer_notifier(struct notifier_block *nb) +{ + return notifier_chain_register(&dasd_eer_chain, nb); +} + +int +dasd_unregister_eer_notifier(struct notifier_block *nb) +{ + return notifier_chain_unregister(&dasd_eer_chain, nb); +} + +/* + * Notify the registered error reporting module of a problem + */ +void +dasd_write_eer_trigger(unsigned int id, struct dasd_device *device, + struct dasd_ccw_req *cqr) +{ + if (device->eer) { + struct dasd_eer_trigger temp; + temp.id = id; + temp.device = device; + temp.cqr = cqr; + notifier_call_chain(&dasd_eer_chain, DASD_EER_TRIGGER, + (void *)&temp); + } +} + +/* + * Tell the registered error reporting module to disable error reporting for + * a given device and to cleanup any private data structures on that device. + */ +static void +dasd_disable_eer(struct dasd_device *device) +{ + notifier_call_chain(&dasd_eer_chain, DASD_EER_DISABLE, (void *)device); +} + + static int __init dasd_init(void) { @@ -2103,6 +2172,11 @@ EXPORT_SYMBOL_GPL(dasd_generic_set_online); EXPORT_SYMBOL_GPL(dasd_generic_set_offline); EXPORT_SYMBOL_GPL(dasd_generic_auto_online); +EXPORT_SYMBOL(dasd_register_eer_notifier); +EXPORT_SYMBOL(dasd_unregister_eer_notifier); +EXPORT_SYMBOL(dasd_write_eer_trigger); + + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 4ee0f934e325..c811380b9079 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -1108,6 +1108,9 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense) case 0x0B: DEV_MESSAGE(KERN_WARNING, device, "%s", "FORMAT F - Volume is suspended duplex"); + /* call extended error reporting (EER) */ + dasd_write_eer_trigger(DASD_EER_PPRCSUSPEND, device, + erp->refers); break; case 0x0C: DEV_MESSAGE(KERN_WARNING, device, "%s", diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index bc3823d35223..e15dd7978050 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -29,6 +29,7 @@ #define DASD_ECKD_CCW_PSF 0x27 #define DASD_ECKD_CCW_RSSD 0x3e #define DASD_ECKD_CCW_LOCATE_RECORD 0x47 +#define DASD_ECKD_CCW_SNSS 0x54 #define DASD_ECKD_CCW_DEFINE_EXTENT 0x63 #define DASD_ECKD_CCW_WRITE_MT 0x85 #define DASD_ECKD_CCW_READ_MT 0x86 diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c new file mode 100644 index 000000000000..f70cd7716b24 --- /dev/null +++ b/drivers/s390/block/dasd_eer.c @@ -0,0 +1,1090 @@ +/* + * character device driver for extended error reporting + * + * + * Copyright (C) 2005 IBM Corporation + * extended error reporting for DASD ECKD devices + * Author(s): Stefan Weinhuber <wein@de.ibm.com> + * + */ + +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/device.h> +#include <linux/workqueue.h> +#include <linux/poll.h> +#include <linux/notifier.h> + +#include <asm/uaccess.h> +#include <asm/semaphore.h> +#include <asm/atomic.h> +#include <asm/ebcdic.h> + +#include "dasd_int.h" +#include "dasd_eckd.h" + + +MODULE_LICENSE("GPL"); + +MODULE_AUTHOR("Stefan Weinhuber <wein@de.ibm.com>"); +MODULE_DESCRIPTION("DASD extended error reporting module"); + + +#ifdef PRINTK_HEADER +#undef PRINTK_HEADER +#endif /* PRINTK_HEADER */ +#define PRINTK_HEADER "dasd(eer):" + + + + + +/*****************************************************************************/ +/* the internal buffer */ +/*****************************************************************************/ + +/* + * The internal buffer is meant to store obaque blobs of data, so it doesn't + * know of higher level concepts like triggers. + * It consists of a number of pages that are used as a ringbuffer. Each data + * blob is stored in a simple record that consists of an integer, which + * contains the size of the following data, and the data bytes themselfes. + * + * To allow for multiple independent readers we create one internal buffer + * each time the device is opened and destroy the buffer when the file is + * closed again. + * + * One record can be written to a buffer by using the functions + * - dasd_eer_start_record (one time per record to write the size to the buffer + * and reserve the space for the data) + * - dasd_eer_write_buffer (one or more times per record to write the data) + * The data can be written in several steps but you will have to compute + * the total size up front for the invocation of dasd_eer_start_record. + * If the ringbuffer is full, dasd_eer_start_record will remove the required + * number of old records. + * + * A record is typically read in two steps, first read the integer that + * specifies the size of the following data, then read the data. + * Both can be done by + * - dasd_eer_read_buffer + * + * For all mentioned functions you need to get the bufferlock first and keep it + * until a complete record is written or read. + */ + + +/* + * Alle information necessary to keep track of an internal buffer is kept in + * a struct eerbuffer. The buffer specific to a file pointer is strored in + * the private_data field of that file. To be able to write data to all + * existing buffers, each buffer is also added to the bufferlist. + * If the user doesn't want to read a complete record in one go, we have to + * keep track of the rest of the record. residual stores the number of bytes + * that are still to deliver. If the rest of the record is invalidated between + * two reads then residual will be set to -1 so that the next read will fail. + * All entries in the eerbuffer structure are protected with the bufferlock. + * To avoid races between writing to a buffer on the one side and creating + * and destroying buffers on the other side, the bufferlock must also be used + * to protect the bufferlist. + */ + +struct eerbuffer { + struct list_head list; + char **buffer; + int buffersize; + int buffer_page_count; + int head; + int tail; + int residual; +}; + +LIST_HEAD(bufferlist); + +static spinlock_t bufferlock = SPIN_LOCK_UNLOCKED; + +DECLARE_WAIT_QUEUE_HEAD(dasd_eer_read_wait_queue); + +/* + * How many free bytes are available on the buffer. + * needs to be called with bufferlock held + */ +static int +dasd_eer_get_free_bytes(struct eerbuffer *eerb) +{ + if (eerb->head < eerb->tail) { + return eerb->tail - eerb->head - 1; + } else + return eerb->buffersize - eerb->head + eerb->tail -1; +} + +/* + * How many bytes of buffer space are used. + * needs to be called with bufferlock held + */ +static int +dasd_eer_get_filled_bytes(struct eerbuffer *eerb) +{ + + if (eerb->head >= eerb->tail) { + return eerb->head - eerb->tail; + } else + return eerb->buffersize - eerb->tail + eerb->head; +} + +/* + * The dasd_eer_write_buffer function just copies count bytes of data + * to the buffer. Make sure to call dasd_eer_start_record first, to + * make sure that enough free space is available. + * needs to be called with bufferlock held + */ +static void +dasd_eer_write_buffer(struct eerbuffer *eerb, int count, char *data) +{ + + unsigned long headindex,localhead; + unsigned long rest, len; + char *nextdata; + + nextdata = data; + rest = count; + while (rest > 0) { + headindex = eerb->head / PAGE_SIZE; + localhead = eerb->head % PAGE_SIZE; + len = min(rest, (PAGE_SIZE - localhead)); + memcpy(eerb->buffer[headindex]+localhead, nextdata, len); + nextdata += len; + rest -= len; + eerb->head += len; + if ( eerb->head == eerb->buffersize ) + eerb->head = 0; /* wrap around */ + if (eerb->head > eerb->buffersize) { + MESSAGE(KERN_ERR, "%s", "runaway buffer head."); + BUG(); + } + } +} + +/* + * needs to be called with bufferlock held + */ +static int +dasd_eer_read_buffer(struct eerbuffer *eerb, int count, char *data) +{ + + unsigned long tailindex,localtail; + unsigned long rest, len, finalcount; + char *nextdata; + + finalcount = min(count, dasd_eer_get_filled_bytes(eerb)); + nextdata = data; + rest = finalcount; + while (rest > 0) { + tailindex = eerb->tail / PAGE_SIZE; + localtail = eerb->tail % PAGE_SIZE; + len = min(rest, (PAGE_SIZE - localtail)); + memcpy(nextdata, eerb->buffer[tailindex]+localtail, len); + nextdata += len; + rest -= len; + eerb->tail += len; + if ( eerb->tail == eerb->buffersize ) + eerb->tail = 0; /* wrap around */ + if (eerb->tail > eerb->buffersize) { + MESSAGE(KERN_ERR, "%s", "runaway buffer tail."); + BUG(); + } + } + return finalcount; +} + +/* + * Whenever you want to write a blob of data to the internal buffer you + * have to start by using this function first. It will write the number + * of bytes that will be written to the buffer. If necessary it will remove + * old records to make room for the new one. + * needs to be called with bufferlock held + */ +static int +dasd_eer_start_record(struct eerbuffer *eerb, int count) +{ + int tailcount; + if (count + sizeof(count) > eerb->buffersize) + return -ENOMEM; + while (dasd_eer_get_free_bytes(eerb) < count + sizeof(count)) { + if (eerb->residual > 0) { + eerb->tail += eerb->residual; + if (eerb->tail >= eerb->buffersize) + eerb->tail -= eerb->buffersize; + eerb->residual = -1; + } + dasd_eer_read_buffer(eerb, sizeof(tailcount), + (char*)(&tailcount)); + eerb->tail += tailcount; + if (eerb->tail >= eerb->buffersize) + eerb->tail -= eerb->buffersize; + } + dasd_eer_write_buffer(eerb, sizeof(count), (char*)(&count)); + + return 0; +}; + +/* + * release pages that are not used anymore + */ +static void +dasd_eer_free_buffer_pages(char **buf, int no_pages) +{ + int i; + + for (i = 0; i < no_pages; ++i) { + free_page((unsigned long)buf[i]); + } +} + +/* + * allocate a new set of memory pages + */ +static int +dasd_eer_allocate_buffer_pages(char **buf, int no_pages) +{ + int i; + + for (i = 0; i < no_pages; ++i) { + buf[i] = (char *) get_zeroed_page(GFP_KERNEL); + if (!buf[i]) { + dasd_eer_free_buffer_pages(buf, i); + return -ENOMEM; + } + } + return 0; +} + +/* + * empty the buffer by resetting head and tail + * In case there is a half read data blob in the buffer, we set residual + * to -1 to indicate that the remainder of the blob is lost. + */ +static void +dasd_eer_purge_buffer(struct eerbuffer *eerb) +{ + unsigned long flags; + + spin_lock_irqsave(&bufferlock, flags); + if (eerb->residual > 0) + eerb->residual = -1; + eerb->tail=0; + eerb->head=0; + spin_unlock_irqrestore(&bufferlock, flags); +} + +/* + * set the size of the buffer, newsize is the new number of pages to be used + * we don't try to copy any data back an forth, so any resize will also purge + * the buffer + */ +static int +dasd_eer_resize_buffer(struct eerbuffer *eerb, int newsize) +{ + int i, oldcount, reuse; + char **new; + char **old; + unsigned long flags; + + if (newsize < 1) + return -EINVAL; + if (eerb->buffer_page_count == newsize) { + /* documented behaviour is that any successfull invocation + * will purge all records */ + dasd_eer_purge_buffer(eerb); + return 0; + } + new = kmalloc(newsize*sizeof(char*), GFP_KERNEL); + if (!new) + return -ENOMEM; + + reuse=min(eerb->buffer_page_count, newsize); + for (i = 0; i < reuse; ++i) { + new[i] = eerb->buffer[i]; + } + if (eerb->buffer_page_count < newsize) { + if (dasd_eer_allocate_buffer_pages( + &new[eerb->buffer_page_count], + newsize - eerb->buffer_page_count)) { + kfree(new); + return -ENOMEM; + } + } + + spin_lock_irqsave(&bufferlock, flags); + old = eerb->buffer; + eerb->buffer = new; + if (eerb->residual > 0) + eerb->residual = -1; + eerb->tail = 0; + eerb->head = 0; + oldcount = eerb->buffer_page_count; + eerb->buffer_page_count = newsize; + spin_unlock_irqrestore(&bufferlock, flags); + + if (oldcount > newsize) { + for (i = newsize; i < oldcount; ++i) { + free_page((unsigned long)old[i]); + } + } + kfree(old); + + return 0; +} + + +/*****************************************************************************/ +/* The extended error reporting functionality */ +/*****************************************************************************/ + +/* + * When a DASD device driver wants to report an error, it calls the + * function dasd_eer_write_trigger (via a notifier mechanism) and gives the + * respective trigger ID as parameter. + * Currently there are four kinds of triggers: + * + * DASD_EER_FATALERROR: all kinds of unrecoverable I/O problems + * DASD_EER_PPRCSUSPEND: PPRC was suspended + * DASD_EER_NOPATH: There is no path to the device left. + * DASD_EER_STATECHANGE: The state of the device has changed. + * + * For the first three triggers all required information can be supplied by + * the caller. For these triggers a record is written by the function + * dasd_eer_write_standard_trigger. + * + * When dasd_eer_write_trigger is called to write a DASD_EER_STATECHANGE + * trigger, we have to gather the necessary sense data first. We cannot queue + * the necessary SNSS (sense subsystem status) request immediatly, since we + * are likely to run in a deadlock situation. Instead, we schedule a + * work_struct that calls the function dasd_eer_sense_subsystem_status to + * create and start an SNSS request asynchronously. + * + * To avoid memory allocations at runtime, the necessary memory is allocated + * when the extended error reporting is enabled for a device (by + * dasd_eer_probe). There is one private eer data structure for each eer + * enabled DASD device. It contains memory for the work_struct, one SNSS cqr + * and a flags field that is used to coordinate the use of the cqr. The call + * to write a state change trigger can come in at any time, so we have one flag + * CQR_IN_USE that protects the cqr itself. When this flag indicates that the + * cqr is currently in use, dasd_eer_sense_subsystem_status cannot start a + * second request but sets the SNSS_REQUESTED flag instead. + * + * When the request is finished, the callback function dasd_eer_SNSS_cb + * is called. This function will invoke the function + * dasd_eer_write_SNSS_trigger to finally write the trigger. It will also + * check the SNSS_REQUESTED flag and if it is set it will call + * dasd_eer_sense_subsystem_status again. + * + * To avoid race conditions during the handling of the lock, the flags must + * be protected by the snsslock. + */ + +struct dasd_eer_private { + struct dasd_ccw_req *cqr; + unsigned long flags; + struct work_struct worker; +}; + +static void dasd_eer_destroy(struct dasd_device *device, + struct dasd_eer_private *eer); +static int +dasd_eer_write_trigger(struct dasd_eer_trigger *trigger); +static void dasd_eer_sense_subsystem_status(void *data); +static int dasd_eer_notify(struct notifier_block *self, + unsigned long action, void *data); + +struct workqueue_struct *dasd_eer_workqueue; + +#define SNSS_DATA_SIZE 44 +static spinlock_t snsslock = SPIN_LOCK_UNLOCKED; + +#define DASD_EER_BUSID_SIZE 10 +struct dasd_eer_header { + __u32 total_size; + __u32 trigger; + __u64 tv_sec; + __u64 tv_usec; + char busid[DASD_EER_BUSID_SIZE]; +} __attribute__ ((packed)); + +static struct notifier_block dasd_eer_nb = { + .notifier_call = dasd_eer_notify, +}; + +/* + * flags for use with dasd_eer_private + */ +#define CQR_IN_USE 0 +#define SNSS_REQUESTED 1 + +/* + * This function checks if extended error reporting is available for a given + * dasd_device. If yes, then it creates and returns a struct dasd_eer, + * otherwise it returns an -EPERM error pointer. + */ +struct dasd_eer_private * +dasd_eer_probe(struct dasd_device *device) +{ + struct dasd_eer_private *private; + + if (!(device && device->discipline + && !strcmp(device->discipline->name, "ECKD"))) { + return ERR_PTR(-EPERM); + } + /* allocate the private data structure */ + private = (struct dasd_eer_private *)kmalloc( + sizeof(struct dasd_eer_private), GFP_KERNEL); + if (!private) { + return ERR_PTR(-ENOMEM); + } + INIT_WORK(&private->worker, dasd_eer_sense_subsystem_status, + (void *)device); + private->cqr = dasd_kmalloc_request("ECKD", + 1 /* SNSS */ , + SNSS_DATA_SIZE , + device); + if (!private->cqr) { + kfree(private); + return ERR_PTR(-ENOMEM); + } + private->flags = 0; + return private; +}; + +/* + * If our private SNSS request is queued, remove it from the + * dasd ccw queue so we can free the requests memory. + */ +static void +dasd_eer_dequeue_SNSS_request(struct dasd_device *device, + struct dasd_eer_private *eer) +{ + struct list_head *lst, *nxt; + struct dasd_ccw_req *cqr, *erpcqr; + dasd_erp_fn_t erp_fn; + + spin_lock_irq(get_ccwdev_lock(device->cdev)); + list_for_each_safe(lst, nxt, &device->ccw_queue) { + cqr = list_entry(lst, struct dasd_ccw_req, list); + /* we are looking for two kinds or requests */ + /* first kind: our SNSS request: */ + if (cqr == eer->cqr) { + if (cqr->status == DASD_CQR_IN_IO) + device->discipline->term_IO(cqr); + list_del(&cqr->list); + break; + } + /* second kind: ERP requests for our SNSS request */ + if (cqr->refers) { + /* If this erp request chain ends in our cqr, then */ + /* cal the erp_postaction to clean it up */ + erpcqr = cqr; + while (erpcqr->refers) { + erpcqr = erpcqr->refers; + } + if (erpcqr == eer->cqr) { + erp_fn = device->discipline->erp_postaction( + cqr); + erp_fn(cqr); + } + continue; + } + } + spin_unlock_irq(get_ccwdev_lock(device->cdev)); +} + +/* + * This function dismantles a struct dasd_eer that was created by + * dasd_eer_probe. Since we want to free our private data structure, + * we must make sure that the memory is not in use anymore. + * We have to flush the work queue and remove a possible SNSS request + * from the dasd queue. + */ +static void +dasd_eer_destroy(struct dasd_device *device, struct dasd_eer_private *eer) +{ + flush_workqueue(dasd_eer_workqueue); + dasd_eer_dequeue_SNSS_request(device, eer); + dasd_kfree_request(eer->cqr, device); + kfree(eer); +}; + +/* + * enable the extended error reporting for a particular device + */ +static int +dasd_eer_enable_on_device(struct dasd_device *device) +{ + void *eer; + if (!device) + return -ENODEV; + if (device->eer) + return 0; + if (!try_module_get(THIS_MODULE)) { + return -EINVAL; + } + eer = (void *)dasd_eer_probe(device); + if (IS_ERR(eer)) { + module_put(THIS_MODULE); + return PTR_ERR(eer); + } + device->eer = eer; + return 0; +} + +/* + * enable the extended error reporting for a particular device + */ +static int +dasd_eer_disable_on_device(struct dasd_device *device) +{ + struct dasd_eer_private *eer = device->eer; + + if (!device) + return -ENODEV; + if (!device->eer) + return 0; + device->eer = NULL; + dasd_eer_destroy(device,eer); + module_put(THIS_MODULE); + + return 0; +} + +/* + * Set extended error reporting (eer) + * Note: This will be registered as a DASD ioctl, to be called on DASD devices. + */ +static int +dasd_ioctl_set_eer(struct block_device *bdev, int no, long args) +{ + struct dasd_device *device; + int intval; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (bdev != bdev->bd_contains) + /* Error-reporting is not allowed for partitions */ + return -EINVAL; + if (get_user(intval, (int __user *) args)) + return -EFAULT; + device = bdev->bd_disk->private_data; + if (device == NULL) + return -ENODEV; + + intval = (intval != 0); + DEV_MESSAGE (KERN_DEBUG, device, + "set eer on device to %d", intval); + if (intval) + return dasd_eer_enable_on_device(device); + else + return dasd_eer_disable_on_device(device); +} + +/* + * Get value of extended error reporting. + * Note: This will be registered as a DASD ioctl, to be called on DASD devices. + */ +static int +dasd_ioctl_get_eer(struct block_device *bdev, int no, long args) +{ + struct dasd_device *device; + + device = bdev->bd_disk->private_data; + if (device == NULL) + return -ENODEV; + return put_user((device->eer != NULL), (int __user *) args); +} + +/* + * The following function can be used for those triggers that have + * all necessary data available when the function is called. + * If the parameter cqr is not NULL, the chain of requests will be searched + * for valid sense data, and all valid sense data sets will be added to + * the triggers data. + */ +static int +dasd_eer_write_standard_trigger(int trigger, struct dasd_device *device, + struct dasd_ccw_req *cqr) +{ + struct dasd_ccw_req *temp_cqr; + int data_size; + struct timeval tv; + struct dasd_eer_header header; + unsigned long flags; + struct eerbuffer *eerb; + + /* go through cqr chain and count the valid sense data sets */ + temp_cqr = cqr; + data_size = 0; + while (temp_cqr) { + if (temp_cqr->irb.esw.esw0.erw.cons) + data_size += 32; + temp_cqr = temp_cqr->refers; + } + + header.total_size = sizeof(header) + data_size + 4; /* "EOR" */ + header.trigger = trigger; + do_gettimeofday(&tv); + header.tv_sec = tv.tv_sec; + header.tv_usec = tv.tv_usec; + strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE); + + spin_lock_irqsave(&bufferlock, flags); + list_for_each_entry(eerb, &bufferlist, list) { + dasd_eer_start_record(eerb, header.total_size); + dasd_eer_write_buffer(eerb, sizeof(header), (char*)(&header)); + temp_cqr = cqr; + while (temp_cqr) { + if (temp_cqr->irb.esw.esw0.erw.cons) + dasd_eer_write_buffer(eerb, 32, cqr->irb.ecw); + temp_cqr = temp_cqr->refers; + } + dasd_eer_write_buffer(eerb, 4,"EOR"); + } + spin_unlock_irqrestore(&bufferlock, flags); + + wake_up_interruptible(&dasd_eer_read_wait_queue); + + return 0; +} + +/* + * This function writes a DASD_EER_STATECHANGE trigger. + */ +static void +dasd_eer_write_SNSS_trigger(struct dasd_device *device, + struct dasd_ccw_req *cqr) +{ + int data_size; + int snss_rc; + struct timeval tv; + struct dasd_eer_header header; + unsigned long flags; + struct eerbuffer *eerb; + + snss_rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0; + if (snss_rc) + data_size = 0; + else + data_size = SNSS_DATA_SIZE; + + header.total_size = sizeof(header) + data_size + 4; /* "EOR" */ + header.trigger = DASD_EER_STATECHANGE; + do_gettimeofday(&tv); + header.tv_sec = tv.tv_sec; + header.tv_usec = tv.tv_usec; + strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE); + + spin_lock_irqsave(&bufferlock, flags); + list_for_each_entry(eerb, &bufferlist, list) { + dasd_eer_start_record(eerb, header.total_size); + dasd_eer_write_buffer(eerb, sizeof(header),(char*)(&header)); + if (!snss_rc) + dasd_eer_write_buffer(eerb, SNSS_DATA_SIZE, cqr->data); + dasd_eer_write_buffer(eerb, 4,"EOR"); + } + spin_unlock_irqrestore(&bufferlock, flags); + + wake_up_interruptible(&dasd_eer_read_wait_queue); +} + +/* + * callback function for use with SNSS request + */ +static void +dasd_eer_SNSS_cb(struct dasd_ccw_req *cqr, void *data) +{ + struct dasd_device *device; + struct dasd_eer_private *private; + unsigned long irqflags; + + device = (struct dasd_device *)data; + private = (struct dasd_eer_private *)device->eer; + dasd_eer_write_SNSS_trigger(device, cqr); + spin_lock_irqsave(&snsslock, irqflags); + if(!test_and_clear_bit(SNSS_REQUESTED, &private->flags)) { + clear_bit(CQR_IN_USE, &private->flags); + spin_unlock_irqrestore(&snsslock, irqflags); + return; + }; + clear_bit(CQR_IN_USE, &private->flags); + spin_unlock_irqrestore(&snsslock, irqflags); + dasd_eer_sense_subsystem_status(device); + return; +} + +/* + * clean a used cqr before using it again + */ +static void +dasd_eer_clean_SNSS_request(struct dasd_ccw_req *cqr) +{ + struct ccw1 *cpaddr = cqr->cpaddr; + void *data = cqr->data; + + memset(cqr, 0, sizeof(struct dasd_ccw_req)); + memset(cpaddr, 0, sizeof(struct ccw1)); + memset(data, 0, SNSS_DATA_SIZE); + cqr->cpaddr = cpaddr; + cqr->data = data; + strncpy((char *) &cqr->magic, "ECKD", 4); + ASCEBC((char *) &cqr->magic, 4); + set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); +} + +/* + * build and start an SNSS request + * This function is called from a work queue so we have to + * pass the dasd_device pointer as a void pointer. + */ +static void +dasd_eer_sense_subsystem_status(void *data) +{ + struct dasd_device *device; + struct dasd_eer_private *private; + struct dasd_ccw_req *cqr; + struct ccw1 *ccw; + unsigned long irqflags; + + device = (struct dasd_device *)data; + private = (struct dasd_eer_private *)device->eer; + if (!private) /* device not eer enabled any more */ + return; + cqr = private->cqr; + spin_lock_irqsave(&snsslock, irqflags); + if(test_and_set_bit(CQR_IN_USE, &private->flags)) { + set_bit(SNSS_REQUESTED, &private->flags); + spin_unlock_irqrestore(&snsslock, irqflags); + return; + }; + spin_unlock_irqrestore(&snsslock, irqflags); + dasd_eer_clean_SNSS_request(cqr); + cqr->device = device; + cqr->retries = 255; + cqr->expires = 10 * HZ; + + ccw = cqr->cpaddr; + ccw->cmd_code = DASD_ECKD_CCW_SNSS; + ccw->count = SNSS_DATA_SIZE; + ccw->flags = 0; + ccw->cda = (__u32)(addr_t)cqr->data; + + cqr->buildclk = get_clock(); + cqr->status = DASD_CQR_FILLED; + cqr->callback = dasd_eer_SNSS_cb; + cqr->callback_data = (void *)device; + dasd_add_request_head(cqr); + + return; +} + +/* + * This function is called for all triggers. It calls the appropriate + * function that writes the actual trigger records. + */ +static int +dasd_eer_write_trigger(struct dasd_eer_trigger *trigger) +{ + int rc; + struct dasd_eer_private *private = trigger->device->eer; + + switch (trigger->id) { + case DASD_EER_FATALERROR: + case DASD_EER_PPRCSUSPEND: + rc = dasd_eer_write_standard_trigger( + trigger->id, trigger->device, trigger->cqr); + break; + case DASD_EER_NOPATH: + rc = dasd_eer_write_standard_trigger( + trigger->id, trigger->device, NULL); + break; + case DASD_EER_STATECHANGE: + if (queue_work(dasd_eer_workqueue, &private->worker)) { + rc=0; + } else { + /* If the work_struct was already queued, it can't + * be queued again. But this is OK since we don't + * need to have it queued twice. + */ + rc = -EBUSY; + } + break; + default: /* unknown trigger, so we write it without any sense data */ + rc = dasd_eer_write_standard_trigger( + trigger->id, trigger->device, NULL); + break; + } + return rc; +} + +/* + * This function is registered with the dasd device driver and gets called + * for all dasd eer notifications. + */ +static int dasd_eer_notify(struct notifier_block *self, + unsigned long action, void *data) +{ + switch (action) { + case DASD_EER_DISABLE: + dasd_eer_disable_on_device((struct dasd_device *)data); + break; + case DASD_EER_TRIGGER: + dasd_eer_write_trigger((struct dasd_eer_trigger *)data); + break; + } + return NOTIFY_OK; +} + + +/*****************************************************************************/ +/* the device operations */ +/*****************************************************************************/ + +/* + * On the one side we need a lock to access our internal buffer, on the + * other side a copy_to_user can sleep. So we need to copy the data we have + * to transfer in a readbuffer, which is protected by the readbuffer_mutex. + */ +static char readbuffer[PAGE_SIZE]; +DECLARE_MUTEX(readbuffer_mutex); + + +static int +dasd_eer_open(struct inode *inp, struct file *filp) +{ + struct eerbuffer *eerb; + unsigned long flags; + + eerb = kmalloc(sizeof(struct eerbuffer), GFP_KERNEL); + eerb->head = 0; + eerb->tail = 0; + eerb->residual = 0; + eerb->buffer_page_count = 1; + eerb->buffersize = eerb->buffer_page_count * PAGE_SIZE; + eerb->buffer = kmalloc(eerb->buffer_page_count*sizeof(char*), + GFP_KERNEL); + if (!eerb->buffer) + return -ENOMEM; + if (dasd_eer_allocate_buffer_pages(eerb->buffer, + eerb->buffer_page_count)) { + kfree(eerb->buffer); + return -ENOMEM; + } + filp->private_data = eerb; + spin_lock_irqsave(&bufferlock, flags); + list_add(&eerb->list, &bufferlist); + spin_unlock_irqrestore(&bufferlock, flags); + + return nonseekable_open(inp,filp); +} + +static int +dasd_eer_close(struct inode *inp, struct file *filp) +{ + struct eerbuffer *eerb; + unsigned long flags; + + eerb = (struct eerbuffer *)filp->private_data; + spin_lock_irqsave(&bufferlock, flags); + list_del(&eerb->list); + spin_unlock_irqrestore(&bufferlock, flags); + dasd_eer_free_buffer_pages(eerb->buffer, eerb->buffer_page_count); + kfree(eerb->buffer); + kfree(eerb); + + return 0; +} + +static long +dasd_eer_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int intval; + struct eerbuffer *eerb; + + eerb = (struct eerbuffer *)filp->private_data; + switch (cmd) { + case DASD_EER_PURGE: + dasd_eer_purge_buffer(eerb); + return 0; + case DASD_EER_SETBUFSIZE: + if (get_user(intval, (int __user *)arg)) + return -EFAULT; + return dasd_eer_resize_buffer(eerb, intval); + default: + return -ENOIOCTLCMD; + } +} + +static ssize_t +dasd_eer_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) +{ + int tc,rc; + int tailcount,effective_count; + unsigned long flags; + struct eerbuffer *eerb; + + eerb = (struct eerbuffer *)filp->private_data; + if(down_interruptible(&readbuffer_mutex)) + return -ERESTARTSYS; + + spin_lock_irqsave(&bufferlock, flags); + + if (eerb->residual < 0) { /* the remainder of this record */ + /* has been deleted */ + eerb->residual = 0; + spin_unlock_irqrestore(&bufferlock, flags); + up(&readbuffer_mutex); + return -EIO; + } else if (eerb->residual > 0) { + /* OK we still have a second half of a record to deliver */ + effective_count = min(eerb->residual, (int)count); + eerb->residual -= effective_count; + } else { + tc = 0; + while (!tc) { + tc = dasd_eer_read_buffer(eerb, + sizeof(tailcount), (char*)(&tailcount)); + if (!tc) { + /* no data available */ + spin_unlock_irqrestore(&bufferlock, flags); + up(&readbuffer_mutex); + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + rc = wait_event_interruptible( + dasd_eer_read_wait_queue, + eerb->head != eerb->tail); + if (rc) { + return rc; + } + if(down_interruptible(&readbuffer_mutex)) + return -ERESTARTSYS; + spin_lock_irqsave(&bufferlock, flags); + } + } + WARN_ON(tc != sizeof(tailcount)); + effective_count = min(tailcount,(int)count); + eerb->residual = tailcount - effective_count; + } + + tc = dasd_eer_read_buffer(eerb, effective_count, readbuffer); + WARN_ON(tc != effective_count); + + spin_unlock_irqrestore(&bufferlock, flags); + + if (copy_to_user(buf, readbuffer, effective_count)) { + up(&readbuffer_mutex); + return -EFAULT; + } + + up(&readbuffer_mutex); + return effective_count; +} + +static unsigned int +dasd_eer_poll (struct file *filp, poll_table *ptable) +{ + unsigned int mask; + unsigned long flags; + struct eerbuffer *eerb; + + eerb = (struct eerbuffer *)filp->private_data; + poll_wait(filp, &dasd_eer_read_wait_queue, ptable); + spin_lock_irqsave(&bufferlock, flags); + if (eerb->head != eerb->tail) + mask = POLLIN | POLLRDNORM ; + else + mask = 0; + spin_unlock_irqrestore(&bufferlock, flags); + return mask; +} + +static struct file_operations dasd_eer_fops = { + .open = &dasd_eer_open, + .release = &dasd_eer_close, + .unlocked_ioctl = &dasd_eer_ioctl, + .compat_ioctl = &dasd_eer_ioctl, + .read = &dasd_eer_read, + .poll = &dasd_eer_poll, + .owner = THIS_MODULE, +}; + +static struct miscdevice dasd_eer_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "dasd_eer", + .fops = &dasd_eer_fops, +}; + + +/*****************************************************************************/ +/* Init and exit */ +/*****************************************************************************/ + +static int +__init dasd_eer_init(void) +{ + int rc; + + dasd_eer_workqueue = create_singlethread_workqueue("dasd_eer"); + if (!dasd_eer_workqueue) { + MESSAGE(KERN_ERR , "%s", "dasd_eer_init could not " + "create workqueue \n"); + rc = -ENOMEM; + goto out; + } + + rc = dasd_register_eer_notifier(&dasd_eer_nb); + if (rc) { + MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not " + "register error reporting"); + goto queue; + } + + dasd_ioctl_no_register(THIS_MODULE, BIODASDEERSET, dasd_ioctl_set_eer); + dasd_ioctl_no_register(THIS_MODULE, BIODASDEERGET, dasd_ioctl_get_eer); + + /* we don't need our own character device, + * so we just register as misc device */ + rc = misc_register(&dasd_eer_dev); + if (rc) { + MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not " + "register misc device"); + goto unregister; + } + + return 0; + +unregister: + dasd_unregister_eer_notifier(&dasd_eer_nb); + dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERSET, + dasd_ioctl_set_eer); + dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERGET, + dasd_ioctl_get_eer); +queue: + destroy_workqueue(dasd_eer_workqueue); +out: + return rc; + +} +module_init(dasd_eer_init); + +static void +__exit dasd_eer_exit(void) +{ + dasd_unregister_eer_notifier(&dasd_eer_nb); + dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERSET, + dasd_ioctl_set_eer); + dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERGET, + dasd_ioctl_get_eer); + destroy_workqueue(dasd_eer_workqueue); + + WARN_ON(misc_deregister(&dasd_eer_dev) != 0); +} +module_exit(dasd_eer_exit); diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index c20af9874500..d1b08fa13fd2 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -275,6 +275,34 @@ struct dasd_discipline { extern struct dasd_discipline *dasd_diag_discipline_pointer; + +/* + * Notification numbers for extended error reporting notifications: + * The DASD_EER_DISABLE notification is sent before a dasd_device (and it's + * eer pointer) is freed. The error reporting module needs to do all necessary + * cleanup steps. + * The DASD_EER_TRIGGER notification sends the actual error reports (triggers). + */ +#define DASD_EER_DISABLE 0 +#define DASD_EER_TRIGGER 1 + +/* Trigger IDs for extended error reporting DASD_EER_TRIGGER notification */ +#define DASD_EER_FATALERROR 1 +#define DASD_EER_NOPATH 2 +#define DASD_EER_STATECHANGE 3 +#define DASD_EER_PPRCSUSPEND 4 + +/* + * The dasd_eer_trigger structure contains all data that we need to send + * along with an DASD_EER_TRIGGER notification. + */ +struct dasd_eer_trigger { + unsigned int id; + struct dasd_device *device; + struct dasd_ccw_req *cqr; +}; + + struct dasd_device { /* Block device stuff. */ struct gendisk *gdp; @@ -288,6 +316,9 @@ struct dasd_device { unsigned long flags; /* per device flags */ unsigned short features; /* copy of devmap-features (read-only!) */ + /* extended error reporting stuff (eer) */ + void *eer; + /* Device discipline stuff. */ struct dasd_discipline *discipline; char *private; @@ -488,6 +519,12 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *); int dasd_generic_set_offline (struct ccw_device *cdev); int dasd_generic_notify(struct ccw_device *, int); void dasd_generic_auto_online (struct ccw_driver *); +int dasd_register_eer_notifier(struct notifier_block *); +int dasd_unregister_eer_notifier(struct notifier_block *); +void dasd_write_eer_trigger(unsigned int , struct dasd_device *, + struct dasd_ccw_req *); + + /* externals in dasd_devmap.c */ extern int dasd_max_devindex; diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 44e4b4bb1c5a..3e75095f35d0 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -68,6 +68,6 @@ extern void *chsc_get_chp_desc(struct subchannel*, int); extern int chsc_enable_facility(int); -#define to_channelpath(dev) container_of(dev, struct channel_path, dev) +#define to_channelpath(device) container_of(device, struct channel_path, dev) #endif diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 42d1de155292..0f4361c8466b 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -893,20 +893,20 @@ config SERIAL_VR41XX_CONSOLE a console on a serial port, say Y. Otherwise, say N. config SERIAL_JSM - tristate "Digi International NEO PCI Support" - depends on PCI && BROKEN - select SERIAL_CORE - help - This is a driver for Digi International's Neo series - of cards which provide multiple serial ports. You would need - something like this to connect more than two modems to your Linux - box, for instance in order to become a dial-in server. This driver - supports PCI boards only. - If you have a card like this, say Y here and read the file - <file:Documentation/jsm.txt>. - - To compile this driver as a module, choose M here: the - module will be called jsm. + tristate "Digi International NEO PCI Support" + depends on PCI + select SERIAL_CORE + help + This is a driver for Digi International's Neo series + of cards which provide multiple serial ports. You would need + something like this to connect more than two modems to your Linux + box, for instance in order to become a dial-in server. This driver + supports PCI boards only. + If you have a card like this, say Y here and read the file + <file:Documentation/jsm.txt>. + + To compile this driver as a module, choose M here: the + module will be called jsm. config SERIAL_SGI_IOC4 tristate "SGI IOC4 controller serial support" diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h index 18753193f59b..dfc1e86d3aa1 100644 --- a/drivers/serial/jsm/jsm.h +++ b/drivers/serial/jsm/jsm.h @@ -380,7 +380,6 @@ struct neo_uart_struct { extern struct uart_driver jsm_uart_driver; extern struct board_ops jsm_neo_ops; extern int jsm_debug; -extern int jsm_rawreadok; /************************************************************************* * diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c index 7e56c7824194..b1b66e71d281 100644 --- a/drivers/serial/jsm/jsm_driver.c +++ b/drivers/serial/jsm/jsm_driver.c @@ -49,11 +49,8 @@ struct uart_driver jsm_uart_driver = { }; int jsm_debug; -int jsm_rawreadok; module_param(jsm_debug, int, 0); -module_param(jsm_rawreadok, int, 0); MODULE_PARM_DESC(jsm_debug, "Driver debugging level"); -MODULE_PARM_DESC(jsm_rawreadok, "Bypass flip buffers on input"); static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) { diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c index 6fa0d62d6f68..4d48b625cd3d 100644 --- a/drivers/serial/jsm/jsm_tty.c +++ b/drivers/serial/jsm/jsm_tty.c @@ -20,8 +20,10 @@ * * Contact Information: * Scott H Kilau <Scott_Kilau@digi.com> - * Wendy Xiong <wendyx@us.ltcfwd.linux.ibm.com> - * + * Ananda Venkatarman <mansarov@us.ibm.com> + * Modifications: + * 01/19/06: changed jsm_input routine to use the dynamically allocated + * tty_buffer changes. Contributors: Scott Kilau and Ananda V. ***********************************************************************/ #include <linux/tty.h> #include <linux/tty_flip.h> @@ -497,16 +499,15 @@ void jsm_input(struct jsm_channel *ch) { struct jsm_board *bd; struct tty_struct *tp; + struct tty_ldisc *ld; u32 rmask; u16 head; u16 tail; int data_len; unsigned long lock_flags; - int flip_len; + int flip_len = 0; int len = 0; int n = 0; - char *buf = NULL; - char *buf2 = NULL; int s = 0; int i = 0; @@ -574,56 +575,50 @@ void jsm_input(struct jsm_channel *ch) /* * If the rxbuf is empty and we are not throttled, put as much - * as we can directly into the linux TTY flip buffer. - * The jsm_rawreadok case takes advantage of carnal knowledge that - * the char_buf and the flag_buf are next to each other and - * are each of (2 * TTY_FLIPBUF_SIZE) size. + * as we can directly into the linux TTY buffer. * - * NOTE: if(!tty->real_raw), the call to ldisc.receive_buf - *actually still uses the flag buffer, so you can't - *use it for input data */ - if (jsm_rawreadok) { - if (tp->real_raw) - flip_len = MYFLIPLEN; - else - flip_len = 2 * TTY_FLIPBUF_SIZE; - } else - flip_len = TTY_FLIPBUF_SIZE - tp->flip.count; + flip_len = TTY_FLIPBUF_SIZE; len = min(data_len, flip_len); len = min(len, (N_TTY_BUF_SIZE - 1) - tp->read_cnt); + ld = tty_ldisc_ref(tp); - if (len <= 0) { - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n"); - return; - } + /* + * If the DONT_FLIP flag is on, don't flush our buffer, and act + * like the ld doesn't have any space to put the data right now. + */ + if (test_bit(TTY_DONT_FLIP, &tp->flags)) + len = 0; /* - * If we're bypassing flip buffers on rx, we can blast it - * right into the beginning of the buffer. + * If we were unable to get a reference to the ld, + * don't flush our buffer, and act like the ld doesn't + * have any space to put the data right now. */ - if (jsm_rawreadok) { - if (tp->real_raw) { - if (ch->ch_flags & CH_FLIPBUF_IN_USE) { - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, - "JSM - FLIPBUF in use. delaying input\n"); - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - return; - } - ch->ch_flags |= CH_FLIPBUF_IN_USE; - buf = ch->ch_bd->flipbuf; - buf2 = NULL; - } else { - buf = tp->flip.char_buf; - buf2 = tp->flip.flag_buf; - } + if (!ld) { + len = 0; } else { - buf = tp->flip.char_buf_ptr; - buf2 = tp->flip.flag_buf_ptr; + /* + * If ld doesn't have a pointer to a receive_buf function, + * flush the data, then act like the ld doesn't have any + * space to put the data right now. + */ + if (!ld->receive_buf) { + ch->ch_r_head = ch->ch_r_tail; + len = 0; + } } + if (len <= 0) { + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n"); + if (ld) + tty_ldisc_deref(ld); + return; + } + + len = tty_buffer_request_room(tp, len); n = len; /* @@ -638,121 +633,47 @@ void jsm_input(struct jsm_channel *ch) if (s <= 0) break; - memcpy(buf, ch->ch_rqueue + tail, s); - - /* buf2 is only set when port isn't raw */ - if (buf2) - memcpy(buf2, ch->ch_equeue + tail, s); - - tail += s; - buf += s; - if (buf2) - buf2 += s; - n -= s; - /* Flip queue if needed */ - tail &= rmask; - } + /* + * If conditions are such that ld needs to see all + * UART errors, we will have to walk each character + * and error byte and send them to the buffer one at + * a time. + */ - /* - * In high performance mode, we don't have to update - * flag_buf or any of the counts or pointers into flip buf. - */ - if (!jsm_rawreadok) { if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { - for (i = 0; i < len; i++) { + for (i = 0; i < s; i++) { /* * Give the Linux ld the flags in the * format it likes. */ - if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI) - tp->flip.flag_buf_ptr[i] = TTY_BREAK; - else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE) - tp->flip.flag_buf_ptr[i] = TTY_PARITY; - else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE) - tp->flip.flag_buf_ptr[i] = TTY_FRAME; + if (*(ch->ch_equeue +tail +i) & UART_LSR_BI) + tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_BREAK); + else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE) + tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_PARITY); + else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE) + tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_FRAME); else - tp->flip.flag_buf_ptr[i] = TTY_NORMAL; + tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_NORMAL); } } else { - memset(tp->flip.flag_buf_ptr, 0, len); + tty_insert_flip_string(tp, ch->ch_rqueue + tail, s) ; } - - tp->flip.char_buf_ptr += len; - tp->flip.flag_buf_ptr += len; - tp->flip.count += len; - } - else if (!tp->real_raw) { - if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { - for (i = 0; i < len; i++) { - /* - * Give the Linux ld the flags in the - * format it likes. - */ - if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI) - tp->flip.flag_buf_ptr[i] = TTY_BREAK; - else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE) - tp->flip.flag_buf_ptr[i] = TTY_PARITY; - else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE) - tp->flip.flag_buf_ptr[i] = TTY_FRAME; - else - tp->flip.flag_buf_ptr[i] = TTY_NORMAL; - } - } else - memset(tp->flip.flag_buf, 0, len); + tail += s; + n -= s; + /* Flip queue if needed */ + tail &= rmask; } - /* - * If we're doing raw reads, jam it right into the - * line disc bypassing the flip buffers. - */ - if (jsm_rawreadok) { - if (tp->real_raw) { - ch->ch_r_tail = tail & rmask; - ch->ch_e_tail = tail & rmask; - - jsm_check_queue_flow_control(ch); - - /* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */ + ch->ch_r_tail = tail & rmask; + ch->ch_e_tail = tail & rmask; + jsm_check_queue_flow_control(ch); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + /* Tell the tty layer its okay to "eat" the data now */ + tty_flip_buffer_push(tp); - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, - "jsm_input. %d real_raw len:%d calling receive_buf for board %d\n", - __LINE__, len, ch->ch_bd->boardnum); - tp->ldisc.receive_buf(tp, ch->ch_bd->flipbuf, NULL, len); - - /* Allow use of channel flip buffer again */ - spin_lock_irqsave(&ch->ch_lock, lock_flags); - ch->ch_flags &= ~CH_FLIPBUF_IN_USE; - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - - } else { - ch->ch_r_tail = tail & rmask; - ch->ch_e_tail = tail & rmask; - - jsm_check_queue_flow_control(ch); - - /* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */ - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, - "jsm_input. %d not real_raw len:%d calling receive_buf for board %d\n", - __LINE__, len, ch->ch_bd->boardnum); - - tp->ldisc.receive_buf(tp, tp->flip.char_buf, tp->flip.flag_buf, len); - } - } else { - ch->ch_r_tail = tail & rmask; - ch->ch_e_tail = tail & rmask; - - jsm_check_queue_flow_control(ch); - - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, - "jsm_input. %d not jsm_read raw okay scheduling flip\n", __LINE__); - tty_schedule_flip(tp); - } + if (ld) + tty_ldisc_deref(ld); jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n"); } diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index d957a3a9edf1..0ef648fa4b2d 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -350,8 +350,7 @@ static inline void receive_chars(struct mcf_serial *info) } tty_insert_flip_char(tty, ch, flag); } - - schedule_work(&tty->flip.work); + tty_flip_buffer_push(tty); return; } diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index f6704688ee8c..5578a9dd04e8 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -3558,10 +3558,16 @@ static void ixj_write_frame(IXJ *j) } /* Add word 0 to G.729 frames for the 8021. Right now we don't do VAD/CNG */ if (j->play_codec == G729 && (cnt == 0 || cnt == 10 || cnt == 20)) { - if(j->write_buffer_rp + cnt == 0 && j->write_buffer_rp + cnt + 1 == 0 && j->write_buffer_rp + cnt + 2 == 0 && - j->write_buffer_rp + cnt + 3 == 0 && j->write_buffer_rp + cnt + 4 == 0 && j->write_buffer_rp + cnt + 5 == 0 && - j->write_buffer_rp + cnt + 6 == 0 && j->write_buffer_rp + cnt + 7 == 0 && j->write_buffer_rp + cnt + 8 == 0 && - j->write_buffer_rp + cnt + 9 == 0) { + if (j->write_buffer_rp[cnt] == 0 && + j->write_buffer_rp[cnt + 1] == 0 && + j->write_buffer_rp[cnt + 2] == 0 && + j->write_buffer_rp[cnt + 3] == 0 && + j->write_buffer_rp[cnt + 4] == 0 && + j->write_buffer_rp[cnt + 5] == 0 && + j->write_buffer_rp[cnt + 6] == 0 && + j->write_buffer_rp[cnt + 7] == 0 && + j->write_buffer_rp[cnt + 8] == 0 && + j->write_buffer_rp[cnt + 9] == 0) { /* someone is trying to write silence lets make this a type 0 frame. */ outb_p(0x00, j->DSPbase + 0x0C); outb_p(0x00, j->DSPbase + 0x0D); |