From b82d49d34b0713095c00afec86819096beb9b274 Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Thu, 24 Apr 2008 00:37:04 +0200 Subject: [PATCH] --- yaml --- r: 95776 b: refs/heads/master c: db11e47dd7b09b7f76c7eaa236277f23391331e7 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/Documentation/lguest/lguest.c | 62 +- trunk/arch/ia64/ia32/ia32_signal.c | 2 +- trunk/arch/ia64/kernel/acpi.c | 2 +- trunk/arch/ia64/kernel/irq.c | 4 +- trunk/arch/ia64/kernel/palinfo.c | 2 +- trunk/arch/ia64/kernel/perfmon.c | 199 ++- trunk/arch/ia64/kernel/signal.c | 15 +- trunk/arch/ia64/kernel/smp.c | 68 +- trunk/arch/ia64/kernel/time.c | 5 + trunk/arch/ia64/kernel/topology.c | 16 +- trunk/arch/m32r/Makefile | 2 - trunk/arch/m32r/defconfig | 863 ++++++++++ trunk/arch/m32r/kernel/vmlinux.lds.S | 3 + trunk/drivers/block/virtio_blk.c | 44 +- trunk/drivers/lguest/lguest_device.c | 68 +- trunk/drivers/lguest/lguest_user.c | 4 +- trunk/drivers/net/virtio_net.c | 96 +- trunk/drivers/usb/host/Kconfig | 26 + trunk/drivers/usb/host/Makefile | 4 +- trunk/drivers/usb/host/isp1760-hcd.c | 2231 +++++++++++++++++++++++++ trunk/drivers/usb/host/isp1760-hcd.h | 206 +++ trunk/drivers/usb/host/isp1760-if.c | 298 ++++ trunk/drivers/virtio/virtio.c | 38 +- trunk/drivers/virtio/virtio_balloon.c | 12 +- trunk/drivers/virtio/virtio_pci.c | 34 +- trunk/drivers/virtio/virtio_ring.c | 5 - trunk/include/asm-ia64/cpu.h | 2 +- trunk/include/asm-ia64/thread_info.h | 13 +- trunk/include/linux/Kbuild | 5 - trunk/include/linux/device.h | 8 +- trunk/include/linux/irq.h | 1 - trunk/include/linux/virtio.h | 7 - trunk/include/linux/virtio_blk.h | 14 +- trunk/include/linux/virtio_config.h | 81 +- trunk/include/linux/virtio_net.h | 13 +- trunk/kernel/irq/manage.c | 49 +- trunk/kernel/irq/spurious.c | 4 +- 38 files changed, 3981 insertions(+), 527 deletions(-) create mode 100644 trunk/arch/m32r/defconfig create mode 100644 trunk/drivers/usb/host/isp1760-hcd.c create mode 100644 trunk/drivers/usb/host/isp1760-hcd.h create mode 100644 trunk/drivers/usb/host/isp1760-if.c diff --git a/[refs] b/[refs] index 3d5fab9336f6..add81f27f08d 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 37b6a04fd9fc887bbcc1a27d9354a5e7a5a4cdd8 +refs/heads/master: db11e47dd7b09b7f76c7eaa236277f23391331e7 diff --git a/trunk/Documentation/lguest/lguest.c b/trunk/Documentation/lguest/lguest.c index 3be8ab2a886a..4c1fc65a8b3d 100644 --- a/trunk/Documentation/lguest/lguest.c +++ b/trunk/Documentation/lguest/lguest.c @@ -131,9 +131,6 @@ struct device /* Any queues attached to this device */ struct virtqueue *vq; - /* Handle status being finalized (ie. feature bits stable). */ - void (*ready)(struct device *me); - /* Device-specific data. */ void *priv; }; @@ -928,40 +925,24 @@ static void enable_fd(int fd, struct virtqueue *vq) write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd)); } -/* When the Guest tells us they updated the status field, we handle it. */ -static void update_device_status(struct device *dev) +/* When the Guest asks us to reset a device, it's is fairly easy. */ +static void reset_device(struct device *dev) { struct virtqueue *vq; - /* This is a reset. */ - if (dev->desc->status == 0) { - verbose("Resetting device %s\n", dev->name); + verbose("Resetting device %s\n", dev->name); + /* Clear the status. */ + dev->desc->status = 0; - /* Clear any features they've acked. */ - memset(get_feature_bits(dev) + dev->desc->feature_len, 0, - dev->desc->feature_len); + /* Clear any features they've acked. */ + memset(get_feature_bits(dev) + dev->desc->feature_len, 0, + dev->desc->feature_len); - /* Zero out the virtqueues. */ - for (vq = dev->vq; vq; vq = vq->next) { - memset(vq->vring.desc, 0, - vring_size(vq->config.num, getpagesize())); - vq->last_avail_idx = 0; - } - } else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) { - warnx("Device %s configuration FAILED", dev->name); - } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) { - unsigned int i; - - verbose("Device %s OK: offered", dev->name); - for (i = 0; i < dev->desc->feature_len; i++) - verbose(" %08x", get_feature_bits(dev)[i]); - verbose(", accepted"); - for (i = 0; i < dev->desc->feature_len; i++) - verbose(" %08x", get_feature_bits(dev) - [dev->desc->feature_len+i]); - - if (dev->ready) - dev->ready(dev); + /* Zero out the virtqueues. */ + for (vq = dev->vq; vq; vq = vq->next) { + memset(vq->vring.desc, 0, + vring_size(vq->config.num, getpagesize())); + vq->last_avail_idx = 0; } } @@ -973,9 +954,9 @@ static void handle_output(int fd, unsigned long addr) /* Check each device and virtqueue. */ for (i = devices.dev; i; i = i->next) { - /* Notifications to device descriptors update device status. */ + /* Notifications to device descriptors reset the device. */ if (from_guest_phys(addr) == i->desc) { - update_device_status(i); + reset_device(i); return; } @@ -1189,7 +1170,6 @@ static struct device *new_device(const char *name, u16 type, int fd, dev->handle_input = handle_input; dev->name = name; dev->vq = NULL; - dev->ready = NULL; /* Append to device list. Prepending to a single-linked list is * easier, but the user expects the devices to be arranged on the bus @@ -1418,7 +1398,7 @@ static bool service_io(struct device *dev) struct vblk_info *vblk = dev->priv; unsigned int head, out_num, in_num, wlen; int ret; - u8 *in; + struct virtio_blk_inhdr *in; struct virtio_blk_outhdr *out; struct iovec iov[dev->vq->vring.num]; off64_t off; @@ -1436,7 +1416,7 @@ static bool service_io(struct device *dev) head, out_num, in_num); out = convert(&iov[0], struct virtio_blk_outhdr); - in = convert(&iov[out_num+in_num-1], u8); + in = convert(&iov[out_num+in_num-1], struct virtio_blk_inhdr); off = out->sector * 512; /* The block device implements "barriers", where the Guest indicates @@ -1450,7 +1430,7 @@ static bool service_io(struct device *dev) * It'd be nice if we supported eject, for example, but we don't. */ if (out->type & VIRTIO_BLK_T_SCSI_CMD) { fprintf(stderr, "Scsi commands unsupported\n"); - *in = VIRTIO_BLK_S_UNSUPP; + in->status = VIRTIO_BLK_S_UNSUPP; wlen = sizeof(*in); } else if (out->type & VIRTIO_BLK_T_OUT) { /* Write */ @@ -1473,7 +1453,7 @@ static bool service_io(struct device *dev) errx(1, "Write past end %llu+%u", off, ret); } wlen = sizeof(*in); - *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR); + in->status = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR); } else { /* Read */ @@ -1486,10 +1466,10 @@ static bool service_io(struct device *dev) verbose("READ from sector %llu: %i\n", out->sector, ret); if (ret >= 0) { wlen = sizeof(*in) + ret; - *in = VIRTIO_BLK_S_OK; + in->status = VIRTIO_BLK_S_OK; } else { wlen = sizeof(*in); - *in = VIRTIO_BLK_S_IOERR; + in->status = VIRTIO_BLK_S_IOERR; } } diff --git a/trunk/arch/ia64/ia32/ia32_signal.c b/trunk/arch/ia64/ia32/ia32_signal.c index b763ca19ef17..256a7faeda07 100644 --- a/trunk/arch/ia64/ia32/ia32_signal.c +++ b/trunk/arch/ia64/ia32/ia32_signal.c @@ -463,7 +463,7 @@ sys32_sigsuspend (int history0, int history1, old_sigset_t mask) current->state = TASK_INTERRUPTIBLE; schedule(); - set_restore_sigmask(); + set_thread_flag(TIF_RESTORE_SIGMASK); return -ERESTARTNOHAND; } diff --git a/trunk/arch/ia64/kernel/acpi.c b/trunk/arch/ia64/kernel/acpi.c index 19709a079635..c7467f863c7a 100644 --- a/trunk/arch/ia64/kernel/acpi.c +++ b/trunk/arch/ia64/kernel/acpi.c @@ -966,7 +966,7 @@ acpi_map_iosapics (void) fs_initcall(acpi_map_iosapics); #endif /* CONFIG_ACPI_NUMA */ -int __ref acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base) +int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base) { int err; diff --git a/trunk/arch/ia64/kernel/irq.c b/trunk/arch/ia64/kernel/irq.c index 7fd18f54c056..6dee579f205f 100644 --- a/trunk/arch/ia64/kernel/irq.c +++ b/trunk/arch/ia64/kernel/irq.c @@ -183,10 +183,10 @@ void fixup_irqs(void) { unsigned int irq; extern void ia64_process_pending_intr(void); + extern void ia64_disable_timer(void); extern volatile int time_keeper_id; - /* Mask ITV to disable timer */ - ia64_set_itv(1 << 16); + ia64_disable_timer(); /* * Find a new timesync master diff --git a/trunk/arch/ia64/kernel/palinfo.c b/trunk/arch/ia64/kernel/palinfo.c index 4547a2092af9..396004e8cd14 100644 --- a/trunk/arch/ia64/kernel/palinfo.c +++ b/trunk/arch/ia64/kernel/palinfo.c @@ -1053,7 +1053,7 @@ static int __cpuinit palinfo_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block __refdata palinfo_cpu_notifier = +static struct notifier_block palinfo_cpu_notifier __cpuinitdata = { .notifier_call = palinfo_cpu_callback, .priority = 0, diff --git a/trunk/arch/ia64/kernel/perfmon.c b/trunk/arch/ia64/kernel/perfmon.c index c1ad27de2dd2..7fbb51e10bbe 100644 --- a/trunk/arch/ia64/kernel/perfmon.c +++ b/trunk/arch/ia64/kernel/perfmon.c @@ -867,7 +867,7 @@ pfm_rvfree(void *mem, unsigned long size) } static pfm_context_t * -pfm_context_alloc(int ctx_flags) +pfm_context_alloc(void) { pfm_context_t *ctx; @@ -878,46 +878,6 @@ pfm_context_alloc(int ctx_flags) ctx = kzalloc(sizeof(pfm_context_t), GFP_KERNEL); if (ctx) { DPRINT(("alloc ctx @%p\n", ctx)); - - /* - * init context protection lock - */ - spin_lock_init(&ctx->ctx_lock); - - /* - * context is unloaded - */ - ctx->ctx_state = PFM_CTX_UNLOADED; - - /* - * initialization of context's flags - */ - ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0; - ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; - ctx->ctx_fl_no_msg = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0; - /* - * will move to set properties - * ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0; - */ - - /* - * init restart semaphore to locked - */ - init_completion(&ctx->ctx_restart_done); - - /* - * activation is used in SMP only - */ - ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; - SET_LAST_CPU(ctx, -1); - - /* - * initialize notification message queue - */ - ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0; - init_waitqueue_head(&ctx->ctx_msgq_wait); - init_waitqueue_head(&ctx->ctx_zombieq); - } return ctx; } @@ -2205,21 +2165,28 @@ static struct dentry_operations pfmfs_dentry_operations = { }; -static struct file * -pfm_alloc_file(pfm_context_t *ctx) +static int +pfm_alloc_fd(struct file **cfile) { - struct file *file; - struct inode *inode; - struct dentry *dentry; + int fd, ret = 0; + struct file *file = NULL; + struct inode * inode; char name[32]; struct qstr this; + fd = get_unused_fd(); + if (fd < 0) return -ENFILE; + + ret = -ENFILE; + + file = get_empty_filp(); + if (!file) goto out; + /* * allocate a new inode */ inode = new_inode(pfmfs_mnt->mnt_sb); - if (!inode) - return ERR_PTR(-ENOMEM); + if (!inode) goto out; DPRINT(("new inode ino=%ld @%p\n", inode->i_ino, inode)); @@ -2232,28 +2199,59 @@ pfm_alloc_file(pfm_context_t *ctx) this.len = strlen(name); this.hash = inode->i_ino; + ret = -ENOMEM; + /* * allocate a new dcache entry */ - dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this); - if (!dentry) { - iput(inode); - return ERR_PTR(-ENOMEM); - } + file->f_path.dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this); + if (!file->f_path.dentry) goto out; - dentry->d_op = &pfmfs_dentry_operations; - d_add(dentry, inode); + file->f_path.dentry->d_op = &pfmfs_dentry_operations; - file = alloc_file(pfmfs_mnt, dentry, FMODE_READ, &pfm_file_ops); - if (!file) { - dput(dentry); - return ERR_PTR(-ENFILE); - } + d_add(file->f_path.dentry, inode); + file->f_path.mnt = mntget(pfmfs_mnt); + file->f_mapping = inode->i_mapping; + file->f_op = &pfm_file_ops; + file->f_mode = FMODE_READ; file->f_flags = O_RDONLY; - file->private_data = ctx; + file->f_pos = 0; + + /* + * may have to delay until context is attached? + */ + fd_install(fd, file); + + /* + * the file structure we will use + */ + *cfile = file; + + return fd; +out: + if (file) put_filp(file); + put_unused_fd(fd); + return ret; +} + +static void +pfm_free_fd(int fd, struct file *file) +{ + struct files_struct *files = current->files; + struct fdtable *fdt; - return file; + /* + * there ie no fd_uninstall(), so we do it here + */ + spin_lock(&files->file_lock); + fdt = files_fdtable(files); + rcu_assign_pointer(fdt->fd[fd], NULL); + spin_unlock(&files->file_lock); + + if (file) + put_filp(file); + put_unused_fd(fd); } static int @@ -2477,7 +2475,6 @@ pfm_setup_buffer_fmt(struct task_struct *task, struct file *filp, pfm_context_t /* link buffer format and context */ ctx->ctx_buf_fmt = fmt; - ctx->ctx_fl_is_sampling = 1; /* assume record() is defined */ /* * check if buffer format wants to use perfmon buffer allocation/mapping service @@ -2672,45 +2669,78 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg { pfarg_context_t *req = (pfarg_context_t *)arg; struct file *filp; - struct path path; int ctx_flags; - int fd; int ret; /* let's check the arguments first */ ret = pfarg_is_sane(current, req); - if (ret < 0) - return ret; + if (ret < 0) return ret; ctx_flags = req->ctx_flags; ret = -ENOMEM; - fd = get_unused_fd(); - if (fd < 0) - return fd; + ctx = pfm_context_alloc(); + if (!ctx) goto error; - ctx = pfm_context_alloc(ctx_flags); - if (!ctx) - goto error; + ret = pfm_alloc_fd(&filp); + if (ret < 0) goto error_file; - filp = pfm_alloc_file(ctx); - if (IS_ERR(filp)) { - ret = PTR_ERR(filp); - goto error_file; - } + req->ctx_fd = ctx->ctx_fd = ret; - req->ctx_fd = ctx->ctx_fd = fd; + /* + * attach context to file + */ + filp->private_data = ctx; /* * does the user want to sample? */ if (pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) { ret = pfm_setup_buffer_fmt(current, filp, ctx, ctx_flags, 0, req); - if (ret) - goto buffer_error; + if (ret) goto buffer_error; } + /* + * init context protection lock + */ + spin_lock_init(&ctx->ctx_lock); + + /* + * context is unloaded + */ + ctx->ctx_state = PFM_CTX_UNLOADED; + + /* + * initialization of context's flags + */ + ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0; + ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; + ctx->ctx_fl_is_sampling = ctx->ctx_buf_fmt ? 1 : 0; /* assume record() is defined */ + ctx->ctx_fl_no_msg = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0; + /* + * will move to set properties + * ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0; + */ + + /* + * init restart semaphore to locked + */ + init_completion(&ctx->ctx_restart_done); + + /* + * activation is used in SMP only + */ + ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; + SET_LAST_CPU(ctx, -1); + + /* + * initialize notification message queue + */ + ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0; + init_waitqueue_head(&ctx->ctx_msgq_wait); + init_waitqueue_head(&ctx->ctx_zombieq); + DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d no_msg=%d ctx_fd=%d \n", ctx, ctx_flags, @@ -2725,14 +2755,10 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg */ pfm_reset_pmu_state(ctx); - fd_install(fd, filp); - return 0; buffer_error: - path = filp->f_path; - put_filp(filp); - path_put(&path); + pfm_free_fd(ctx->ctx_fd, filp); if (ctx->ctx_buf_fmt) { pfm_buf_fmt_exit(ctx->ctx_buf_fmt, current, NULL, regs); @@ -2741,7 +2767,6 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg pfm_context_free(ctx); error: - put_unused_fd(fd); return ret; } diff --git a/trunk/arch/ia64/kernel/signal.c b/trunk/arch/ia64/kernel/signal.c index 19c5a78636fc..5740296c35af 100644 --- a/trunk/arch/ia64/kernel/signal.c +++ b/trunk/arch/ia64/kernel/signal.c @@ -464,7 +464,7 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall) if (!user_mode(&scr->pt)) return; - if (current_thread_info()->status & TS_RESTORE_SIGMASK) + if (test_thread_flag(TIF_RESTORE_SIGMASK)) oldset = ¤t->saved_sigmask; else oldset = ¤t->blocked; @@ -530,13 +530,12 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall) * continue to iterate in this loop so we can deliver the SIGSEGV... */ if (handle_signal(signr, &ka, &info, oldset, scr)) { - /* - * A signal was successfully delivered; the saved + /* a signal was successfully delivered; the saved * sigmask will have been stored in the signal frame, * and will be restored by sigreturn, so we can simply - * clear the TS_RESTORE_SIGMASK flag. - */ - current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + * clear the TIF_RESTORE_SIGMASK flag */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); return; } } @@ -567,8 +566,8 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall) /* if there's no signal to deliver, we just put the saved sigmask * back */ - if (current_thread_info()->status & TS_RESTORE_SIGMASK) { - current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); } } diff --git a/trunk/arch/ia64/kernel/smp.c b/trunk/arch/ia64/kernel/smp.c index 983296f1c813..9a9d4c489330 100644 --- a/trunk/arch/ia64/kernel/smp.c +++ b/trunk/arch/ia64/kernel/smp.c @@ -98,33 +98,8 @@ unlock_ipi_calllock(void) spin_unlock_irq(&call_lock); } -static inline void -handle_call_data(void) -{ - struct call_data_struct *data; - void (*func)(void *info); - void *info; - int wait; - - /* release the 'pointer lock' */ - data = (struct call_data_struct *)call_data; - func = data->func; - info = data->info; - wait = data->wait; - - mb(); - atomic_inc(&data->started); - /* At this point the structure may be gone unless wait is true. */ - (*func)(info); - - /* Notify the sending CPU that the task is done. */ - mb(); - if (wait) - atomic_inc(&data->finished); -} - static void -stop_this_cpu(void) +stop_this_cpu (void) { /* * Remove this CPU: @@ -163,21 +138,44 @@ handle_IPI (int irq, void *dev_id) ops &= ~(1 << which); switch (which) { - case IPI_CALL_FUNC: - handle_call_data(); - break; - - case IPI_CPU_STOP: + case IPI_CALL_FUNC: + { + struct call_data_struct *data; + void (*func)(void *info); + void *info; + int wait; + + /* release the 'pointer lock' */ + data = (struct call_data_struct *) call_data; + func = data->func; + info = data->info; + wait = data->wait; + + mb(); + atomic_inc(&data->started); + /* + * At this point the structure may be gone unless + * wait is true. + */ + (*func)(info); + + /* Notify the sending CPU that the task is done. */ + mb(); + if (wait) + atomic_inc(&data->finished); + } + break; + + case IPI_CPU_STOP: stop_this_cpu(); break; #ifdef CONFIG_KEXEC - case IPI_KDUMP_CPU_STOP: + case IPI_KDUMP_CPU_STOP: unw_init_running(kdump_cpu_freeze, NULL); break; #endif - default: - printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", - this_cpu, which); + default: + printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); break; } } while (ops); diff --git a/trunk/arch/ia64/kernel/time.c b/trunk/arch/ia64/kernel/time.c index 8c73643f2d66..48e15a51782f 100644 --- a/trunk/arch/ia64/kernel/time.c +++ b/trunk/arch/ia64/kernel/time.c @@ -379,6 +379,11 @@ static struct irqaction timer_irqaction = { .name = "timer" }; +void __devinit ia64_disable_timer(void) +{ + ia64_set_itv(1 << 16); +} + void __init time_init (void) { diff --git a/trunk/arch/ia64/kernel/topology.c b/trunk/arch/ia64/kernel/topology.c index 26228e2d01ae..abb17a613b17 100644 --- a/trunk/arch/ia64/kernel/topology.c +++ b/trunk/arch/ia64/kernel/topology.c @@ -36,11 +36,9 @@ void arch_fix_phys_package_id(int num, u32 slot) } EXPORT_SYMBOL_GPL(arch_fix_phys_package_id); - -#ifdef CONFIG_HOTPLUG_CPU -int __ref arch_register_cpu(int num) +int arch_register_cpu(int num) { -#ifdef CONFIG_ACPI +#if defined (CONFIG_ACPI) && defined (CONFIG_HOTPLUG_CPU) /* * If CPEI can be re-targetted or if this is not * CPEI target, then it is hotpluggable @@ -49,21 +47,19 @@ int __ref arch_register_cpu(int num) sysfs_cpus[num].cpu.hotpluggable = 1; map_cpu_to_node(num, node_cpuid[num].nid); #endif + return register_cpu(&sysfs_cpus[num].cpu, num); } -EXPORT_SYMBOL(arch_register_cpu); + +#ifdef CONFIG_HOTPLUG_CPU void arch_unregister_cpu(int num) { unregister_cpu(&sysfs_cpus[num].cpu); unmap_cpu_from_node(num, cpu_to_node(num)); } +EXPORT_SYMBOL(arch_register_cpu); EXPORT_SYMBOL(arch_unregister_cpu); -#else -static int __init arch_register_cpu(int num) -{ - return register_cpu(&sysfs_cpus[num].cpu, num); -} #endif /*CONFIG_HOTPLUG_CPU*/ diff --git a/trunk/arch/m32r/Makefile b/trunk/arch/m32r/Makefile index 469766b24e22..4072a07ebf8e 100644 --- a/trunk/arch/m32r/Makefile +++ b/trunk/arch/m32r/Makefile @@ -5,8 +5,6 @@ # architecture-specific flags and dependencies. # -KBUILD_DEFCONFIG := m32700ut.smp_defconfig - LDFLAGS := OBJCOPYFLAGS := -O binary -R .note -R .comment -S LDFLAGS_vmlinux := diff --git a/trunk/arch/m32r/defconfig b/trunk/arch/m32r/defconfig new file mode 100644 index 000000000000..af3b98179113 --- /dev/null +++ b/trunk/arch/m32r/defconfig @@ -0,0 +1,863 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc1 +# Wed Aug 1 17:22:35 2007 +# +CONFIG_M32R=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_ZONE_DMA=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_NO_IOPORT=y +CONFIG_NO_DMA=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=15 +# CONFIG_CPUSETS is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +# CONFIG_FUTEX is not set +CONFIG_ANON_INODES=y +# CONFIG_EPOLL is not set +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# +# Processor type and features +# +# CONFIG_PLAT_MAPPI is not set +# CONFIG_PLAT_USRV is not set +CONFIG_PLAT_M32700UT=y +# CONFIG_PLAT_OPSPUT is not set +# CONFIG_PLAT_OAKS32R is not set +# CONFIG_PLAT_MAPPI2 is not set +# CONFIG_PLAT_MAPPI3 is not set +# CONFIG_PLAT_M32104UT is not set +CONFIG_CHIP_M32700=y +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_M32104 is not set +# CONFIG_CHIP_VDEC2 is not set +# CONFIG_CHIP_OPSP is not set +CONFIG_MMU=y +CONFIG_TLB_ENTRIES=32 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=50000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x01000000 +CONFIG_NOHIGHMEM=y +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_DISCONTIGMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_IRAM_START=0x00f00000 +CONFIG_IRAM_SIZE=0x00080000 +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_PREEMPT=y +CONFIG_SMP=y +# CONFIG_CHIP_M32700_TS1 is not set +CONFIG_NR_CPUS=2 +CONFIG_NODES_SHIFT=1 + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_ISA is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=y +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_CMDLINE_PARTS is not set + +# +# User Modules And Translation Layers +# +# CONFIG_MTD_CHAR is not set +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +CONFIG_MTD_CFI_ADV_OPTIONS=y +# CONFIG_MTD_CFI_NOSWAP is not set +CONFIG_MTD_CFI_BE_BYTE_SWAP=y +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +# CONFIG_MTD_CFI_I2 is not set +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=m +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=m +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +CONFIG_ATA_OVER_ETH=m +CONFIG_MISC_DEVICES=y +# CONFIG_EEPROM_93CX6 is not set +CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IDE_PROC_FS=y + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_IDEPCI_PCIBUS_ORDER is not set +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=m +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_SMC91X=y +# CONFIG_NE2000 is not set +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_M32R_SIO=y +CONFIG_SERIAL_M32R_SIO_CONSOLE=y +CONFIG_SERIAL_M32R_PLDSIO=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_IPMI_HANDLER is not set +# CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y +# CONFIG_RTC is not set +CONFIG_DS1302=y +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +# CONFIG_VIDEO_CPIA is not set +CONFIG_VIDEO_M32R_AR=m +CONFIG_VIDEO_M32R_AR_M64278=m +CONFIG_RADIO_ADAPTERS=y +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +# CONFIG_FB_DDC is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_SYS_FOPS is not set +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +CONFIG_FB_S1D13XXX=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y +CONFIG_LOGO_M32R_CLUT224=y + +# +# Sound +# +# CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set +CONFIG_USB_SUPPORT=y +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set +CONFIG_MMC=y +CONFIG_MMC_DEBUG=y +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BOUNCE=y + +# +# MMC/SD Host Controller Drivers +# +# CONFIG_NEW_LEDS is not set + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +CONFIG_JBD_DEBUG=y +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_REISERFS_FS_XATTR is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Profiling support +# +CONFIG_PROFILING=y +CONFIG_OPROFILE=y + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_FRAME_POINTER is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_HAS_IOMEM=y diff --git a/trunk/arch/m32r/kernel/vmlinux.lds.S b/trunk/arch/m32r/kernel/vmlinux.lds.S index 15a6f36c06db..41b07854fcc6 100644 --- a/trunk/arch/m32r/kernel/vmlinux.lds.S +++ b/trunk/arch/m32r/kernel/vmlinux.lds.S @@ -60,6 +60,9 @@ SECTIONS . = ALIGN(4096); __nosave_end = .; + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + . = ALIGN(32); .data.cacheline_aligned : { *(.data.cacheline_aligned) } diff --git a/trunk/drivers/block/virtio_blk.c b/trunk/drivers/block/virtio_blk.c index 84e064ffee52..0cfbe8c594a5 100644 --- a/trunk/drivers/block/virtio_blk.c +++ b/trunk/drivers/block/virtio_blk.c @@ -35,7 +35,7 @@ struct virtblk_req struct list_head list; struct request *req; struct virtio_blk_outhdr out_hdr; - u8 status; + struct virtio_blk_inhdr in_hdr; }; static void blk_done(struct virtqueue *vq) @@ -48,7 +48,7 @@ static void blk_done(struct virtqueue *vq) spin_lock_irqsave(&vblk->lock, flags); while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) { int uptodate; - switch (vbr->status) { + switch (vbr->in_hdr.status) { case VIRTIO_BLK_S_OK: uptodate = 1; break; @@ -101,7 +101,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, sg_init_table(vblk->sg, VIRTIO_MAX_SG); sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr)); num = blk_rq_map_sg(q, vbr->req, vblk->sg+1); - sg_set_buf(&vblk->sg[num+1], &vbr->status, sizeof(vbr->status)); + sg_set_buf(&vblk->sg[num+1], &vbr->in_hdr, sizeof(vbr->in_hdr)); if (rq_data_dir(vbr->req) == WRITE) { vbr->out_hdr.type |= VIRTIO_BLK_T_OUT; @@ -157,25 +157,10 @@ static int virtblk_ioctl(struct inode *inode, struct file *filp, /* We provide getgeo only to please some old bootloader/partitioning tools */ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo) { - struct virtio_blk *vblk = bd->bd_disk->private_data; - struct virtio_blk_geometry vgeo; - int err; - - /* see if the host passed in geometry config */ - err = virtio_config_val(vblk->vdev, VIRTIO_BLK_F_GEOMETRY, - offsetof(struct virtio_blk_config, geometry), - &vgeo); - - if (!err) { - geo->heads = vgeo.heads; - geo->sectors = vgeo.sectors; - geo->cylinders = vgeo.cylinders; - } else { - /* some standard values, similar to sd */ - geo->heads = 1 << 6; - geo->sectors = 1 << 5; - geo->cylinders = get_capacity(bd->bd_disk) >> 11; - } + /* some standard values, similar to sd */ + geo->heads = 1 << 6; + geo->sectors = 1 << 5; + geo->cylinders = get_capacity(bd->bd_disk) >> 11; return 0; } @@ -257,12 +242,12 @@ static int virtblk_probe(struct virtio_device *vdev) index++; /* If barriers are supported, tell block layer that queue is ordered */ - if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER)) + if (vdev->config->feature(vdev, VIRTIO_BLK_F_BARRIER)) blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL); /* Host must always specify the capacity. */ - vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity), - &cap, sizeof(cap)); + __virtio_config_val(vdev, offsetof(struct virtio_blk_config, capacity), + &cap); /* If capacity is too big, truncate with warning. */ if ((sector_t)cap != cap) { @@ -304,6 +289,7 @@ static int virtblk_probe(struct virtio_device *vdev) static void virtblk_remove(struct virtio_device *vdev) { struct virtio_blk *vblk = vdev->priv; + int major = vblk->disk->major; /* Nothing should be pending. */ BUG_ON(!list_empty(&vblk->reqs)); @@ -313,6 +299,7 @@ static void virtblk_remove(struct virtio_device *vdev) blk_cleanup_queue(vblk->disk->queue); put_disk(vblk->disk); + unregister_blkdev(major, "virtblk"); mempool_destroy(vblk->pool); vdev->config->del_vq(vblk->vq); kfree(vblk); @@ -323,14 +310,7 @@ static struct virtio_device_id id_table[] = { { 0 }, }; -static unsigned int features[] = { - VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, - VIRTIO_BLK_F_GEOMETRY, -}; - static struct virtio_driver virtio_blk = { - .feature_table = features, - .feature_table_size = ARRAY_SIZE(features), .driver.name = KBUILD_MODNAME, .driver.owner = THIS_MODULE, .id_table = id_table, diff --git a/trunk/drivers/lguest/lguest_device.c b/trunk/drivers/lguest/lguest_device.c index 8080249957af..2bc9bf7e88e5 100644 --- a/trunk/drivers/lguest/lguest_device.c +++ b/trunk/drivers/lguest/lguest_device.c @@ -85,34 +85,27 @@ static unsigned desc_size(const struct lguest_device_desc *desc) + desc->config_len; } -/* This gets the device's feature bits. */ -static u32 lg_get_features(struct virtio_device *vdev) +/* This tests (and acknowleges) a feature bit. */ +static bool lg_feature(struct virtio_device *vdev, unsigned fbit) { - unsigned int i; - u32 features = 0; struct lguest_device_desc *desc = to_lgdev(vdev)->desc; - u8 *in_features = lg_features(desc); - - /* We do this the slow but generic way. */ - for (i = 0; i < min(desc->feature_len * 8, 32); i++) - if (in_features[i / 8] & (1 << (i % 8))) - features |= (1 << i); - - return features; -} - -static void lg_set_features(struct virtio_device *vdev, u32 features) -{ - unsigned int i; - struct lguest_device_desc *desc = to_lgdev(vdev)->desc; - /* Second half of bitmap is features we accept. */ - u8 *out_features = lg_features(desc) + desc->feature_len; - - memset(out_features, 0, desc->feature_len); - for (i = 0; i < min(desc->feature_len * 8, 32); i++) { - if (features & (1 << i)) - out_features[i / 8] |= (1 << (i % 8)); - } + u8 *features; + + /* Obviously if they ask for a feature off the end of our feature + * bitmap, it's not set. */ + if (fbit / 8 > desc->feature_len) + return false; + + /* The feature bitmap comes after the virtqueues. */ + features = lg_features(desc); + if (!(features[fbit / 8] & (1 << (fbit % 8)))) + return false; + + /* We set the matching bit in the other half of the bitmap to tell the + * Host we want to use this feature. We don't use this yet, but we + * could in future. */ + features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8)); + return true; } /* Once they've found a field, getting a copy of it is easy. */ @@ -144,26 +137,20 @@ static u8 lg_get_status(struct virtio_device *vdev) return to_lgdev(vdev)->desc->status; } -/* To notify on status updates, we (ab)use the NOTIFY hypercall, with the - * descriptor address of the device. A zero status means "reset". */ -static void set_status(struct virtio_device *vdev, u8 status) -{ - unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices; - - /* We set the status. */ - to_lgdev(vdev)->desc->status = status; - hcall(LHCALL_NOTIFY, (max_pfn<desc->status = status; } +/* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor + * address of the device. The Host will zero the status and all the + * features. */ static void lg_reset(struct virtio_device *vdev) { - set_status(vdev, 0); + unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices; + + hcall(LHCALL_NOTIFY, (max_pfn<= ARRAY_SIZE(cpu->lg->cpus)) + if (id >= NR_CPUS) return -EINVAL; /* Set up this CPU's id, and pointer back to the lguest struct. */ @@ -251,6 +251,8 @@ static ssize_t write(struct file *file, const char __user *in, if (!lg || (cpu_id >= lg->nr_cpus)) return -EINVAL; cpu = &lg->cpus[cpu_id]; + if (!cpu) + return -EINVAL; /* Once the Guest is dead, you can only read() why it died. */ if (lg->dead) diff --git a/trunk/drivers/net/virtio_net.c b/trunk/drivers/net/virtio_net.c index f926b5ab3d09..555b70c8b863 100644 --- a/trunk/drivers/net/virtio_net.c +++ b/trunk/drivers/net/virtio_net.c @@ -41,9 +41,6 @@ struct virtnet_info struct net_device *dev; struct napi_struct napi; - /* The skb we couldn't send because buffers were full. */ - struct sk_buff *last_xmit_skb; - /* Number of input buffers, and max we've ever had. */ unsigned int num, max; @@ -145,10 +142,10 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, static void try_fill_recv(struct virtnet_info *vi) { struct sk_buff *skb; - struct scatterlist sg[2+MAX_SKB_FRAGS]; + struct scatterlist sg[1+MAX_SKB_FRAGS]; int num, err; - sg_init_table(sg, 2+MAX_SKB_FRAGS); + sg_init_table(sg, 1+MAX_SKB_FRAGS); for (;;) { skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN); if (unlikely(!skb)) @@ -224,22 +221,23 @@ static void free_old_xmit_skbs(struct virtnet_info *vi) while ((skb = vi->svq->vq_ops->get_buf(vi->svq, &len)) != NULL) { pr_debug("Sent skb %p\n", skb); __skb_unlink(skb, &vi->send); - vi->dev->stats.tx_bytes += skb->len; + vi->dev->stats.tx_bytes += len; vi->dev->stats.tx_packets++; kfree_skb(skb); } } -static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) +static int start_xmit(struct sk_buff *skb, struct net_device *dev) { - int num; - struct scatterlist sg[2+MAX_SKB_FRAGS]; + struct virtnet_info *vi = netdev_priv(dev); + int num, err; + struct scatterlist sg[1+MAX_SKB_FRAGS]; struct virtio_net_hdr *hdr; const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; - sg_init_table(sg, 2+MAX_SKB_FRAGS); + sg_init_table(sg, 1+MAX_SKB_FRAGS); - pr_debug("%s: xmit %p " MAC_FMT "\n", vi->dev->name, skb, + pr_debug("%s: xmit %p " MAC_FMT "\n", dev->name, skb, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5]); @@ -274,51 +272,30 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) vnet_hdr_to_sg(sg, skb); num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; - - return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); -} - -static int start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct virtnet_info *vi = netdev_priv(dev); + __skb_queue_head(&vi->send, skb); again: /* Free up any pending old buffers before queueing new ones. */ free_old_xmit_skbs(vi); - - /* If we has a buffer left over from last time, send it now. */ - if (vi->last_xmit_skb) { - if (xmit_skb(vi, vi->last_xmit_skb) != 0) { - /* Drop this skb: we only queue one. */ - vi->dev->stats.tx_dropped++; - kfree_skb(skb); - goto stop_queue; + err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); + if (err) { + pr_debug("%s: virtio not prepared to send\n", dev->name); + netif_stop_queue(dev); + + /* Activate callback for using skbs: if this returns false it + * means some were used in the meantime. */ + if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) { + vi->svq->vq_ops->disable_cb(vi->svq); + netif_start_queue(dev); + goto again; } - vi->last_xmit_skb = NULL; - } + __skb_unlink(skb, &vi->send); - /* Put new one in send queue and do transmit */ - __skb_queue_head(&vi->send, skb); - if (xmit_skb(vi, skb) != 0) { - vi->last_xmit_skb = skb; - goto stop_queue; + return NETDEV_TX_BUSY; } -done: vi->svq->vq_ops->kick(vi->svq); - return NETDEV_TX_OK; - -stop_queue: - pr_debug("%s: virtio not prepared to send\n", dev->name); - netif_stop_queue(dev); - - /* Activate callback for using skbs: if this returns false it - * means some were used in the meantime. */ - if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) { - vi->svq->vq_ops->disable_cb(vi->svq); - netif_start_queue(dev); - goto again; - } - goto done; + + return 0; } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -378,26 +355,17 @@ static int virtnet_probe(struct virtio_device *vdev) SET_NETDEV_DEV(dev, &vdev->dev); /* Do we support "hardware" checksums? */ - if (csum && virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) { + if (csum && vdev->config->feature(vdev, VIRTIO_NET_F_CSUM)) { /* This opens up the world of extra features. */ dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) { + if (gso && vdev->config->feature(vdev, VIRTIO_NET_F_GSO)) { dev->features |= NETIF_F_TSO | NETIF_F_UFO | NETIF_F_TSO_ECN | NETIF_F_TSO6; } - /* Individual feature bits: what can host handle? */ - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4)) - dev->features |= NETIF_F_TSO; - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6)) - dev->features |= NETIF_F_TSO6; - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN)) - dev->features |= NETIF_F_TSO_ECN; - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO)) - dev->features |= NETIF_F_UFO; } /* Configuration may specify what MAC to use. Otherwise random. */ - if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) { + if (vdev->config->feature(vdev, VIRTIO_NET_F_MAC)) { vdev->config->get(vdev, offsetof(struct virtio_net_config, mac), dev->dev_addr, dev->addr_len); @@ -486,15 +454,7 @@ static struct virtio_device_id id_table[] = { { 0 }, }; -static unsigned int features[] = { - VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC, - VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, - VIRTIO_NET_F_HOST_ECN, -}; - static struct virtio_driver virtio_net = { - .feature_table = features, - .feature_table_size = ARRAY_SIZE(features), .driver.name = KBUILD_MODNAME, .driver.owner = THIS_MODULE, .id_table = id_table, diff --git a/trunk/drivers/usb/host/Kconfig b/trunk/drivers/usb/host/Kconfig index 0b87480dd713..acac56852b49 100644 --- a/trunk/drivers/usb/host/Kconfig +++ b/trunk/drivers/usb/host/Kconfig @@ -95,6 +95,32 @@ config USB_ISP116X_HCD To compile this driver as a module, choose M here: the module will be called isp116x-hcd. +config USB_ISP1760_HCD + tristate "ISP 1760 HCD support" + depends on USB && EXPERIMENTAL + ---help--- + The ISP1760 chip is a USB 2.0 host controller. + + This driver does not support isochronous transfers or OTG. + + To compile this driver as a module, choose M here: the + module will be called isp1760-hcd. + +config USB_ISP1760_PCI + bool "Support for the PCI bus" + depends on USB_ISP1760_HCD && PCI + ---help--- + Enables support for the device present on the PCI bus. + This should only be required if you happen to have the eval kit from + NXP and you are going to test it. + +config USB_ISP1760_OF + bool "Support for the OF platform bus" + depends on USB_ISP1760_HCD && OF + ---help--- + Enables support for the device present on the PowerPC + OpenFirmware platform bus. + config USB_OHCI_HCD tristate "OHCI HCD support" depends on USB && USB_ARCH_HAS_OHCI diff --git a/trunk/drivers/usb/host/Makefile b/trunk/drivers/usb/host/Makefile index bb8e9d44f371..f1edda2dcfde 100644 --- a/trunk/drivers/usb/host/Makefile +++ b/trunk/drivers/usb/host/Makefile @@ -6,6 +6,8 @@ ifeq ($(CONFIG_USB_DEBUG),y) EXTRA_CFLAGS += -DDEBUG endif +isp1760-objs := isp1760-hcd.o isp1760-if.o + obj-$(CONFIG_PCI) += pci-quirks.o obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o @@ -16,4 +18,4 @@ obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o - +obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o diff --git a/trunk/drivers/usb/host/isp1760-hcd.c b/trunk/drivers/usb/host/isp1760-hcd.c new file mode 100644 index 000000000000..4ba96c1e060c --- /dev/null +++ b/trunk/drivers/usb/host/isp1760-hcd.c @@ -0,0 +1,2231 @@ +/* + * Driver for the NXP ISP1760 chip + * + * However, the code might contain some bugs. What doesn't work for sure is: + * - ISO + * - OTG + e The interrupt line is configured as active low, level. + * + * (c) 2007 Sebastian Siewior + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../core/hcd.h" +#include "isp1760-hcd.h" + +static struct kmem_cache *qtd_cachep; +static struct kmem_cache *qh_cachep; + +struct isp1760_hcd { + u32 hcs_params; + spinlock_t lock; + struct inter_packet_info atl_ints[32]; + struct inter_packet_info int_ints[32]; + struct memory_chunk memory_pool[BLOCKS]; + + /* periodic schedule support */ +#define DEFAULT_I_TDPS 1024 + unsigned periodic_size; + unsigned i_thresh; + unsigned long reset_done; + unsigned long next_statechange; +}; + +static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd) +{ + return (struct isp1760_hcd *) (hcd->hcd_priv); +} +static inline struct usb_hcd *priv_to_hcd(struct isp1760_hcd *priv) +{ + return container_of((void *) priv, struct usb_hcd, hcd_priv); +} + +/* Section 2.2 Host Controller Capability Registers */ +#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */ +#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */ +#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */ +#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */ +#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */ +#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */ +#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */ + +/* Section 2.3 Host Controller Operational Registers */ +#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */ +#define CMD_RESET (1<<1) /* reset HC not bus */ +#define CMD_RUN (1<<0) /* start/stop HC */ +#define STS_PCD (1<<2) /* port change detect */ +#define FLAG_CF (1<<0) /* true: we'll support "high speed" */ + +#define PORT_OWNER (1<<13) /* true: companion hc owns this port */ +#define PORT_POWER (1<<12) /* true: has power (see PPC) */ +#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */ +#define PORT_RESET (1<<8) /* reset port */ +#define PORT_SUSPEND (1<<7) /* suspend port */ +#define PORT_RESUME (1<<6) /* resume it */ +#define PORT_PE (1<<2) /* port enable */ +#define PORT_CSC (1<<1) /* connect status change */ +#define PORT_CONNECT (1<<0) /* device connected */ +#define PORT_RWC_BITS (PORT_CSC) + +struct isp1760_qtd { + struct isp1760_qtd *hw_next; + u8 packet_type; + u8 toggle; + + void *data_buffer; + /* the rest is HCD-private */ + struct list_head qtd_list; + struct urb *urb; + size_t length; + + /* isp special*/ + u32 status; +#define URB_COMPLETE_NOTIFY (1 << 0) +#define URB_ENQUEUED (1 << 1) +#define URB_TYPE_ATL (1 << 2) +#define URB_TYPE_INT (1 << 3) +}; + +struct isp1760_qh { + /* first part defined by EHCI spec */ + struct list_head qtd_list; + struct isp1760_hcd *priv; + + /* periodic schedule info */ + unsigned short period; /* polling interval */ + struct usb_device *dev; + + u32 toggle; + u32 ping; +}; + +#define ehci_port_speed(priv, portsc) (1 << USB_PORT_FEAT_HIGHSPEED) + +static unsigned int isp1760_readl(__u32 __iomem *regs) +{ + return readl(regs); +} + +static void isp1760_writel(const unsigned int val, __u32 __iomem *regs) +{ + writel(val, regs); +} + +/* + * The next two copy via MMIO data to/from the device. memcpy_{to|from}io() + * doesn't quite work because some people have to enforce 32-bit access + */ +static void priv_read_copy(struct isp1760_hcd *priv, u32 *src, + __u32 __iomem *dst, u32 offset, u32 len) +{ + struct usb_hcd *hcd = priv_to_hcd(priv); + u32 val; + u8 *buff8; + + if (!src) { + printk(KERN_ERR "ERROR: buffer: %p len: %d\n", src, len); + return; + } + isp1760_writel(offset, hcd->regs + HC_MEMORY_REG); + /* XXX + * 90nsec delay, the spec says something how this could be avoided. + */ + mdelay(1); + + while (len >= 4) { + *src = __raw_readl(dst); + len -= 4; + src++; + dst++; + } + + if (!len) + return; + + /* in case we have 3, 2 or 1 by left. The dst buffer may not be fully + * allocated. + */ + val = isp1760_readl(dst); + + buff8 = (u8 *)src; + while (len) { + + *buff8 = val; + val >>= 8; + len--; + buff8++; + } +} + +static void priv_write_copy(const struct isp1760_hcd *priv, const u32 *src, + __u32 __iomem *dst, u32 len) +{ + while (len >= 4) { + __raw_writel(*src, dst); + len -= 4; + src++; + dst++; + } + + if (!len) + return; + /* in case we have 3, 2 or 1 by left. The buffer is allocated and the + * extra bytes should not be read by the HW + */ + + __raw_writel(*src, dst); +} + +/* memory management of the 60kb on the chip from 0x1000 to 0xffff */ +static void init_memory(struct isp1760_hcd *priv) +{ + int i; + u32 payload; + + payload = 0x1000; + for (i = 0; i < BLOCK_1_NUM; i++) { + priv->memory_pool[i].start = payload; + priv->memory_pool[i].size = BLOCK_1_SIZE; + priv->memory_pool[i].free = 1; + payload += priv->memory_pool[i].size; + } + + + for (i = BLOCK_1_NUM; i < BLOCK_1_NUM + BLOCK_2_NUM; i++) { + priv->memory_pool[i].start = payload; + priv->memory_pool[i].size = BLOCK_2_SIZE; + priv->memory_pool[i].free = 1; + payload += priv->memory_pool[i].size; + } + + + for (i = BLOCK_1_NUM + BLOCK_2_NUM; i < BLOCKS; i++) { + priv->memory_pool[i].start = payload; + priv->memory_pool[i].size = BLOCK_3_SIZE; + priv->memory_pool[i].free = 1; + payload += priv->memory_pool[i].size; + } + + BUG_ON(payload - priv->memory_pool[i - 1].size > PAYLOAD_SIZE); +} + +static u32 alloc_mem(struct isp1760_hcd *priv, u32 size) +{ + int i; + + if (!size) + return ISP1760_NULL_POINTER; + + for (i = 0; i < BLOCKS; i++) { + if (priv->memory_pool[i].size >= size && + priv->memory_pool[i].free) { + + priv->memory_pool[i].free = 0; + return priv->memory_pool[i].start; + } + } + + printk(KERN_ERR "ISP1760 MEM: can not allocate %d bytes of memory\n", + size); + printk(KERN_ERR "Current memory map:\n"); + for (i = 0; i < BLOCKS; i++) { + printk(KERN_ERR "Pool %2d size %4d status: %d\n", + i, priv->memory_pool[i].size, + priv->memory_pool[i].free); + } + /* XXX maybe -ENOMEM could be possible */ + BUG(); + return 0; +} + +static void free_mem(struct isp1760_hcd *priv, u32 mem) +{ + int i; + + if (mem == ISP1760_NULL_POINTER) + return; + + for (i = 0; i < BLOCKS; i++) { + if (priv->memory_pool[i].start == mem) { + + BUG_ON(priv->memory_pool[i].free); + + priv->memory_pool[i].free = 1; + return ; + } + } + + printk(KERN_ERR "Trying to free not-here-allocated memory :%08x\n", + mem); + BUG(); +} + +static void isp1760_init_regs(struct usb_hcd *hcd) +{ + isp1760_writel(0, hcd->regs + HC_BUFFER_STATUS_REG); + isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs + + HC_ATL_PTD_SKIPMAP_REG); + isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs + + HC_INT_PTD_SKIPMAP_REG); + isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs + + HC_ISO_PTD_SKIPMAP_REG); + + isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs + + HC_ATL_PTD_DONEMAP_REG); + isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs + + HC_INT_PTD_DONEMAP_REG); + isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs + + HC_ISO_PTD_DONEMAP_REG); +} + +static int handshake(struct isp1760_hcd *priv, void __iomem *ptr, + u32 mask, u32 done, int usec) +{ + u32 result; + + do { + result = isp1760_readl(ptr); + if (result == ~0) + return -ENODEV; + result &= mask; + if (result == done) + return 0; + udelay(1); + usec--; + } while (usec > 0); + return -ETIMEDOUT; +} + +/* reset a non-running (STS_HALT == 1) controller */ +static int ehci_reset(struct isp1760_hcd *priv) +{ + int retval; + struct usb_hcd *hcd = priv_to_hcd(priv); + u32 command = isp1760_readl(hcd->regs + HC_USBCMD); + + command |= CMD_RESET; + isp1760_writel(command, hcd->regs + HC_USBCMD); + hcd->state = HC_STATE_HALT; + priv->next_statechange = jiffies; + retval = handshake(priv, hcd->regs + HC_USBCMD, + CMD_RESET, 0, 250 * 1000); + return retval; +} + +static void qh_destroy(struct isp1760_qh *qh) +{ + BUG_ON(!list_empty(&qh->qtd_list)); + kmem_cache_free(qh_cachep, qh); +} + +static struct isp1760_qh *isp1760_qh_alloc(struct isp1760_hcd *priv, + gfp_t flags) +{ + struct isp1760_qh *qh; + + qh = kmem_cache_zalloc(qh_cachep, flags); + if (!qh) + return qh; + + INIT_LIST_HEAD(&qh->qtd_list); + qh->priv = priv; + return qh; +} + +/* magic numbers that can affect system performance */ +#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ +#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */ +#define EHCI_TUNE_RL_TT 0 +#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ +#define EHCI_TUNE_MULT_TT 1 +#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ + +/* one-time init, only for memory state */ +static int priv_init(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 hcc_params; + + spin_lock_init(&priv->lock); + + /* + * hw default: 1K periodic list heads, one per frame. + * periodic_size can shrink by USBCMD update if hcc_params allows. + */ + priv->periodic_size = DEFAULT_I_TDPS; + + /* controllers may cache some of the periodic schedule ... */ + hcc_params = isp1760_readl(hcd->regs + HC_HCCPARAMS); + /* full frame cache */ + if (HCC_ISOC_CACHE(hcc_params)) + priv->i_thresh = 8; + else /* N microframes cached */ + priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); + + return 0; +} + +static int isp1760_hc_setup(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + int result; + u32 scratch; + + isp1760_writel(0xdeadbabe, hcd->regs + HC_SCRATCH_REG); + scratch = isp1760_readl(hcd->regs + HC_SCRATCH_REG); + if (scratch != 0xdeadbabe) { + printk(KERN_ERR "ISP1760: Scratch test failed.\n"); + return -ENODEV; + } + + /* pre reset */ + isp1760_init_regs(hcd); + + /* reset */ + isp1760_writel(SW_RESET_RESET_ALL, hcd->regs + HC_RESET_REG); + mdelay(100); + + isp1760_writel(SW_RESET_RESET_HC, hcd->regs + HC_RESET_REG); + mdelay(100); + + result = ehci_reset(priv); + if (result) + return result; + + /* Step 11 passed */ + + isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_REG); + isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_ENABLE); + + /* ATL reset */ + scratch = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL); + isp1760_writel(scratch | ALL_ATX_RESET, hcd->regs + HC_HW_MODE_CTRL); + mdelay(10); + isp1760_writel(scratch, hcd->regs + HC_HW_MODE_CTRL); + + isp1760_writel(PORT1_POWER | PORT1_INIT2, hcd->regs + HC_PORT1_CTRL); + mdelay(10); + + priv->hcs_params = isp1760_readl(hcd->regs + HC_HCSPARAMS); + + return priv_init(hcd); +} + +static void isp1760_init_maps(struct usb_hcd *hcd) +{ + /*set last maps, for iso its only 1, else 32 tds bitmap*/ + isp1760_writel(0x80000000, hcd->regs + HC_ATL_PTD_LASTPTD_REG); + isp1760_writel(0x80000000, hcd->regs + HC_INT_PTD_LASTPTD_REG); + isp1760_writel(0x00000001, hcd->regs + HC_ISO_PTD_LASTPTD_REG); +} + +static void isp1760_enable_interrupts(struct usb_hcd *hcd) +{ + isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_AND_REG); + isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_OR_REG); + isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_AND_REG); + isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_OR_REG); + isp1760_writel(0, hcd->regs + HC_ISO_IRQ_MASK_AND_REG); + isp1760_writel(0xffffffff, hcd->regs + HC_ISO_IRQ_MASK_OR_REG); + /* step 23 passed */ +} + +static int isp1760_run(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + int retval; + u32 temp; + u32 command; + u32 chipid; + + hcd->uses_new_polling = 1; + hcd->poll_rh = 0; + + hcd->state = HC_STATE_RUNNING; + isp1760_enable_interrupts(hcd); + temp = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL); + temp |= FINAL_HW_CONFIG; + isp1760_writel(temp, hcd->regs + HC_HW_MODE_CTRL); + + command = isp1760_readl(hcd->regs + HC_USBCMD); + command &= ~(CMD_LRESET|CMD_RESET); + command |= CMD_RUN; + isp1760_writel(command, hcd->regs + HC_USBCMD); + + retval = handshake(priv, hcd->regs + HC_USBCMD, CMD_RUN, CMD_RUN, + 250 * 1000); + if (retval) + return retval; + + /* + * XXX + * Spec says to write FLAG_CF as last config action, priv code grabs + * the semaphore while doing so. + */ + down_write(&ehci_cf_port_reset_rwsem); + isp1760_writel(FLAG_CF, hcd->regs + HC_CONFIGFLAG); + + retval = handshake(priv, hcd->regs + HC_CONFIGFLAG, FLAG_CF, FLAG_CF, + 250 * 1000); + up_write(&ehci_cf_port_reset_rwsem); + if (retval) + return retval; + + chipid = isp1760_readl(hcd->regs + HC_CHIP_ID_REG); + isp1760_info(priv, "USB ISP %04x HW rev. %d started\n", chipid & 0xffff, + chipid >> 16); + + /* PTD Register Init Part 2, Step 28 */ + /* enable INTs */ + isp1760_init_maps(hcd); + + /* GRR this is run-once init(), being done every time the HC starts. + * So long as they're part of class devices, we can't do it init() + * since the class device isn't created that early. + */ + return 0; +} + +static u32 base_to_chip(u32 base) +{ + return ((base - 0x400) >> 3); +} + +static void transform_into_atl(struct isp1760_hcd *priv, struct isp1760_qh *qh, + struct isp1760_qtd *qtd, struct urb *urb, + u32 payload, struct ptd *ptd) +{ + u32 dw0; + u32 dw1; + u32 dw2; + u32 dw3; + u32 maxpacket; + u32 multi; + u32 pid_code; + u32 rl = RL_COUNTER; + u32 nak = NAK_COUNTER; + + /* according to 3.6.2, max packet len can not be > 0x400 */ + maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + multi = 1 + ((maxpacket >> 11) & 0x3); + maxpacket &= 0x7ff; + + /* DW0 */ + dw0 = PTD_VALID; + dw0 |= PTD_LENGTH(qtd->length); + dw0 |= PTD_MAXPACKET(maxpacket); + dw0 |= PTD_ENDPOINT(usb_pipeendpoint(urb->pipe)); + dw1 = usb_pipeendpoint(urb->pipe) >> 1; + + /* DW1 */ + dw1 |= PTD_DEVICE_ADDR(usb_pipedevice(urb->pipe)); + + pid_code = qtd->packet_type; + dw1 |= PTD_PID_TOKEN(pid_code); + + if (usb_pipebulk(urb->pipe)) + dw1 |= PTD_TRANS_BULK; + else if (usb_pipeint(urb->pipe)) + dw1 |= PTD_TRANS_INT; + + if (urb->dev->speed != USB_SPEED_HIGH) { + /* split transaction */ + + dw1 |= PTD_TRANS_SPLIT; + if (urb->dev->speed == USB_SPEED_LOW) + dw1 |= PTD_SE_USB_LOSPEED; + + dw1 |= PTD_PORT_NUM(urb->dev->ttport); + dw1 |= PTD_HUB_NUM(urb->dev->tt->hub->devnum); + + /* SE bit for Split INT transfers */ + if (usb_pipeint(urb->pipe) && + (urb->dev->speed == USB_SPEED_LOW)) + dw1 |= 2 << 16; + + dw3 = 0; + rl = 0; + nak = 0; + } else { + dw0 |= PTD_MULTI(multi); + if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) + dw3 = qh->ping; + else + dw3 = 0; + } + /* DW2 */ + dw2 = 0; + dw2 |= PTD_DATA_START_ADDR(base_to_chip(payload)); + dw2 |= PTD_RL_CNT(rl); + dw3 |= PTD_NAC_CNT(nak); + + /* DW3 */ + if (usb_pipecontrol(urb->pipe)) + dw3 |= PTD_DATA_TOGGLE(qtd->toggle); + else + dw3 |= qh->toggle; + + + dw3 |= PTD_ACTIVE; + /* Cerr */ + dw3 |= PTD_CERR(ERR_COUNTER); + + memset(ptd, 0, sizeof(*ptd)); + + ptd->dw0 = cpu_to_le32(dw0); + ptd->dw1 = cpu_to_le32(dw1); + ptd->dw2 = cpu_to_le32(dw2); + ptd->dw3 = cpu_to_le32(dw3); +} + +static void transform_add_int(struct isp1760_hcd *priv, struct isp1760_qh *qh, + struct isp1760_qtd *qtd, struct urb *urb, + u32 payload, struct ptd *ptd) +{ + u32 maxpacket; + u32 multi; + u32 numberofusofs; + u32 i; + u32 usofmask, usof; + u32 period; + + maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + multi = 1 + ((maxpacket >> 11) & 0x3); + maxpacket &= 0x7ff; + /* length of the data per uframe */ + maxpacket = multi * maxpacket; + + numberofusofs = urb->transfer_buffer_length / maxpacket; + if (urb->transfer_buffer_length % maxpacket) + numberofusofs += 1; + + usofmask = 1; + usof = 0; + for (i = 0; i < numberofusofs; i++) { + usof |= usofmask; + usofmask <<= 1; + } + + if (urb->dev->speed != USB_SPEED_HIGH) { + /* split */ + ptd->dw5 = __constant_cpu_to_le32(0x1c); + + if (qh->period >= 32) + period = qh->period / 2; + else + period = qh->period; + + } else { + + if (qh->period >= 8) + period = qh->period/8; + else + period = qh->period; + + if (period >= 32) + period = 16; + + if (qh->period >= 8) { + /* millisecond period */ + period = (period << 3); + } else { + /* usof based tranmsfers */ + /* minimum 4 usofs */ + usof = 0x11; + } + } + + ptd->dw2 |= cpu_to_le32(period); + ptd->dw4 = cpu_to_le32(usof); +} + +static void transform_into_int(struct isp1760_hcd *priv, struct isp1760_qh *qh, + struct isp1760_qtd *qtd, struct urb *urb, + u32 payload, struct ptd *ptd) +{ + transform_into_atl(priv, qh, qtd, urb, payload, ptd); + transform_add_int(priv, qh, qtd, urb, payload, ptd); +} + +static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len, + u32 token) +{ + int count; + + qtd->data_buffer = databuffer; + qtd->packet_type = GET_QTD_TOKEN_TYPE(token); + qtd->toggle = GET_DATA_TOGGLE(token); + + if (len > HC_ATL_PL_SIZE) + count = HC_ATL_PL_SIZE; + else + count = len; + + qtd->length = count; + return count; +} + +static int check_error(struct ptd *ptd) +{ + int error = 0; + u32 dw3; + + dw3 = le32_to_cpu(ptd->dw3); + if (dw3 & DW3_HALT_BIT) + error = -EPIPE; + + if (dw3 & DW3_ERROR_BIT) { + printk(KERN_ERR "error bit is set in DW3\n"); + error = -EPIPE; + } + + if (dw3 & DW3_QTD_ACTIVE) { + printk(KERN_ERR "transfer active bit is set DW3\n"); + printk(KERN_ERR "nak counter: %d, rl: %d\n", (dw3 >> 19) & 0xf, + (le32_to_cpu(ptd->dw2) >> 25) & 0xf); + } + + return error; +} + +static void check_int_err_status(u32 dw4) +{ + u32 i; + + dw4 >>= 8; + + for (i = 0; i < 8; i++) { + switch (dw4 & 0x7) { + case INT_UNDERRUN: + printk(KERN_ERR "ERROR: under run , %d\n", i); + break; + + case INT_EXACT: + printk(KERN_ERR "ERROR: transaction error, %d\n", i); + break; + + case INT_BABBLE: + printk(KERN_ERR "ERROR: babble error, %d\n", i); + break; + } + dw4 >>= 3; + } +} + +static void enqueue_one_qtd(struct isp1760_qtd *qtd, struct isp1760_hcd *priv, + u32 payload) +{ + u32 token; + struct usb_hcd *hcd = priv_to_hcd(priv); + + token = qtd->packet_type; + + if (qtd->length && (qtd->length <= HC_ATL_PL_SIZE)) { + switch (token) { + case IN_PID: + break; + case OUT_PID: + case SETUP_PID: + priv_write_copy(priv, qtd->data_buffer, + hcd->regs + payload, + qtd->length); + } + } +} + +static void enqueue_one_atl_qtd(u32 atl_regs, u32 payload, + struct isp1760_hcd *priv, struct isp1760_qh *qh, + struct urb *urb, u32 slot, struct isp1760_qtd *qtd) +{ + struct ptd ptd; + struct usb_hcd *hcd = priv_to_hcd(priv); + + transform_into_atl(priv, qh, qtd, urb, payload, &ptd); + priv_write_copy(priv, (u32 *)&ptd, hcd->regs + atl_regs, sizeof(ptd)); + enqueue_one_qtd(qtd, priv, payload); + + priv->atl_ints[slot].urb = urb; + priv->atl_ints[slot].qh = qh; + priv->atl_ints[slot].qtd = qtd; + priv->atl_ints[slot].data_buffer = qtd->data_buffer; + priv->atl_ints[slot].payload = payload; + qtd->status |= URB_ENQUEUED | URB_TYPE_ATL; + qtd->status |= slot << 16; +} + +static void enqueue_one_int_qtd(u32 int_regs, u32 payload, + struct isp1760_hcd *priv, struct isp1760_qh *qh, + struct urb *urb, u32 slot, struct isp1760_qtd *qtd) +{ + struct ptd ptd; + struct usb_hcd *hcd = priv_to_hcd(priv); + + transform_into_int(priv, qh, qtd, urb, payload, &ptd); + priv_write_copy(priv, (u32 *)&ptd, hcd->regs + int_regs, sizeof(ptd)); + enqueue_one_qtd(qtd, priv, payload); + + priv->int_ints[slot].urb = urb; + priv->int_ints[slot].qh = qh; + priv->int_ints[slot].qtd = qtd; + priv->int_ints[slot].data_buffer = qtd->data_buffer; + priv->int_ints[slot].payload = payload; + qtd->status |= URB_ENQUEUED | URB_TYPE_INT; + qtd->status |= slot << 16; +} + +void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, + struct isp1760_qtd *qtd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 skip_map, or_map; + u32 queue_entry; + u32 slot; + u32 atl_regs, payload; + u32 buffstatus; + + skip_map = isp1760_readl(hcd->regs + HC_ATL_PTD_SKIPMAP_REG); + + BUG_ON(!skip_map); + slot = __ffs(skip_map); + queue_entry = 1 << slot; + + atl_regs = ATL_REGS_OFFSET + slot * sizeof(struct ptd); + + payload = alloc_mem(priv, qtd->length); + + enqueue_one_atl_qtd(atl_regs, payload, priv, qh, qtd->urb, slot, qtd); + + or_map = isp1760_readl(hcd->regs + HC_ATL_IRQ_MASK_OR_REG); + or_map |= queue_entry; + isp1760_writel(or_map, hcd->regs + HC_ATL_IRQ_MASK_OR_REG); + + skip_map &= ~queue_entry; + isp1760_writel(skip_map, hcd->regs + HC_ATL_PTD_SKIPMAP_REG); + + buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG); + buffstatus |= ATL_BUFFER; + isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG); +} + +void enqueue_an_INT_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, + struct isp1760_qtd *qtd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 skip_map, or_map; + u32 queue_entry; + u32 slot; + u32 int_regs, payload; + u32 buffstatus; + + skip_map = isp1760_readl(hcd->regs + HC_INT_PTD_SKIPMAP_REG); + + BUG_ON(!skip_map); + slot = __ffs(skip_map); + queue_entry = 1 << slot; + + int_regs = INT_REGS_OFFSET + slot * sizeof(struct ptd); + + payload = alloc_mem(priv, qtd->length); + + enqueue_one_int_qtd(int_regs, payload, priv, qh, qtd->urb, slot, qtd); + + or_map = isp1760_readl(hcd->regs + HC_INT_IRQ_MASK_OR_REG); + or_map |= queue_entry; + isp1760_writel(or_map, hcd->regs + HC_INT_IRQ_MASK_OR_REG); + + skip_map &= ~queue_entry; + isp1760_writel(skip_map, hcd->regs + HC_INT_PTD_SKIPMAP_REG); + + buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG); + buffstatus |= INT_BUFFER; + isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG); +} + +static void isp1760_urb_done(struct isp1760_hcd *priv, struct urb *urb, int status) +__releases(priv->lock) +__acquires(priv->lock) +{ + if (!urb->unlinked) { + if (status == -EINPROGRESS) + status = 0; + } + + /* complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb); + spin_unlock(&priv->lock); + usb_hcd_giveback_urb(priv_to_hcd(priv), urb, status); + spin_lock(&priv->lock); +} + +static void isp1760_qtd_free(struct isp1760_qtd *qtd) +{ + kmem_cache_free(qtd_cachep, qtd); +} + +static struct isp1760_qtd *clean_this_qtd(struct isp1760_qtd *qtd) +{ + struct isp1760_qtd *tmp_qtd; + + tmp_qtd = qtd->hw_next; + list_del(&qtd->qtd_list); + isp1760_qtd_free(qtd); + return tmp_qtd; +} + +/* + * Remove this QTD from the QH list and free its memory. If this QTD + * isn't the last one than remove also his successor(s). + * Returns the QTD which is part of an new URB and should be enqueued. + */ +static struct isp1760_qtd *clean_up_qtdlist(struct isp1760_qtd *qtd) +{ + struct isp1760_qtd *tmp_qtd; + int last_one; + + do { + tmp_qtd = qtd->hw_next; + last_one = qtd->status & URB_COMPLETE_NOTIFY; + list_del(&qtd->qtd_list); + isp1760_qtd_free(qtd); + qtd = tmp_qtd; + } while (!last_one && qtd); + + return qtd; +} + +static void do_atl_int(struct usb_hcd *usb_hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); + u32 done_map, skip_map; + struct ptd ptd; + struct urb *urb = NULL; + u32 atl_regs_base; + u32 atl_regs; + u32 queue_entry; + u32 payload; + u32 length; + u32 or_map; + u32 status = -EINVAL; + int error; + struct isp1760_qtd *qtd; + struct isp1760_qh *qh; + u32 rl; + u32 nakcount; + + done_map = isp1760_readl(usb_hcd->regs + + HC_ATL_PTD_DONEMAP_REG); + skip_map = isp1760_readl(usb_hcd->regs + + HC_ATL_PTD_SKIPMAP_REG); + + or_map = isp1760_readl(usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG); + or_map &= ~done_map; + isp1760_writel(or_map, usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG); + + atl_regs_base = ATL_REGS_OFFSET; + while (done_map) { + u32 dw1; + u32 dw2; + u32 dw3; + + status = 0; + + queue_entry = __ffs(done_map); + done_map &= ~(1 << queue_entry); + skip_map |= 1 << queue_entry; + + atl_regs = atl_regs_base + queue_entry * sizeof(struct ptd); + + urb = priv->atl_ints[queue_entry].urb; + qtd = priv->atl_ints[queue_entry].qtd; + qh = priv->atl_ints[queue_entry].qh; + payload = priv->atl_ints[queue_entry].payload; + + if (!qh) { + printk(KERN_ERR "qh is 0\n"); + continue; + } + priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + atl_regs, + atl_regs, sizeof(ptd)); + + dw1 = le32_to_cpu(ptd.dw1); + dw2 = le32_to_cpu(ptd.dw2); + dw3 = le32_to_cpu(ptd.dw3); + rl = (dw2 >> 25) & 0x0f; + nakcount = (dw3 >> 19) & 0xf; + + /* Transfer Error, *but* active and no HALT -> reload */ + if ((dw3 & DW3_ERROR_BIT) && (dw3 & DW3_QTD_ACTIVE) && + !(dw3 & DW3_HALT_BIT)) { + + /* according to ppriv code, we have to + * reload this one if trasfered bytes != requested bytes + * else act like everything went smooth.. + * XXX This just doesn't feel right and hasn't + * triggered so far. + */ + + length = PTD_XFERRED_LENGTH(dw3); + printk(KERN_ERR "Should reload now.... transfered %d " + "of %zu\n", length, qtd->length); + BUG(); + } + + if (!nakcount && (dw3 & DW3_QTD_ACTIVE)) { + u32 buffstatus; + + /* XXX + * NAKs are handled in HW by the chip. Usually if the + * device is not able to send data fast enough. + * This did not trigger for a long time now. + */ + printk(KERN_ERR "Reloading ptd %p/%p... qh %p readed: " + "%d of %d done: %08x cur: %08x\n", qtd, + urb, qh, PTD_XFERRED_LENGTH(dw3), + qtd->length, done_map, + (1 << queue_entry)); + + /* RL counter = ERR counter */ + dw3 &= ~(0xf << 19); + dw3 |= rl << 19; + dw3 &= ~(3 << (55 - 32)); + dw3 |= ERR_COUNTER << (55 - 32); + + /* + * It is not needed to write skip map back because it + * is unchanged. Just make sure that this entry is + * unskipped once it gets written to the HW. + */ + skip_map &= ~(1 << queue_entry); + or_map = isp1760_readl(usb_hcd->regs + + HC_ATL_IRQ_MASK_OR_REG); + or_map |= 1 << queue_entry; + isp1760_writel(or_map, usb_hcd->regs + + HC_ATL_IRQ_MASK_OR_REG); + + ptd.dw3 = cpu_to_le32(dw3); + priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs + + atl_regs, sizeof(ptd)); + + ptd.dw0 |= __constant_cpu_to_le32(PTD_VALID); + priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs + + atl_regs, sizeof(ptd)); + + buffstatus = isp1760_readl(usb_hcd->regs + + HC_BUFFER_STATUS_REG); + buffstatus |= ATL_BUFFER; + isp1760_writel(buffstatus, usb_hcd->regs + + HC_BUFFER_STATUS_REG); + continue; + } + + error = check_error(&ptd); + if (error) { + status = error; + priv->atl_ints[queue_entry].qh->toggle = 0; + priv->atl_ints[queue_entry].qh->ping = 0; + urb->status = -EPIPE; + +#if 0 + printk(KERN_ERR "Error in %s().\n", __func__); + printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x " + "dw3: %08x dw4: %08x dw5: %08x dw6: " + "%08x dw7: %08x\n", + ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3, + ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7); +#endif + } else { + if (usb_pipetype(urb->pipe) == PIPE_BULK) { + priv->atl_ints[queue_entry].qh->toggle = dw3 & + (1 << 25); + priv->atl_ints[queue_entry].qh->ping = dw3 & + (1 << 26); + } + } + + length = PTD_XFERRED_LENGTH(dw3); + if (length) { + switch (DW1_GET_PID(dw1)) { + case IN_PID: + priv_read_copy(priv, + priv->atl_ints[queue_entry].data_buffer, + usb_hcd->regs + payload, payload, + length); + + case OUT_PID: + + urb->actual_length += length; + + case SETUP_PID: + break; + } + } + + priv->atl_ints[queue_entry].data_buffer = NULL; + priv->atl_ints[queue_entry].urb = NULL; + priv->atl_ints[queue_entry].qtd = NULL; + priv->atl_ints[queue_entry].qh = NULL; + + free_mem(priv, payload); + + isp1760_writel(skip_map, usb_hcd->regs + + HC_ATL_PTD_SKIPMAP_REG); + + if (urb->status == -EPIPE) { + /* HALT was received */ + + qtd = clean_up_qtdlist(qtd); + isp1760_urb_done(priv, urb, urb->status); + + } else if (usb_pipebulk(urb->pipe) && (length < qtd->length)) { + /* short BULK received */ + + printk(KERN_ERR "short bulk, %d instead %d\n", length, + qtd->length); + if (urb->transfer_flags & URB_SHORT_NOT_OK) { + urb->status = -EREMOTEIO; + printk(KERN_ERR "not okey\n"); + } + + if (urb->status == -EINPROGRESS) + urb->status = 0; + + qtd = clean_up_qtdlist(qtd); + + isp1760_urb_done(priv, urb, urb->status); + + } else if (qtd->status & URB_COMPLETE_NOTIFY) { + /* that was the last qtd of that URB */ + + if (urb->status == -EINPROGRESS) + urb->status = 0; + + qtd = clean_this_qtd(qtd); + isp1760_urb_done(priv, urb, urb->status); + + } else { + /* next QTD of this URB */ + + qtd = clean_this_qtd(qtd); + BUG_ON(!qtd); + } + + if (qtd) + enqueue_an_ATL_packet(usb_hcd, qh, qtd); + + skip_map = isp1760_readl(usb_hcd->regs + + HC_ATL_PTD_SKIPMAP_REG); + } +} + +static void do_intl_int(struct usb_hcd *usb_hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); + u32 done_map, skip_map; + struct ptd ptd; + struct urb *urb = NULL; + u32 int_regs; + u32 int_regs_base; + u32 payload; + u32 length; + u32 or_map; + int error; + u32 queue_entry; + struct isp1760_qtd *qtd; + struct isp1760_qh *qh; + + done_map = isp1760_readl(usb_hcd->regs + + HC_INT_PTD_DONEMAP_REG); + skip_map = isp1760_readl(usb_hcd->regs + + HC_INT_PTD_SKIPMAP_REG); + + or_map = isp1760_readl(usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG); + or_map &= ~done_map; + isp1760_writel(or_map, usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG); + + int_regs_base = INT_REGS_OFFSET; + + while (done_map) { + u32 dw1; + u32 dw3; + + queue_entry = __ffs(done_map); + done_map &= ~(1 << queue_entry); + skip_map |= 1 << queue_entry; + + int_regs = int_regs_base + queue_entry * sizeof(struct ptd); + urb = priv->int_ints[queue_entry].urb; + qtd = priv->int_ints[queue_entry].qtd; + qh = priv->int_ints[queue_entry].qh; + payload = priv->int_ints[queue_entry].payload; + + if (!qh) { + printk(KERN_ERR "(INT) qh is 0\n"); + continue; + } + + priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + int_regs, + int_regs, sizeof(ptd)); + dw1 = le32_to_cpu(ptd.dw1); + dw3 = le32_to_cpu(ptd.dw3); + check_int_err_status(le32_to_cpu(ptd.dw4)); + + error = check_error(&ptd); + if (error) { +#if 0 + printk(KERN_ERR "Error in %s().\n", __func__); + printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x " + "dw3: %08x dw4: %08x dw5: %08x dw6: " + "%08x dw7: %08x\n", + ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3, + ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7); +#endif + urb->status = -EPIPE; + priv->int_ints[queue_entry].qh->toggle = 0; + priv->int_ints[queue_entry].qh->ping = 0; + + } else { + priv->int_ints[queue_entry].qh->toggle = + dw3 & (1 << 25); + priv->int_ints[queue_entry].qh->ping = dw3 & (1 << 26); + } + + if (urb->dev->speed != USB_SPEED_HIGH) + length = PTD_XFERRED_LENGTH_LO(dw3); + else + length = PTD_XFERRED_LENGTH(dw3); + + if (length) { + switch (DW1_GET_PID(dw1)) { + case IN_PID: + priv_read_copy(priv, + priv->int_ints[queue_entry].data_buffer, + usb_hcd->regs + payload , payload, + length); + case OUT_PID: + + urb->actual_length += length; + + case SETUP_PID: + break; + } + } + + priv->int_ints[queue_entry].data_buffer = NULL; + priv->int_ints[queue_entry].urb = NULL; + priv->int_ints[queue_entry].qtd = NULL; + priv->int_ints[queue_entry].qh = NULL; + + isp1760_writel(skip_map, usb_hcd->regs + + HC_INT_PTD_SKIPMAP_REG); + free_mem(priv, payload); + + if (urb->status == -EPIPE) { + /* HALT received */ + + qtd = clean_up_qtdlist(qtd); + isp1760_urb_done(priv, urb, urb->status); + + } else if (qtd->status & URB_COMPLETE_NOTIFY) { + + if (urb->status == -EINPROGRESS) + urb->status = 0; + + qtd = clean_this_qtd(qtd); + isp1760_urb_done(priv, urb, urb->status); + + } else { + /* next QTD of this URB */ + + qtd = clean_this_qtd(qtd); + BUG_ON(!qtd); + } + + if (qtd) + enqueue_an_INT_packet(usb_hcd, qh, qtd); + + skip_map = isp1760_readl(usb_hcd->regs + + HC_INT_PTD_SKIPMAP_REG); + } +} + +#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) +static struct isp1760_qh *qh_make(struct isp1760_hcd *priv, struct urb *urb, + gfp_t flags) +{ + struct isp1760_qh *qh; + int is_input, type; + + qh = isp1760_qh_alloc(priv, flags); + if (!qh) + return qh; + + /* + * init endpoint/device data for this QH + */ + is_input = usb_pipein(urb->pipe); + type = usb_pipetype(urb->pipe); + + if (type == PIPE_INTERRUPT) { + + if (urb->dev->speed == USB_SPEED_HIGH) { + + qh->period = urb->interval >> 3; + if (qh->period == 0 && urb->interval != 1) { + /* NOTE interval 2 or 4 uframes could work. + * But interval 1 scheduling is simpler, and + * includes high bandwidth. + */ + printk(KERN_ERR "intr period %d uframes, NYET!", + urb->interval); + qh_destroy(qh); + return NULL; + } + } else { + qh->period = urb->interval; + } + } + + /* support for tt scheduling, and access to toggles */ + qh->dev = urb->dev; + + if (!usb_pipecontrol(urb->pipe)) + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, + 1); + return qh; +} + +/* + * For control/bulk/interrupt, return QH with these TDs appended. + * Allocates and initializes the QH if necessary. + * Returns null if it can't allocate a QH it needs to. + * If the QH has TDs (urbs) already, that's great. + */ +static struct isp1760_qh *qh_append_tds(struct isp1760_hcd *priv, + struct urb *urb, struct list_head *qtd_list, int epnum, + void **ptr) +{ + struct isp1760_qh *qh; + struct isp1760_qtd *qtd; + struct isp1760_qtd *prev_qtd; + + qh = (struct isp1760_qh *)*ptr; + if (!qh) { + /* can't sleep here, we have priv->lock... */ + qh = qh_make(priv, urb, GFP_ATOMIC); + if (!qh) + return qh; + *ptr = qh; + } + + qtd = list_entry(qtd_list->next, struct isp1760_qtd, + qtd_list); + if (!list_empty(&qh->qtd_list)) + prev_qtd = list_entry(qh->qtd_list.prev, + struct isp1760_qtd, qtd_list); + else + prev_qtd = NULL; + + list_splice(qtd_list, qh->qtd_list.prev); + if (prev_qtd) { + BUG_ON(prev_qtd->hw_next); + prev_qtd->hw_next = qtd; + } + + urb->hcpriv = qh; + return qh; +} + +static void qtd_list_free(struct isp1760_hcd *priv, struct urb *urb, + struct list_head *qtd_list) +{ + struct list_head *entry, *temp; + + list_for_each_safe(entry, temp, qtd_list) { + struct isp1760_qtd *qtd; + + qtd = list_entry(entry, struct isp1760_qtd, qtd_list); + list_del(&qtd->qtd_list); + isp1760_qtd_free(qtd); + } +} + +static int isp1760_prepare_enqueue(struct isp1760_hcd *priv, struct urb *urb, + struct list_head *qtd_list, gfp_t mem_flags, packet_enqueue *p) +{ + struct isp1760_qtd *qtd; + int epnum; + unsigned long flags; + struct isp1760_qh *qh = NULL; + int rc; + int qh_busy; + + qtd = list_entry(qtd_list->next, struct isp1760_qtd, qtd_list); + epnum = urb->ep->desc.bEndpointAddress; + + spin_lock_irqsave(&priv->lock, flags); + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &priv_to_hcd(priv)->flags)) { + rc = -ESHUTDOWN; + goto done; + } + rc = usb_hcd_link_urb_to_ep(priv_to_hcd(priv), urb); + if (rc) + goto done; + + qh = urb->ep->hcpriv; + if (qh) + qh_busy = !list_empty(&qh->qtd_list); + else + qh_busy = 0; + + qh = qh_append_tds(priv, urb, qtd_list, epnum, &urb->ep->hcpriv); + if (!qh) { + usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb); + rc = -ENOMEM; + goto done; + } + + if (!qh_busy) + p(priv_to_hcd(priv), qh, qtd); + +done: + spin_unlock_irqrestore(&priv->lock, flags); + if (!qh) + qtd_list_free(priv, urb, qtd_list); + return rc; +} + +static struct isp1760_qtd *isp1760_qtd_alloc(struct isp1760_hcd *priv, + gfp_t flags) +{ + struct isp1760_qtd *qtd; + + qtd = kmem_cache_zalloc(qtd_cachep, flags); + if (qtd) + INIT_LIST_HEAD(&qtd->qtd_list); + + return qtd; +} + +/* + * create a list of filled qtds for this URB; won't link into qh. + */ +static struct list_head *qh_urb_transaction(struct isp1760_hcd *priv, + struct urb *urb, struct list_head *head, gfp_t flags) +{ + struct isp1760_qtd *qtd, *qtd_prev; + void *buf; + int len, maxpacket; + int is_input; + u32 token; + + /* + * URBs map to sequences of QTDs: one logical transaction + */ + qtd = isp1760_qtd_alloc(priv, flags); + if (!qtd) + return NULL; + + list_add_tail(&qtd->qtd_list, head); + qtd->urb = urb; + urb->status = -EINPROGRESS; + + token = 0; + /* for split transactions, SplitXState initialized to zero */ + + len = urb->transfer_buffer_length; + is_input = usb_pipein(urb->pipe); + if (usb_pipecontrol(urb->pipe)) { + /* SETUP pid */ + qtd_fill(qtd, urb->setup_packet, + sizeof(struct usb_ctrlrequest), + token | SETUP_PID); + + /* ... and always at least one more pid */ + token ^= DATA_TOGGLE; + qtd_prev = qtd; + qtd = isp1760_qtd_alloc(priv, flags); + if (!qtd) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = qtd; + list_add_tail(&qtd->qtd_list, head); + + /* for zero length DATA stages, STATUS is always IN */ + if (len == 0) + token |= IN_PID; + } + + /* + * data transfer stage: buffer setup + */ + buf = urb->transfer_buffer; + + if (is_input) + token |= IN_PID; + else + token |= OUT_PID; + + maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input)); + + /* + * buffer gets wrapped in one or more qtds; + * last one may be "short" (including zero len) + * and may serve as a control status ack + */ + for (;;) { + int this_qtd_len; + + if (!buf && len) { + /* XXX This looks like usb storage / SCSI bug */ + printk(KERN_ERR "buf is null, dma is %08lx len is %d\n", + (long unsigned)urb->transfer_dma, len); + WARN_ON(1); + } + + this_qtd_len = qtd_fill(qtd, buf, len, token); + len -= this_qtd_len; + buf += this_qtd_len; + + /* qh makes control packets use qtd toggle; maybe switch it */ + if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) + token ^= DATA_TOGGLE; + + if (len <= 0) + break; + + qtd_prev = qtd; + qtd = isp1760_qtd_alloc(priv, flags); + if (!qtd) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = qtd; + list_add_tail(&qtd->qtd_list, head); + } + + /* + * control requests may need a terminating data "status" ack; + * bulk ones may need a terminating short packet (zero length). + */ + if (urb->transfer_buffer_length != 0) { + int one_more = 0; + + if (usb_pipecontrol(urb->pipe)) { + one_more = 1; + /* "in" <--> "out" */ + token ^= IN_PID; + /* force DATA1 */ + token |= DATA_TOGGLE; + } else if (usb_pipebulk(urb->pipe) + && (urb->transfer_flags & URB_ZERO_PACKET) + && !(urb->transfer_buffer_length % maxpacket)) { + one_more = 1; + } + if (one_more) { + qtd_prev = qtd; + qtd = isp1760_qtd_alloc(priv, flags); + if (!qtd) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = qtd; + list_add_tail(&qtd->qtd_list, head); + + /* never any data in such packets */ + qtd_fill(qtd, NULL, 0, token); + } + } + + qtd->status = URB_COMPLETE_NOTIFY; + return head; + +cleanup: + qtd_list_free(priv, urb, head); + return NULL; +} + +static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + struct list_head qtd_list; + packet_enqueue *pe; + + INIT_LIST_HEAD(&qtd_list); + + switch (usb_pipetype(urb->pipe)) { + case PIPE_CONTROL: + case PIPE_BULK: + + if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags)) + return -ENOMEM; + pe = enqueue_an_ATL_packet; + break; + + case PIPE_INTERRUPT: + if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags)) + return -ENOMEM; + pe = enqueue_an_INT_packet; + break; + + case PIPE_ISOCHRONOUS: + printk(KERN_ERR "PIPE_ISOCHRONOUS ain't supported\n"); + default: + return -EPIPE; + } + + isp1760_prepare_enqueue(priv, urb, &qtd_list, mem_flags, pe); + return 0; +} + +static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, + int status) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + struct inter_packet_info *ints; + u32 i; + u32 reg_base, or_reg, skip_reg; + int flags; + struct ptd ptd; + + switch (usb_pipetype(urb->pipe)) { + case PIPE_ISOCHRONOUS: + return -EPIPE; + break; + + case PIPE_INTERRUPT: + ints = priv->int_ints; + reg_base = INT_REGS_OFFSET; + or_reg = HC_INT_IRQ_MASK_OR_REG; + skip_reg = HC_INT_PTD_SKIPMAP_REG; + break; + + default: + ints = priv->atl_ints; + reg_base = ATL_REGS_OFFSET; + or_reg = HC_ATL_IRQ_MASK_OR_REG; + skip_reg = HC_ATL_PTD_SKIPMAP_REG; + break; + } + + memset(&ptd, 0, sizeof(ptd)); + spin_lock_irqsave(&priv->lock, flags); + + for (i = 0; i < 32; i++) { + if (ints->urb == urb) { + u32 skip_map; + u32 or_map; + struct isp1760_qtd *qtd; + + skip_map = isp1760_readl(hcd->regs + skip_reg); + skip_map |= 1 << i; + isp1760_writel(skip_map, hcd->regs + skip_reg); + + or_map = isp1760_readl(hcd->regs + or_reg); + or_map &= ~(1 << i); + isp1760_writel(or_map, hcd->regs + or_reg); + + priv_write_copy(priv, (u32 *)&ptd, hcd->regs + reg_base + + i * sizeof(ptd), sizeof(ptd)); + qtd = ints->qtd; + + clean_up_qtdlist(qtd); + + free_mem(priv, ints->payload); + + ints->urb = NULL; + ints->qh = NULL; + ints->qtd = NULL; + ints->data_buffer = NULL; + ints->payload = 0; + + isp1760_urb_done(priv, urb, status); + break; + } + ints++; + } + + spin_unlock_irqrestore(&priv->lock, flags); + return 0; +} + +static irqreturn_t isp1760_irq(struct usb_hcd *usb_hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); + u32 imask; + irqreturn_t irqret = IRQ_NONE; + + spin_lock(&priv->lock); + + if (!(usb_hcd->state & HC_STATE_RUNNING)) + goto leave; + + imask = isp1760_readl(usb_hcd->regs + HC_INTERRUPT_REG); + if (unlikely(!imask)) + goto leave; + + isp1760_writel(imask, usb_hcd->regs + HC_INTERRUPT_REG); + if (imask & HC_ATL_INT) + do_atl_int(usb_hcd); + + if (imask & HC_INTL_INT) + do_intl_int(usb_hcd); + + irqret = IRQ_HANDLED; +leave: + spin_unlock(&priv->lock); + return irqret; +} + +static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 temp, status = 0; + u32 mask; + int retval = 1; + unsigned long flags; + + /* if !USB_SUSPEND, root hub timers won't get shut down ... */ + if (!HC_IS_RUNNING(hcd->state)) + return 0; + + /* init status to no-changes */ + buf[0] = 0; + mask = PORT_CSC; + + spin_lock_irqsave(&priv->lock, flags); + temp = isp1760_readl(hcd->regs + HC_PORTSC1); + + if (temp & PORT_OWNER) { + if (temp & PORT_CSC) { + temp &= ~PORT_CSC; + isp1760_writel(temp, hcd->regs + HC_PORTSC1); + goto done; + } + } + + /* + * Return status information even for ports with OWNER set. + * Otherwise khubd wouldn't see the disconnect event when a + * high-speed device is switched over to the companion + * controller by the user. + */ + + if ((temp & mask) != 0 + || ((temp & PORT_RESUME) != 0 + && time_after_eq(jiffies, + priv->reset_done))) { + buf [0] |= 1 << (0 + 1); + status = STS_PCD; + } + /* FIXME autosuspend idle root hubs */ +done: + spin_unlock_irqrestore(&priv->lock, flags); + return status ? retval : 0; +} + +static void isp1760_hub_descriptor(struct isp1760_hcd *priv, + struct usb_hub_descriptor *desc) +{ + int ports = HCS_N_PORTS(priv->hcs_params); + u16 temp; + + desc->bDescriptorType = 0x29; + /* priv 1.0, 2.3.9 says 20ms max */ + desc->bPwrOn2PwrGood = 10; + desc->bHubContrCurrent = 0; + + desc->bNbrPorts = ports; + temp = 1 + (ports / 8); + desc->bDescLength = 7 + 2 * temp; + + /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ + memset(&desc->bitmap[0], 0, temp); + memset(&desc->bitmap[temp], 0xff, temp); + + /* per-port overcurrent reporting */ + temp = 0x0008; + if (HCS_PPC(priv->hcs_params)) + /* per-port power control */ + temp |= 0x0001; + else + /* no power switching */ + temp |= 0x0002; + desc->wHubCharacteristics = cpu_to_le16(temp); +} + +#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) + +static int check_reset_complete(struct isp1760_hcd *priv, int index, + u32 __iomem *status_reg, int port_status) +{ + if (!(port_status & PORT_CONNECT)) + return port_status; + + /* if reset finished and it's still not enabled -- handoff */ + if (!(port_status & PORT_PE)) { + + printk(KERN_ERR "port %d full speed --> companion\n", + index + 1); + + port_status |= PORT_OWNER; + port_status &= ~PORT_RWC_BITS; + isp1760_writel(port_status, status_reg); + + } else + printk(KERN_ERR "port %d high speed\n", index + 1); + + return port_status; +} + +static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, + u16 wValue, u16 wIndex, char *buf, u16 wLength) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + int ports = HCS_N_PORTS(priv->hcs_params); + u32 __iomem *status_reg = hcd->regs + HC_PORTSC1; + u32 temp, status; + unsigned long flags; + int retval = 0; + unsigned selector; + + /* + * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. + * HCS_INDICATOR may say we can change LEDs to off/amber/green. + * (track current state ourselves) ... blink for diagnostics, + * power, "this is the one", etc. EHCI spec supports this. + */ + + spin_lock_irqsave(&priv->lock, flags); + switch (typeReq) { + case ClearHubFeature: + switch (wValue) { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* no hub-wide feature/status flags */ + break; + default: + goto error; + } + break; + case ClearPortFeature: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = isp1760_readl(status_reg); + + /* + * Even if OWNER is set, so the port is owned by the + * companion controller, khubd needs to be able to clear + * the port-change status bits (especially + * USB_PORT_FEAT_C_CONNECTION). + */ + + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + isp1760_writel(temp & ~PORT_PE, status_reg); + break; + case USB_PORT_FEAT_C_ENABLE: + /* XXX error? */ + break; + case USB_PORT_FEAT_SUSPEND: + if (temp & PORT_RESET) + goto error; + + if (temp & PORT_SUSPEND) { + if ((temp & PORT_PE) == 0) + goto error; + /* resume signaling for 20 msec */ + temp &= ~(PORT_RWC_BITS); + isp1760_writel(temp | PORT_RESUME, + status_reg); + priv->reset_done = jiffies + + msecs_to_jiffies(20); + } + break; + case USB_PORT_FEAT_C_SUSPEND: + /* we auto-clear this feature */ + break; + case USB_PORT_FEAT_POWER: + if (HCS_PPC(priv->hcs_params)) + isp1760_writel(temp & ~PORT_POWER, status_reg); + break; + case USB_PORT_FEAT_C_CONNECTION: + isp1760_writel(temp | PORT_CSC, + status_reg); + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + /* XXX error ?*/ + break; + case USB_PORT_FEAT_C_RESET: + /* GetPortStatus clears reset */ + break; + default: + goto error; + } + isp1760_readl(hcd->regs + HC_USBCMD); + break; + case GetHubDescriptor: + isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *) + buf); + break; + case GetHubStatus: + /* no hub-wide feature/status flags */ + memset(buf, 0, 4); + break; + case GetPortStatus: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + status = 0; + temp = isp1760_readl(status_reg); + + /* wPortChange bits */ + if (temp & PORT_CSC) + status |= 1 << USB_PORT_FEAT_C_CONNECTION; + + + /* whoever resumes must GetPortStatus to complete it!! */ + if (temp & PORT_RESUME) { + printk(KERN_ERR "Port resume should be skipped.\n"); + + /* Remote Wakeup received? */ + if (!priv->reset_done) { + /* resume signaling for 20 msec */ + priv->reset_done = jiffies + + msecs_to_jiffies(20); + /* check the port again */ + mod_timer(&priv_to_hcd(priv)->rh_timer, + priv->reset_done); + } + + /* resume completed? */ + else if (time_after_eq(jiffies, + priv->reset_done)) { + status |= 1 << USB_PORT_FEAT_C_SUSPEND; + priv->reset_done = 0; + + /* stop resume signaling */ + temp = isp1760_readl(status_reg); + isp1760_writel( + temp & ~(PORT_RWC_BITS | PORT_RESUME), + status_reg); + retval = handshake(priv, status_reg, + PORT_RESUME, 0, 2000 /* 2msec */); + if (retval != 0) { + isp1760_err(priv, + "port %d resume error %d\n", + wIndex + 1, retval); + goto error; + } + temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); + } + } + + /* whoever resets must GetPortStatus to complete it!! */ + if ((temp & PORT_RESET) + && time_after_eq(jiffies, + priv->reset_done)) { + status |= 1 << USB_PORT_FEAT_C_RESET; + priv->reset_done = 0; + + /* force reset to complete */ + isp1760_writel(temp & ~PORT_RESET, + status_reg); + /* REVISIT: some hardware needs 550+ usec to clear + * this bit; seems too long to spin routinely... + */ + retval = handshake(priv, status_reg, + PORT_RESET, 0, 750); + if (retval != 0) { + isp1760_err(priv, "port %d reset error %d\n", + wIndex + 1, retval); + goto error; + } + + /* see what we found out */ + temp = check_reset_complete(priv, wIndex, status_reg, + isp1760_readl(status_reg)); + } + /* + * Even if OWNER is set, there's no harm letting khubd + * see the wPortStatus values (they should all be 0 except + * for PORT_POWER anyway). + */ + + if (temp & PORT_OWNER) + printk(KERN_ERR "Warning: PORT_OWNER is set\n"); + + if (temp & PORT_CONNECT) { + status |= 1 << USB_PORT_FEAT_CONNECTION; + /* status may be from integrated TT */ + status |= ehci_port_speed(priv, temp); + } + if (temp & PORT_PE) + status |= 1 << USB_PORT_FEAT_ENABLE; + if (temp & (PORT_SUSPEND|PORT_RESUME)) + status |= 1 << USB_PORT_FEAT_SUSPEND; + if (temp & PORT_RESET) + status |= 1 << USB_PORT_FEAT_RESET; + if (temp & PORT_POWER) + status |= 1 << USB_PORT_FEAT_POWER; + + put_unaligned(cpu_to_le32(status), (__le32 *) buf); + break; + case SetHubFeature: + switch (wValue) { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* no hub-wide feature/status flags */ + break; + default: + goto error; + } + break; + case SetPortFeature: + selector = wIndex >> 8; + wIndex &= 0xff; + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = isp1760_readl(status_reg); + if (temp & PORT_OWNER) + break; + +/* temp &= ~PORT_RWC_BITS; */ + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + isp1760_writel(temp | PORT_PE, status_reg); + break; + + case USB_PORT_FEAT_SUSPEND: + if ((temp & PORT_PE) == 0 + || (temp & PORT_RESET) != 0) + goto error; + + isp1760_writel(temp | PORT_SUSPEND, status_reg); + break; + case USB_PORT_FEAT_POWER: + if (HCS_PPC(priv->hcs_params)) + isp1760_writel(temp | PORT_POWER, + status_reg); + break; + case USB_PORT_FEAT_RESET: + if (temp & PORT_RESUME) + goto error; + /* line status bits may report this as low speed, + * which can be fine if this root hub has a + * transaction translator built in. + */ + if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT + && PORT_USB11(temp)) { + temp |= PORT_OWNER; + } else { + temp |= PORT_RESET; + temp &= ~PORT_PE; + + /* + * caller must wait, then call GetPortStatus + * usb 2.0 spec says 50 ms resets on root + */ + priv->reset_done = jiffies + + msecs_to_jiffies(50); + } + isp1760_writel(temp, status_reg); + break; + default: + goto error; + } + isp1760_readl(hcd->regs + HC_USBCMD); + break; + + default: +error: + /* "stall" on error */ + retval = -EPIPE; + } + spin_unlock_irqrestore(&priv->lock, flags); + return retval; +} + +static void isp1760_endpoint_disable(struct usb_hcd *usb_hcd, + struct usb_host_endpoint *ep) +{ + struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); + struct isp1760_qh *qh; + struct isp1760_qtd *qtd; + u32 flags; + + spin_lock_irqsave(&priv->lock, flags); + qh = ep->hcpriv; + if (!qh) + goto out; + + ep->hcpriv = NULL; + do { + /* more than entry might get removed */ + if (list_empty(&qh->qtd_list)) + break; + + qtd = list_first_entry(&qh->qtd_list, struct isp1760_qtd, + qtd_list); + + if (qtd->status & URB_ENQUEUED) { + + spin_unlock_irqrestore(&priv->lock, flags); + isp1760_urb_dequeue(usb_hcd, qtd->urb, -ECONNRESET); + spin_lock_irqsave(&priv->lock, flags); + } else { + struct urb *urb; + + urb = qtd->urb; + clean_up_qtdlist(qtd); + isp1760_urb_done(priv, urb, -ECONNRESET); + } + } while (1); + + qh_destroy(qh); + /* remove requests and leak them. + * ATL are pretty fast done, INT could take a while... + * The latter shoule be removed + */ +out: + spin_unlock_irqrestore(&priv->lock, flags); +} + +static int isp1760_get_frame(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 fr; + + fr = isp1760_readl(hcd->regs + HC_FRINDEX); + return (fr >> 3) % priv->periodic_size; +} + +static void isp1760_stop(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + + isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1, + NULL, 0); + mdelay(20); + + spin_lock_irq(&priv->lock); + ehci_reset(priv); + /* Disable IRQ */ + isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL); + spin_unlock_irq(&priv->lock); + + isp1760_writel(0, hcd->regs + HC_CONFIGFLAG); +} + +static void isp1760_shutdown(struct usb_hcd *hcd) +{ + u32 command; + + isp1760_stop(hcd); + isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL); + + command = isp1760_readl(hcd->regs + HC_USBCMD); + command &= ~CMD_RUN; + isp1760_writel(command, hcd->regs + HC_USBCMD); +} + +static const struct hc_driver isp1760_hc_driver = { + .description = "isp1760-hcd", + .product_desc = "NXP ISP1760 USB Host Controller", + .hcd_priv_size = sizeof(struct isp1760_hcd), + .irq = isp1760_irq, + .flags = HCD_MEMORY | HCD_USB2, + .reset = isp1760_hc_setup, + .start = isp1760_run, + .stop = isp1760_stop, + .shutdown = isp1760_shutdown, + .urb_enqueue = isp1760_urb_enqueue, + .urb_dequeue = isp1760_urb_dequeue, + .endpoint_disable = isp1760_endpoint_disable, + .get_frame_number = isp1760_get_frame, + .hub_status_data = isp1760_hub_status_data, + .hub_control = isp1760_hub_control, +}; + +int __init init_kmem_once(void) +{ + qtd_cachep = kmem_cache_create("isp1760_qtd", + sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY | + SLAB_MEM_SPREAD, NULL); + + if (!qtd_cachep) + return -ENOMEM; + + qh_cachep = kmem_cache_create("isp1760_qh", sizeof(struct isp1760_qh), + 0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL); + + if (!qh_cachep) { + kmem_cache_destroy(qtd_cachep); + return -ENOMEM; + } + + return 0; +} + +void deinit_kmem_cache(void) +{ + kmem_cache_destroy(qtd_cachep); + kmem_cache_destroy(qh_cachep); +} + +struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq, + u64 irqflags, struct device *dev, const char *busname) +{ + struct usb_hcd *hcd; + struct isp1760_hcd *priv; + int ret; + + if (usb_disabled()) + return ERR_PTR(-ENODEV); + + /* prevent usb-core allocating DMA pages */ + dev->dma_mask = NULL; + + hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev->bus_id); + if (!hcd) + return ERR_PTR(-ENOMEM); + + priv = hcd_to_priv(hcd); + init_memory(priv); + hcd->regs = ioremap(res_start, res_len); + if (!hcd->regs) { + ret = -EIO; + goto err_put; + } + + ret = usb_add_hcd(hcd, irq, irqflags); + if (ret) + goto err_unmap; + + hcd->irq = irq; + hcd->rsrc_start = res_start; + hcd->rsrc_len = res_len; + + return hcd; + +err_unmap: + iounmap(hcd->regs); + +err_put: + usb_put_hcd(hcd); + + return ERR_PTR(ret); +} + +MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP"); +MODULE_AUTHOR("Sebastian Siewior "); +MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/usb/host/isp1760-hcd.h b/trunk/drivers/usb/host/isp1760-hcd.h new file mode 100644 index 000000000000..3d86d0f6b147 --- /dev/null +++ b/trunk/drivers/usb/host/isp1760-hcd.h @@ -0,0 +1,206 @@ +#ifndef _ISP1760_HCD_H_ +#define _ISP1760_HCD_H_ + +/* exports for if */ +struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq, + u64 irqflags, struct device *dev, const char *busname); +int init_kmem_once(void); +void deinit_kmem_cache(void); + +/* EHCI capability registers */ +#define HC_CAPLENGTH 0x00 +#define HC_HCSPARAMS 0x04 +#define HC_HCCPARAMS 0x08 + +/* EHCI operational registers */ +#define HC_USBCMD 0x20 +#define HC_USBSTS 0x24 +#define HC_FRINDEX 0x2c +#define HC_CONFIGFLAG 0x60 +#define HC_PORTSC1 0x64 +#define HC_ISO_PTD_DONEMAP_REG 0x130 +#define HC_ISO_PTD_SKIPMAP_REG 0x134 +#define HC_ISO_PTD_LASTPTD_REG 0x138 +#define HC_INT_PTD_DONEMAP_REG 0x140 +#define HC_INT_PTD_SKIPMAP_REG 0x144 +#define HC_INT_PTD_LASTPTD_REG 0x148 +#define HC_ATL_PTD_DONEMAP_REG 0x150 +#define HC_ATL_PTD_SKIPMAP_REG 0x154 +#define HC_ATL_PTD_LASTPTD_REG 0x158 + +/* Configuration Register */ +#define HC_HW_MODE_CTRL 0x300 +#define ALL_ATX_RESET (1 << 31) +#define HW_DATA_BUS_32BIT (1 << 8) +#define HW_DACK_POL_HIGH (1 << 6) +#define HW_DREQ_POL_HIGH (1 << 5) +#define HW_INTR_HIGH_ACT (1 << 2) +#define HW_INTR_EDGE_TRIG (1 << 1) +#define HW_GLOBAL_INTR_EN (1 << 0) + +#define HC_CHIP_ID_REG 0x304 +#define HC_SCRATCH_REG 0x308 + +#define HC_RESET_REG 0x30c +#define SW_RESET_RESET_HC (1 << 1) +#define SW_RESET_RESET_ALL (1 << 0) + +#define HC_BUFFER_STATUS_REG 0x334 +#define ATL_BUFFER 0x1 +#define INT_BUFFER 0x2 +#define ISO_BUFFER 0x4 +#define BUFFER_MAP 0x7 + +#define HC_MEMORY_REG 0x33c +#define HC_PORT1_CTRL 0x374 +#define PORT1_POWER (3 << 3) +#define PORT1_INIT1 (1 << 7) +#define PORT1_INIT2 (1 << 23) + +/* Interrupt Register */ +#define HC_INTERRUPT_REG 0x310 + +#define HC_INTERRUPT_ENABLE 0x314 +#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT | HC_EOT_INT) +#define FINAL_HW_CONFIG (HW_GLOBAL_INTR_EN | HW_DATA_BUS_32BIT) + +#define HC_ISO_INT (1 << 9) +#define HC_ATL_INT (1 << 8) +#define HC_INTL_INT (1 << 7) +#define HC_EOT_INT (1 << 3) +#define HC_SOT_INT (1 << 1) + +#define HC_ISO_IRQ_MASK_OR_REG 0x318 +#define HC_INT_IRQ_MASK_OR_REG 0x31C +#define HC_ATL_IRQ_MASK_OR_REG 0x320 +#define HC_ISO_IRQ_MASK_AND_REG 0x324 +#define HC_INT_IRQ_MASK_AND_REG 0x328 +#define HC_ATL_IRQ_MASK_AND_REG 0x32C + +/* Register sets */ +#define HC_BEGIN_OF_ATL 0x0c00 +#define HC_BEGIN_OF_INT 0x0800 +#define HC_BEGIN_OF_ISO 0x0400 +#define HC_BEGIN_OF_PAYLOAD 0x1000 + +/* urb state*/ +#define DELETE_URB (0x0008) +#define NO_TRANSFER_ACTIVE (0xffffffff) + +#define ATL_REGS_OFFSET (0xc00) +#define INT_REGS_OFFSET (0x800) + +/* Philips Transfer Descriptor (PTD) */ +struct ptd { + __le32 dw0; + __le32 dw1; + __le32 dw2; + __le32 dw3; + __le32 dw4; + __le32 dw5; + __le32 dw6; + __le32 dw7; +}; + +struct inter_packet_info { + void *data_buffer; + u32 payload; +#define PTD_FIRE_NEXT (1 << 0) +#define PTD_URB_FINISHED (1 << 1) + struct urb *urb; + struct isp1760_qh *qh; + struct isp1760_qtd *qtd; +}; + + +typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh, + struct isp1760_qtd *qtd); + +#define isp1760_info(priv, fmt, args...) \ + dev_info(priv_to_hcd(priv)->self.controller, fmt, ##args) + +#define isp1760_err(priv, fmt, args...) \ + dev_err(priv_to_hcd(priv)->self.controller, fmt, ##args) + +/* chip memory management */ +struct memory_chunk { + unsigned int start; + unsigned int size; + unsigned int free; +}; + +/* + * 60kb divided in: + * - 32 blocks @ 256 bytes + * - 20 blocks @ 1024 bytes + * - 4 blocks @ 8192 bytes + */ + +#define BLOCK_1_NUM 32 +#define BLOCK_2_NUM 20 +#define BLOCK_3_NUM 4 + +#define BLOCK_1_SIZE 256 +#define BLOCK_2_SIZE 1024 +#define BLOCK_3_SIZE 8192 +#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM) +#define PAYLOAD_SIZE 0xf000 + +/* I saw if some reloads if the pointer was negative */ +#define ISP1760_NULL_POINTER (0x400) + +/* ATL */ +/* DW0 */ +#define PTD_VALID 1 +#define PTD_LENGTH(x) (((u32) x) << 3) +#define PTD_MAXPACKET(x) (((u32) x) << 18) +#define PTD_MULTI(x) (((u32) x) << 29) +#define PTD_ENDPOINT(x) (((u32) x) << 31) +/* DW1 */ +#define PTD_DEVICE_ADDR(x) (((u32) x) << 3) +#define PTD_PID_TOKEN(x) (((u32) x) << 10) +#define PTD_TRANS_BULK ((u32) 2 << 12) +#define PTD_TRANS_INT ((u32) 3 << 12) +#define PTD_TRANS_SPLIT ((u32) 1 << 14) +#define PTD_SE_USB_LOSPEED ((u32) 2 << 16) +#define PTD_PORT_NUM(x) (((u32) x) << 18) +#define PTD_HUB_NUM(x) (((u32) x) << 25) +#define PTD_PING(x) (((u32) x) << 26) +/* DW2 */ +#define PTD_RL_CNT(x) (((u32) x) << 25) +#define PTD_DATA_START_ADDR(x) (((u32) x) << 8) +#define BASE_ADDR 0x1000 +/* DW3 */ +#define PTD_CERR(x) (((u32) x) << 23) +#define PTD_NAC_CNT(x) (((u32) x) << 19) +#define PTD_ACTIVE ((u32) 1 << 31) +#define PTD_DATA_TOGGLE(x) (((u32) x) << 25) + +#define DW3_HALT_BIT (1 << 30) +#define DW3_ERROR_BIT (1 << 28) +#define DW3_QTD_ACTIVE (1 << 31) + +#define INT_UNDERRUN (1 << 2) +#define INT_BABBLE (1 << 1) +#define INT_EXACT (1 << 0) + +#define DW1_GET_PID(x) (((x) >> 10) & 0x3) +#define PTD_XFERRED_LENGTH(x) ((x) & 0x7fff) +#define PTD_XFERRED_LENGTH_LO(x) ((x) & 0x7ff) + +#define SETUP_PID (2) +#define IN_PID (1) +#define OUT_PID (0) +#define GET_QTD_TOKEN_TYPE(x) ((x) & 0x3) + +#define DATA_TOGGLE (1 << 31) +#define GET_DATA_TOGGLE(x) ((x) >> 31) + +/* Errata 1 */ +#define RL_COUNTER (0) +#define NAK_COUNTER (0) +#define ERR_COUNTER (2) + +#define HC_ATL_PL_SIZE (8192) + +#endif diff --git a/trunk/drivers/usb/host/isp1760-if.c b/trunk/drivers/usb/host/isp1760-if.c new file mode 100644 index 000000000000..73fb2a38f1e4 --- /dev/null +++ b/trunk/drivers/usb/host/isp1760-if.c @@ -0,0 +1,298 @@ +/* + * Glue code for the ISP1760 driver and bus + * Currently there is support for + * - OpenFirmware + * - PCI + * + * (c) 2007 Sebastian Siewior + * + */ + +#include +#include + +#include "../core/hcd.h" +#include "isp1760-hcd.h" + +#ifdef CONFIG_USB_ISP1760_OF +#include +#include +#endif + +#ifdef CONFIG_USB_ISP1760_PCI +#include +#endif + +#ifdef CONFIG_USB_ISP1760_OF +static int of_isp1760_probe(struct of_device *dev, + const struct of_device_id *match) +{ + struct usb_hcd *hcd; + struct device_node *dp = dev->node; + struct resource *res; + struct resource memory; + struct of_irq oirq; + int virq; + u64 res_len; + int ret; + + ret = of_address_to_resource(dp, 0, &memory); + if (ret) + return -ENXIO; + + res = request_mem_region(memory.start, memory.end - memory.start + 1, + dev->dev.bus_id); + if (!res) + return -EBUSY; + + res_len = memory.end - memory.start + 1; + + if (of_irq_map_one(dp, 0, &oirq)) { + ret = -ENODEV; + goto release_reg; + } + + virq = irq_create_of_mapping(oirq.controller, oirq.specifier, + oirq.size); + + hcd = isp1760_register(memory.start, res_len, virq, + IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id); + if (IS_ERR(hcd)) { + ret = PTR_ERR(hcd); + goto release_reg; + } + + dev_set_drvdata(&dev->dev, hcd); + return ret; + +release_reg: + release_mem_region(memory.start, memory.end - memory.start + 1); + return ret; +} + +static int of_isp1760_remove(struct of_device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(&dev->dev); + + dev_set_drvdata(&dev->dev, NULL); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + return 0; +} + +static struct of_device_id of_isp1760_match[] = { + { + .compatible = "nxp,usb-isp1760", + }, + { }, +}; +MODULE_DEVICE_TABLE(of, of_isp1760_match); + +static struct of_platform_driver isp1760_of_driver = { + .name = "nxp-isp1760", + .match_table = of_isp1760_match, + .probe = of_isp1760_probe, + .remove = of_isp1760_remove, +}; +#endif + +#ifdef CONFIG_USB_ISP1760_PCI +static u32 nxp_pci_io_base; +static u32 iolength; +static u32 pci_mem_phy0; +static u32 length; +static u8 *chip_addr; +static u8 *iobase; + +static int __devinit isp1761_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + u8 latency, limit; + __u32 reg_data; + int retry_count; + int length; + int status = 1; + struct usb_hcd *hcd; + + if (usb_disabled()) + return -ENODEV; + + if (pci_enable_device(dev) < 0) + return -ENODEV; + + if (!dev->irq) + return -ENODEV; + + /* Grab the PLX PCI mem maped port start address we need */ + nxp_pci_io_base = pci_resource_start(dev, 0); + iolength = pci_resource_len(dev, 0); + + if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) { + printk(KERN_ERR "request region #1\n"); + return -EBUSY; + } + + iobase = ioremap_nocache(nxp_pci_io_base, iolength); + if (!iobase) { + printk(KERN_ERR "ioremap #1\n"); + release_mem_region(nxp_pci_io_base, iolength); + return -ENOMEM; + } + /* Grab the PLX PCI shared memory of the ISP 1761 we need */ + pci_mem_phy0 = pci_resource_start(dev, 3); + length = pci_resource_len(dev, 3); + + if (length < 0xffff) { + printk(KERN_ERR "memory length for this resource is less than " + "required\n"); + release_mem_region(nxp_pci_io_base, iolength); + iounmap(iobase); + return -ENOMEM; + } + + if (!request_mem_region(pci_mem_phy0, length, "ISP-PCI")) { + printk(KERN_ERR "host controller already in use\n"); + release_mem_region(nxp_pci_io_base, iolength); + iounmap(iobase); + return -EBUSY; + } + + /* bad pci latencies can contribute to overruns */ + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency); + if (latency) { + pci_read_config_byte(dev, PCI_MAX_LAT, &limit); + if (limit && limit < latency) + pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit); + } + + /* Try to check whether we can access Scratch Register of + * Host Controller or not. The initial PCI access is retried until + * local init for the PCI bridge is completed + */ + retry_count = 20; + reg_data = 0; + while ((reg_data != 0xFACE) && retry_count) { + /*by default host is in 16bit mode, so + * io operations at this stage must be 16 bit + * */ + writel(0xface, chip_addr + HC_SCRATCH_REG); + udelay(100); + reg_data = readl(chip_addr + HC_SCRATCH_REG); + retry_count--; + } + + /* Host Controller presence is detected by writing to scratch register + * and reading back and checking the contents are same or not + */ + if (reg_data != 0xFACE) { + err("scratch register mismatch %x", reg_data); + goto clean; + } + + pci_set_master(dev); + + status = readl(iobase + 0x68); + status |= 0x900; + writel(status, iobase + 0x68); + + dev->dev.dma_mask = NULL; + hcd = isp1760_register(pci_mem_phy0, length, dev->irq, + IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id); + pci_set_drvdata(dev, hcd); + if (!hcd) + return 0; +clean: + status = -ENODEV; + iounmap(iobase); + release_mem_region(pci_mem_phy0, length); + release_mem_region(nxp_pci_io_base, iolength); + return status; +} +static void isp1761_pci_remove(struct pci_dev *dev) +{ + struct usb_hcd *hcd; + + hcd = pci_get_drvdata(dev); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + + pci_disable_device(dev); + + iounmap(iobase); + iounmap(chip_addr); + + release_mem_region(nxp_pci_io_base, iolength); + release_mem_region(pci_mem_phy0, length); +} + +static void isp1761_pci_shutdown(struct pci_dev *dev) +{ + printk(KERN_ERR "ips1761_pci_shutdown\n"); +} + +static const struct pci_device_id isp1760_plx [] = { { + /* handle any USB 2.0 EHCI controller */ + PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_OTHER << 8) | (0x06 << 16)), ~0), + .driver_data = 0, +}, +{ /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE(pci, isp1760_plx); + +static struct pci_driver isp1761_pci_driver = { + .name = "isp1760", + .id_table = isp1760_plx, + .probe = isp1761_pci_probe, + .remove = isp1761_pci_remove, + .shutdown = isp1761_pci_shutdown, +}; +#endif + +static int __init isp1760_init(void) +{ + int ret; + + init_kmem_once(); + +#ifdef CONFIG_USB_ISP1760_OF + ret = of_register_platform_driver(&isp1760_of_driver); + if (ret) { + deinit_kmem_cache(); + return ret; + } +#endif +#ifdef CONFIG_USB_ISP1760_PCI + ret = pci_register_driver(&isp1761_pci_driver); + if (ret) + goto unreg_of; +#endif + return ret; + +#ifdef CONFIG_USB_ISP1760_PCI +unreg_of: +#endif +#ifdef CONFIG_USB_ISP1760_OF + of_unregister_platform_driver(&isp1760_of_driver); +#endif + deinit_kmem_cache(); + return ret; +} +module_init(isp1760_init); + +static void __exit isp1760_exit(void) +{ +#ifdef CONFIG_USB_ISP1760_OF + of_unregister_platform_driver(&isp1760_of_driver); +#endif +#ifdef CONFIG_USB_ISP1760_PCI + pci_unregister_driver(&isp1761_pci_driver); +#endif + deinit_kmem_cache(); +} +module_exit(isp1760_exit); diff --git a/trunk/drivers/virtio/virtio.c b/trunk/drivers/virtio/virtio.c index 13866789b356..b535483bc556 100644 --- a/trunk/drivers/virtio/virtio.c +++ b/trunk/drivers/virtio/virtio.c @@ -80,51 +80,19 @@ static void add_status(struct virtio_device *dev, unsigned status) dev->config->set_status(dev, dev->config->get_status(dev) | status); } -void virtio_check_driver_offered_feature(const struct virtio_device *vdev, - unsigned int fbit) -{ - unsigned int i; - struct virtio_driver *drv = container_of(vdev->dev.driver, - struct virtio_driver, driver); - - for (i = 0; i < drv->feature_table_size; i++) - if (drv->feature_table[i] == fbit) - return; - BUG(); -} -EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature); - static int virtio_dev_probe(struct device *_d) { - int err, i; + int err; struct virtio_device *dev = container_of(_d,struct virtio_device,dev); struct virtio_driver *drv = container_of(dev->dev.driver, struct virtio_driver, driver); - u32 device_features; - /* We have a driver! */ add_status(dev, VIRTIO_CONFIG_S_DRIVER); - - /* Figure out what features the device supports. */ - device_features = dev->config->get_features(dev); - - /* Features supported by both device and driver into dev->features. */ - memset(dev->features, 0, sizeof(dev->features)); - for (i = 0; i < drv->feature_table_size; i++) { - unsigned int f = drv->feature_table[i]; - BUG_ON(f >= 32); - if (device_features & (1 << f)) - set_bit(f, dev->features); - } - err = drv->probe(dev); if (err) add_status(dev, VIRTIO_CONFIG_S_FAILED); - else { + else add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); - /* They should never have set feature bits beyond 32 */ - dev->config->set_features(dev, dev->features[0]); - } return err; } @@ -146,8 +114,6 @@ static int virtio_dev_remove(struct device *_d) int register_virtio_driver(struct virtio_driver *driver) { - /* Catch this early. */ - BUG_ON(driver->feature_table_size && !driver->feature_table); driver->driver.bus = &virtio_bus; driver->driver.probe = virtio_dev_probe; driver->driver.remove = virtio_dev_remove; diff --git a/trunk/drivers/virtio/virtio_balloon.c b/trunk/drivers/virtio/virtio_balloon.c index bfef604160d1..0b3efc31ee6d 100644 --- a/trunk/drivers/virtio/virtio_balloon.c +++ b/trunk/drivers/virtio/virtio_balloon.c @@ -155,9 +155,9 @@ static void virtballoon_changed(struct virtio_device *vdev) static inline s64 towards_target(struct virtio_balloon *vb) { u32 v; - vb->vdev->config->get(vb->vdev, - offsetof(struct virtio_balloon_config, num_pages), - &v, sizeof(v)); + __virtio_config_val(vb->vdev, + offsetof(struct virtio_balloon_config, num_pages), + &v); return v - vb->num_pages; } @@ -227,7 +227,7 @@ static int virtballoon_probe(struct virtio_device *vdev) } vb->tell_host_first - = virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST); + = vdev->config->feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST); return 0; @@ -259,11 +259,7 @@ static void virtballoon_remove(struct virtio_device *vdev) kfree(vb); } -static unsigned int features[] = { VIRTIO_BALLOON_F_MUST_TELL_HOST }; - static struct virtio_driver virtio_balloon = { - .feature_table = features, - .feature_table_size = ARRAY_SIZE(features), .driver.name = KBUILD_MODNAME, .driver.owner = THIS_MODULE, .id_table = id_table, diff --git a/trunk/drivers/virtio/virtio_pci.c b/trunk/drivers/virtio/virtio_pci.c index 27e9fc9117cd..c0df924766a7 100644 --- a/trunk/drivers/virtio/virtio_pci.c +++ b/trunk/drivers/virtio/virtio_pci.c @@ -87,22 +87,23 @@ static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev) return container_of(vdev, struct virtio_pci_device, vdev); } -/* virtio config->get_features() implementation */ -static u32 vp_get_features(struct virtio_device *vdev) -{ - struct virtio_pci_device *vp_dev = to_vp_device(vdev); - - /* When someone needs more than 32 feature bits, we'll need to - * steal a bit to indicate that the rest are somewhere else. */ - return ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES); -} - -/* virtio config->set_features() implementation */ -static void vp_set_features(struct virtio_device *vdev, u32 features) +/* virtio config->feature() implementation */ +static bool vp_feature(struct virtio_device *vdev, unsigned bit) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); + u32 mask; + + /* Since this function is supposed to have the side effect of + * enabling a queried feature, we simulate that by doing a read + * from the host feature bitmask and then writing to the guest + * feature bitmask */ + mask = ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES); + if (mask & (1 << bit)) { + mask |= (1 << bit); + iowrite32(mask, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES); + } - iowrite32(features, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES); + return !!(mask & (1 << bit)); } /* virtio config->get() implementation */ @@ -144,14 +145,14 @@ static void vp_set_status(struct virtio_device *vdev, u8 status) struct virtio_pci_device *vp_dev = to_vp_device(vdev); /* We should never be setting status to 0. */ BUG_ON(status == 0); - iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS); + return iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS); } static void vp_reset(struct virtio_device *vdev) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); /* 0 status means a reset. */ - iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS); + return iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS); } /* the notify function used when creating a virt queue */ @@ -292,6 +293,7 @@ static void vp_del_vq(struct virtqueue *vq) } static struct virtio_config_ops virtio_pci_config_ops = { + .feature = vp_feature, .get = vp_get, .set = vp_set, .get_status = vp_get_status, @@ -299,8 +301,6 @@ static struct virtio_config_ops virtio_pci_config_ops = { .reset = vp_reset, .find_vq = vp_find_vq, .del_vq = vp_del_vq, - .get_features = vp_get_features, - .set_features = vp_set_features, }; /* the PCI probing function */ diff --git a/trunk/drivers/virtio/virtio_ring.c b/trunk/drivers/virtio/virtio_ring.c index 937a49d6772c..c2fa5c630813 100644 --- a/trunk/drivers/virtio/virtio_ring.c +++ b/trunk/drivers/virtio/virtio_ring.c @@ -184,11 +184,6 @@ static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len) START_USE(vq); - if (unlikely(vq->broken)) { - END_USE(vq); - return NULL; - } - if (!more_used(vq)) { pr_debug("No more buffers in queue\n"); END_USE(vq); diff --git a/trunk/include/asm-ia64/cpu.h b/trunk/include/asm-ia64/cpu.h index fcca30b9f110..e87fa3210a2b 100644 --- a/trunk/include/asm-ia64/cpu.h +++ b/trunk/include/asm-ia64/cpu.h @@ -14,8 +14,8 @@ DECLARE_PER_CPU(struct ia64_cpu, cpu_devices); DECLARE_PER_CPU(int, cpu_state); -#ifdef CONFIG_HOTPLUG_CPU extern int arch_register_cpu(int num); +#ifdef CONFIG_HOTPLUG_CPU extern void arch_unregister_cpu(int); #endif diff --git a/trunk/include/asm-ia64/thread_info.h b/trunk/include/asm-ia64/thread_info.h index 2422ac61658a..f30e05583869 100644 --- a/trunk/include/asm-ia64/thread_info.h +++ b/trunk/include/asm-ia64/thread_info.h @@ -108,11 +108,13 @@ extern void tsk_clear_notify_resume(struct task_struct *tsk); #define TIF_DB_DISABLED 19 /* debug trap disabled for fsyscall */ #define TIF_FREEZE 20 /* is freezing for suspend */ #define TIF_RESTORE_RSE 21 /* user RBS is newer than kernel RBS */ +#define TIF_RESTORE_SIGMASK 22 /* restore signal mask in do_signal() */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) #define _TIF_SYSCALL_TRACEAUDIT (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP) +#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) @@ -129,18 +131,7 @@ extern void tsk_clear_notify_resume(struct task_struct *tsk); #define TIF_WORK_MASK (TIF_ALLWORK_MASK&~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)) #define TS_POLLING 1 /* true if in idle loop and not sleeping */ -#define TS_RESTORE_SIGMASK 2 /* restore signal mask in do_signal() */ #define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING) -#ifndef __ASSEMBLY__ -#define HAVE_SET_RESTORE_SIGMASK 1 -static inline void set_restore_sigmask(void) -{ - struct thread_info *ti = current_thread_info(); - ti->status |= TS_RESTORE_SIGMASK; - set_bit(TIF_SIGPENDING, &ti->flags); -} -#endif /* !__ASSEMBLY__ */ - #endif /* _ASM_IA64_THREAD_INFO_H */ diff --git a/trunk/include/linux/Kbuild b/trunk/include/linux/Kbuild index b7d81b2a9041..78fade0a1e35 100644 --- a/trunk/include/linux/Kbuild +++ b/trunk/include/linux/Kbuild @@ -346,11 +346,6 @@ unifdef-y += videodev.h unifdef-y += virtio_config.h unifdef-y += virtio_blk.h unifdef-y += virtio_net.h -unifdef-y += virtio_9p.h -unifdef-y += virtio_balloon.h -unifdef-y += virtio_console.h -unifdef-y += virtio_pci.h -unifdef-y += virtio_ring.h unifdef-y += vt.h unifdef-y += wait.h unifdef-y += wanrouter.h diff --git a/trunk/include/linux/device.h b/trunk/include/linux/device.h index 8c23e3dfe3ac..832fb0eb2933 100644 --- a/trunk/include/linux/device.h +++ b/trunk/include/linux/device.h @@ -380,12 +380,6 @@ struct device { /* Get the wakeup routines, which depend on struct device */ #include -static inline const char *dev_name(struct device *dev) -{ - /* will be changed into kobject_name(&dev->kobj) in the near future */ - return dev->bus_id; -} - #ifdef CONFIG_NUMA static inline int dev_to_node(struct device *dev) { @@ -484,7 +478,7 @@ extern void sysdev_shutdown(void); extern const char *dev_driver_string(struct device *dev); #define dev_printk(level, dev, format, arg...) \ printk(level "%s %s: " format , dev_driver_string(dev) , \ - dev_name(dev) , ## arg) + (dev)->bus_id , ## arg) #define dev_emerg(dev, format, arg...) \ dev_printk(KERN_EMERG , dev , format , ## arg) diff --git a/trunk/include/linux/irq.h b/trunk/include/linux/irq.h index 552e0ec269c9..1883a85625dd 100644 --- a/trunk/include/linux/irq.h +++ b/trunk/include/linux/irq.h @@ -61,7 +61,6 @@ typedef void (*irq_flow_handler_t)(unsigned int irq, #define IRQ_WAKEUP 0x00100000 /* IRQ triggers system wakeup */ #define IRQ_MOVE_PENDING 0x00200000 /* need to re-target IRQ destination */ #define IRQ_NO_BALANCING 0x00400000 /* IRQ is excluded from balancing */ -#define IRQ_SPURIOUS_DISABLED 0x00800000 /* IRQ was disabled by the spurious trap */ #ifdef CONFIG_IRQ_PER_CPU # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU) diff --git a/trunk/include/linux/virtio.h b/trunk/include/linux/virtio.h index 06005fa9e982..e7d10845b3c1 100644 --- a/trunk/include/linux/virtio.h +++ b/trunk/include/linux/virtio.h @@ -76,7 +76,6 @@ struct virtqueue_ops { * @dev: underlying device. * @id: the device type identification (used to match it with a driver). * @config: the configuration ops for this device. - * @features: the features supported by both driver and device. * @priv: private pointer for the driver's use. */ struct virtio_device @@ -85,8 +84,6 @@ struct virtio_device struct device dev; struct virtio_device_id id; struct virtio_config_ops *config; - /* Note that this is a Linux set_bit-style bitmap. */ - unsigned long features[1]; void *priv; }; @@ -97,8 +94,6 @@ void unregister_virtio_device(struct virtio_device *dev); * virtio_driver - operations for a virtio I/O driver * @driver: underlying device driver (populate name and owner). * @id_table: the ids serviced by this driver. - * @feature_table: an array of feature numbers supported by this device. - * @feature_table_size: number of entries in the feature table array. * @probe: the function to call when a device is found. Returns a token for * remove, or PTR_ERR(). * @remove: the function when a device is removed. @@ -108,8 +103,6 @@ void unregister_virtio_device(struct virtio_device *dev); struct virtio_driver { struct device_driver driver; const struct virtio_device_id *id_table; - const unsigned int *feature_table; - unsigned int feature_table_size; int (*probe)(struct virtio_device *dev); void (*remove)(struct virtio_device *dev); void (*config_changed)(struct virtio_device *dev); diff --git a/trunk/include/linux/virtio_blk.h b/trunk/include/linux/virtio_blk.h index d4695a3356d0..bca0b10d7947 100644 --- a/trunk/include/linux/virtio_blk.h +++ b/trunk/include/linux/virtio_blk.h @@ -9,7 +9,6 @@ #define VIRTIO_BLK_F_BARRIER 0 /* Does host support barriers? */ #define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */ #define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */ -#define VIRTIO_BLK_F_GEOMETRY 4 /* Legacy geometry available */ struct virtio_blk_config { @@ -19,12 +18,6 @@ struct virtio_blk_config __le32 size_max; /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */ __le32 seg_max; - /* geometry the device (if VIRTIO_BLK_F_GEOMETRY) */ - struct virtio_blk_geometry { - __le16 cylinders; - __u8 heads; - __u8 sectors; - } geometry; } __attribute__((packed)); /* These two define direction. */ @@ -48,8 +41,13 @@ struct virtio_blk_outhdr __u64 sector; }; -/* And this is the final byte of the write scatter-gather list. */ #define VIRTIO_BLK_S_OK 0 #define VIRTIO_BLK_S_IOERR 1 #define VIRTIO_BLK_S_UNSUPP 2 + +/* This is the first element of the write scatter-gather list */ +struct virtio_blk_inhdr +{ + unsigned char status; +}; #endif /* _LINUX_VIRTIO_BLK_H */ diff --git a/trunk/include/linux/virtio_config.h b/trunk/include/linux/virtio_config.h index 50db245c81ad..d581b2914b34 100644 --- a/trunk/include/linux/virtio_config.h +++ b/trunk/include/linux/virtio_config.h @@ -16,20 +16,27 @@ #define VIRTIO_CONFIG_S_FAILED 0x80 #ifdef __KERNEL__ -#include +struct virtio_device; /** * virtio_config_ops - operations for configuring a virtio device + * @feature: search for a feature in this config + * vdev: the virtio_device + * bit: the feature bit + * Returns true if the feature is supported. Acknowledges the feature + * so the host can see it. * @get: read the value of a configuration field * vdev: the virtio_device * offset: the offset of the configuration field * buf: the buffer to write the field value into. * len: the length of the buffer + * Note that contents are conventionally little-endian. * @set: write the value of a configuration field * vdev: the virtio_device * offset: the offset of the configuration field * buf: the buffer to read the field value from. * len: the length of the buffer + * Note that contents are conventionally little-endian. * @get_status: read the status byte * vdev: the virtio_device * Returns the status byte @@ -45,15 +52,10 @@ * callback: the virqtueue callback * Returns the new virtqueue or ERR_PTR() (eg. -ENOENT). * @del_vq: free a virtqueue found by find_vq(). - * @get_features: get the array of feature bits for this device. - * vdev: the virtio_device - * Returns the first 32 feature bits (all we currently need). - * @set_features: confirm what device features we'll be using. - * vdev: the virtio_device - * feature: the first 32 feature bits */ struct virtio_config_ops { + bool (*feature)(struct virtio_device *vdev, unsigned bit); void (*get)(struct virtio_device *vdev, unsigned offset, void *buf, unsigned len); void (*set)(struct virtio_device *vdev, unsigned offset, @@ -65,52 +67,43 @@ struct virtio_config_ops unsigned index, void (*callback)(struct virtqueue *)); void (*del_vq)(struct virtqueue *vq); - u32 (*get_features)(struct virtio_device *vdev); - void (*set_features)(struct virtio_device *vdev, u32 features); }; -/* If driver didn't advertise the feature, it will never appear. */ -void virtio_check_driver_offered_feature(const struct virtio_device *vdev, - unsigned int fbit); - /** - * virtio_has_feature - helper to determine if this device has this feature. - * @vdev: the device - * @fbit: the feature bit - */ -static inline bool virtio_has_feature(const struct virtio_device *vdev, - unsigned int fbit) -{ - /* Did you forget to fix assumptions on max features? */ - if (__builtin_constant_p(fbit)) - BUILD_BUG_ON(fbit >= 32); - - virtio_check_driver_offered_feature(vdev, fbit); - return test_bit(fbit, vdev->features); -} - -/** - * virtio_config_val - look for a feature and get a virtio config entry. + * virtio_config_val - look for a feature and get a single virtio config. * @vdev: the virtio device * @fbit: the feature bit * @offset: the type to search for. * @val: a pointer to the value to fill in. * * The return value is -ENOENT if the feature doesn't exist. Otherwise - * the config value is copied into whatever is pointed to by v. */ -#define virtio_config_val(vdev, fbit, offset, v) \ - virtio_config_buf((vdev), (fbit), (offset), (v), sizeof(v)) - -static inline int virtio_config_buf(struct virtio_device *vdev, - unsigned int fbit, - unsigned int offset, - void *buf, unsigned len) -{ - if (!virtio_has_feature(vdev, fbit)) - return -ENOENT; + * the value is endian-corrected and returned in v. */ +#define virtio_config_val(vdev, fbit, offset, v) ({ \ + int _err; \ + if ((vdev)->config->feature((vdev), (fbit))) { \ + __virtio_config_val((vdev), (offset), (v)); \ + _err = 0; \ + } else \ + _err = -ENOENT; \ + _err; \ +}) - vdev->config->get(vdev, offset, buf, len); - return 0; -} +/** + * __virtio_config_val - get a single virtio config without feature check. + * @vdev: the virtio device + * @offset: the type to search for. + * @val: a pointer to the value to fill in. + * + * The value is endian-corrected and returned in v. */ +#define __virtio_config_val(vdev, offset, v) do { \ + BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2 \ + && sizeof(*(v)) != 4 && sizeof(*(v)) != 8); \ + (vdev)->config->get((vdev), (offset), (v), sizeof(*(v))); \ + switch (sizeof(*(v))) { \ + case 2: le16_to_cpus((__u16 *) v); break; \ + case 4: le32_to_cpus((__u32 *) v); break; \ + case 8: le64_to_cpus((__u64 *) v); break; \ + } \ +} while(0) #endif /* __KERNEL__ */ #endif /* _LINUX_VIRTIO_CONFIG_H */ diff --git a/trunk/include/linux/virtio_net.h b/trunk/include/linux/virtio_net.h index 9405aa6cdf26..1ea3351df609 100644 --- a/trunk/include/linux/virtio_net.h +++ b/trunk/include/linux/virtio_net.h @@ -6,18 +6,9 @@ #define VIRTIO_ID_NET 1 /* The feature bitmap for virtio net */ -#define VIRTIO_NET_F_CSUM 0 /* Host handles pkts w/ partial csum */ -#define VIRTIO_NET_F_GUEST_CSUM 1 /* Guest handles pkts w/ partial csum */ +#define VIRTIO_NET_F_CSUM 0 /* Can handle pkts w/ partial csum */ #define VIRTIO_NET_F_MAC 5 /* Host has given MAC address. */ -#define VIRTIO_NET_F_GSO 6 /* Host handles pkts w/ any GSO type */ -#define VIRTIO_NET_F_GUEST_TSO4 7 /* Guest can handle TSOv4 in. */ -#define VIRTIO_NET_F_GUEST_TSO6 8 /* Guest can handle TSOv6 in. */ -#define VIRTIO_NET_F_GUEST_ECN 9 /* Guest can handle TSO[6] w/ ECN in. */ -#define VIRTIO_NET_F_GUEST_UFO 10 /* Guest can handle UFO in. */ -#define VIRTIO_NET_F_HOST_TSO4 11 /* Host can handle TSOv4 in. */ -#define VIRTIO_NET_F_HOST_TSO6 12 /* Host can handle TSOv6 in. */ -#define VIRTIO_NET_F_HOST_ECN 13 /* Host can handle TSO[6] w/ ECN in. */ -#define VIRTIO_NET_F_HOST_UFO 14 /* Host can handle UFO in. */ +#define VIRTIO_NET_F_GSO 6 /* Can handle pkts w/ any GSO type */ struct virtio_net_config { diff --git a/trunk/kernel/irq/manage.c b/trunk/kernel/irq/manage.c index 46d6611a33bb..46e4ad1723f0 100644 --- a/trunk/kernel/irq/manage.c +++ b/trunk/kernel/irq/manage.c @@ -150,26 +150,6 @@ void disable_irq(unsigned int irq) } EXPORT_SYMBOL(disable_irq); -static void __enable_irq(struct irq_desc *desc, unsigned int irq) -{ - switch (desc->depth) { - case 0: - printk(KERN_WARNING "Unbalanced enable for IRQ %d\n", irq); - WARN_ON(1); - break; - case 1: { - unsigned int status = desc->status & ~IRQ_DISABLED; - - /* Prevent probing on this irq: */ - desc->status = status | IRQ_NOPROBE; - check_irq_resend(desc, irq); - /* fall-through */ - } - default: - desc->depth--; - } -} - /** * enable_irq - enable handling of an irq * @irq: Interrupt to enable @@ -189,7 +169,22 @@ void enable_irq(unsigned int irq) return; spin_lock_irqsave(&desc->lock, flags); - __enable_irq(desc, irq); + switch (desc->depth) { + case 0: + printk(KERN_WARNING "Unbalanced enable for IRQ %d\n", irq); + WARN_ON(1); + break; + case 1: { + unsigned int status = desc->status & ~IRQ_DISABLED; + + /* Prevent probing on this irq: */ + desc->status = status | IRQ_NOPROBE; + check_irq_resend(desc, irq); + /* fall-through */ + } + default: + desc->depth--; + } spin_unlock_irqrestore(&desc->lock, flags); } EXPORT_SYMBOL(enable_irq); @@ -370,7 +365,7 @@ int setup_irq(unsigned int irq, struct irqaction *new) compat_irq_chip_set_default_handler(desc); desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | - IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED); + IRQ_INPROGRESS); if (!(desc->status & IRQ_NOAUTOEN)) { desc->depth = 0; @@ -386,16 +381,6 @@ int setup_irq(unsigned int irq, struct irqaction *new) /* Reset broken irq detection when installing new handler */ desc->irq_count = 0; desc->irqs_unhandled = 0; - - /* - * Check whether we disabled the irq via the spurious handler - * before. Reenable it and give it another chance. - */ - if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) { - desc->status &= ~IRQ_SPURIOUS_DISABLED; - __enable_irq(desc, irq); - } - spin_unlock_irqrestore(&desc->lock, flags); new->irq = irq; diff --git a/trunk/kernel/irq/spurious.c b/trunk/kernel/irq/spurious.c index c66d3f10e853..088dabbf2d6a 100644 --- a/trunk/kernel/irq/spurious.c +++ b/trunk/kernel/irq/spurious.c @@ -209,8 +209,8 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc, * Now kill the IRQ */ printk(KERN_EMERG "Disabling IRQ #%d\n", irq); - desc->status |= IRQ_DISABLED | IRQ_SPURIOUS_DISABLED; - desc->depth++; + desc->status |= IRQ_DISABLED; + desc->depth = 1; desc->chip->disable(irq); } desc->irqs_unhandled = 0;