From 354e57f3a0a26120af3bcd6c92c355ad00a057c1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 7 Nov 2013 10:25:55 +0100 Subject: ARM/serial: at91: switch atmel serial to use gpiolib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This passes the errata fix using a GPIO to control the RTS pin on one of the AT91 chips to use gpiolib instead of the AT91-specific interfaces. Also remove the reliance on compile-time #defines and the cpu_* check and rely on the platform passing down the proper GPIO pin through platform data. This is a prerequisite for getting rid of the local GPIO implementation in the AT91 platform and move toward multiplatform. The patch also adds device tree support for getting the RTS GPIO pin from the device tree on DT boot paths. Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Linus Walleij Acked-by: Greg Kroah-Hartman Signed-off-by: Uwe Kleine-König --- include/linux/platform_data/atmel.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/platform_data/atmel.h b/include/linux/platform_data/atmel.h index cea9f70133c5..e26b0c14edea 100644 --- a/include/linux/platform_data/atmel.h +++ b/include/linux/platform_data/atmel.h @@ -84,6 +84,7 @@ struct atmel_uart_data { short use_dma_rx; /* use receive DMA? */ void __iomem *regs; /* virt. base address, if any */ struct serial_rs485 rs485; /* rs485 settings */ + int rts_gpio; /* optional RTS GPIO */ }; /* Touchscreen Controller */ -- cgit v1.3-8-gc7d7 From cd4dc0821bc97947f25c8483a4aa0711bff8619a Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Wed, 22 Jan 2014 13:49:41 -0500 Subject: HID: Add transport-driver callbacks to the hid_ll_driver struct Add raw_request and output_report callbacks to the hid_ll_driver struct. Signed-off-by: Frank Praznik Acked-by: David Herrmann Signed-off-by: Jiri Kosina --- include/linux/hid.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/hid.h b/include/linux/hid.h index 31b9d299ef6c..003cc8e89831 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -700,8 +700,14 @@ struct hid_ll_driver { struct hid_report *report, int reqtype); int (*wait)(struct hid_device *hdev); - int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype); + int (*raw_request) (struct hid_device *hdev, unsigned char reportnum, + __u8 *buf, size_t len, unsigned char rtype, + int reqtype); + + int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len); + + int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype); }; #define PM_HINT_FULLON 1<<5 -- cgit v1.3-8-gc7d7 From c05c4186bbe4e99d64e8a36f7ca7f480da5d109f Mon Sep 17 00:00:00 2001 From: Jens Freimann Date: Mon, 7 Oct 2013 16:13:45 +0200 Subject: KVM: s390: add floating irq controller This patch adds a floating irq controller as a kvm_device. It will be necessary for migration of floating interrupts as well as for hardening the reset code by allowing user space to explicitly remove all pending floating interrupts. Signed-off-by: Jens Freimann Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- Documentation/virtual/kvm/devices/s390_flic.txt | 36 +++ arch/s390/include/asm/kvm_host.h | 1 + arch/s390/include/uapi/asm/kvm.h | 14 ++ arch/s390/kvm/interrupt.c | 304 ++++++++++++++++++++---- arch/s390/kvm/kvm-s390.c | 1 + include/linux/kvm_host.h | 1 + include/uapi/linux/kvm.h | 1 + virt/kvm/kvm_main.c | 5 + 8 files changed, 312 insertions(+), 51 deletions(-) create mode 100644 Documentation/virtual/kvm/devices/s390_flic.txt (limited to 'include/linux') diff --git a/Documentation/virtual/kvm/devices/s390_flic.txt b/Documentation/virtual/kvm/devices/s390_flic.txt new file mode 100644 index 000000000000..6b557953066a --- /dev/null +++ b/Documentation/virtual/kvm/devices/s390_flic.txt @@ -0,0 +1,36 @@ +FLIC (floating interrupt controller) +==================================== + +FLIC handles floating (non per-cpu) interrupts, i.e. I/O, service and some +machine check interruptions. All interrupts are stored in a per-vm list of +pending interrupts. FLIC performs operations on this list. + +Only one FLIC instance may be instantiated. + +FLIC provides support to +- add interrupts (KVM_DEV_FLIC_ENQUEUE) +- inspect currently pending interrupts (KVM_FLIC_GET_ALL_IRQS) +- purge all pending floating interrupts (KVM_DEV_FLIC_CLEAR_IRQS) + +Groups: + KVM_DEV_FLIC_ENQUEUE + Passes a buffer and length into the kernel which are then injected into + the list of pending interrupts. + attr->addr contains the pointer to the buffer and attr->attr contains + the length of the buffer. + The format of the data structure kvm_s390_irq as it is copied from userspace + is defined in usr/include/linux/kvm.h. + + KVM_DEV_FLIC_GET_ALL_IRQS + Copies all floating interrupts into a buffer provided by userspace. + When the buffer is too small it returns -ENOMEM, which is the indication + for userspace to try again with a bigger buffer. + All interrupts remain pending, i.e. are not deleted from the list of + currently pending interrupts. + attr->addr contains the userspace address of the buffer into which all + interrupt data will be copied. + attr->attr contains the size of the buffer in bytes. + + KVM_DEV_FLIC_CLEAR_IRQS + Simply deletes all elements from the list of currently pending floating + interrupts. No interrupts are injected into the guest. diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 3ffc9646e742..59635b5c59a6 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -243,6 +243,7 @@ struct kvm_arch{ struct sca_block *sca; debug_info_t *dbf; struct kvm_s390_float_interrupt float_int; + struct kvm_device *flic; struct gmap *gmap; int css_support; }; diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h index d25da598ec62..38d5f98552bb 100644 --- a/arch/s390/include/uapi/asm/kvm.h +++ b/arch/s390/include/uapi/asm/kvm.h @@ -16,6 +16,20 @@ #define __KVM_S390 +/* Device control API: s390-specific devices */ +#define KVM_DEV_FLIC_GET_ALL_IRQS 1 +#define KVM_DEV_FLIC_ENQUEUE 2 +#define KVM_DEV_FLIC_CLEAR_IRQS 3 +/* + * We can have up to 4*64k pending subchannels + 8 adapter interrupts, + * as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts. + * There are also sclp and machine checks. This gives us + * sizeof(kvm_s390_irq)*(4*65536+8+64*64+1+1) = 72 * 266250 = 19170000 + * Lets round up to 8192 pages. + */ + +#define KVM_S390_FLIC_MAX_BUFFER 0x2000000 + /* for KVM_GET_REGS and KVM_SET_REGS */ struct kvm_regs { /* general purpose regs for s390 */ diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 5f79d2d79ca7..a5f18babed4c 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -659,53 +659,86 @@ struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm, return inti; } -int kvm_s390_inject_vm(struct kvm *kvm, - struct kvm_s390_interrupt *s390int) +static void __inject_vm(struct kvm *kvm, struct kvm_s390_interrupt_info *inti) { struct kvm_s390_local_interrupt *li; struct kvm_s390_float_interrupt *fi; - struct kvm_s390_interrupt_info *inti, *iter; + struct kvm_s390_interrupt_info *iter; int sigcpu; + mutex_lock(&kvm->lock); + fi = &kvm->arch.float_int; + spin_lock(&fi->lock); + if (!is_ioint(inti->type)) { + list_add_tail(&inti->list, &fi->list); + } else { + u64 isc_bits = int_word_to_isc_bits(inti->io.io_int_word); + + /* Keep I/O interrupts sorted in isc order. */ + list_for_each_entry(iter, &fi->list, list) { + if (!is_ioint(iter->type)) + continue; + if (int_word_to_isc_bits(iter->io.io_int_word) + <= isc_bits) + continue; + break; + } + list_add_tail(&inti->list, &iter->list); + } + atomic_set(&fi->active, 1); + sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS); + if (sigcpu == KVM_MAX_VCPUS) { + do { + sigcpu = fi->next_rr_cpu++; + if (sigcpu == KVM_MAX_VCPUS) + sigcpu = fi->next_rr_cpu = 0; + } while (fi->local_int[sigcpu] == NULL); + } + li = fi->local_int[sigcpu]; + spin_lock_bh(&li->lock); + atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); + if (waitqueue_active(li->wq)) + wake_up_interruptible(li->wq); + spin_unlock_bh(&li->lock); + spin_unlock(&fi->lock); + mutex_unlock(&kvm->lock); +} + +int kvm_s390_inject_vm(struct kvm *kvm, + struct kvm_s390_interrupt *s390int) +{ + struct kvm_s390_interrupt_info *inti; + inti = kzalloc(sizeof(*inti), GFP_KERNEL); if (!inti) return -ENOMEM; - switch (s390int->type) { + inti->type = s390int->type; + switch (inti->type) { case KVM_S390_INT_VIRTIO: VM_EVENT(kvm, 5, "inject: virtio parm:%x,parm64:%llx", s390int->parm, s390int->parm64); - inti->type = s390int->type; inti->ext.ext_params = s390int->parm; inti->ext.ext_params2 = s390int->parm64; break; case KVM_S390_INT_SERVICE: VM_EVENT(kvm, 5, "inject: sclp parm:%x", s390int->parm); - inti->type = s390int->type; inti->ext.ext_params = s390int->parm; break; - case KVM_S390_PROGRAM_INT: - case KVM_S390_SIGP_STOP: - case KVM_S390_INT_EXTERNAL_CALL: - case KVM_S390_INT_EMERGENCY: - kfree(inti); - return -EINVAL; case KVM_S390_MCHK: VM_EVENT(kvm, 5, "inject: machine check parm64:%llx", s390int->parm64); - inti->type = s390int->type; inti->mchk.cr14 = s390int->parm; /* upper bits are not used */ inti->mchk.mcic = s390int->parm64; break; case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: - if (s390int->type & IOINT_AI_MASK) + if (inti->type & IOINT_AI_MASK) VM_EVENT(kvm, 5, "%s", "inject: I/O (AI)"); else VM_EVENT(kvm, 5, "inject: I/O css %x ss %x schid %04x", s390int->type & IOINT_CSSID_MASK, s390int->type & IOINT_SSID_MASK, s390int->type & IOINT_SCHID_MASK); - inti->type = s390int->type; inti->io.subchannel_id = s390int->parm >> 16; inti->io.subchannel_nr = s390int->parm & 0x0000ffffu; inti->io.io_int_parm = s390int->parm64 >> 32; @@ -718,42 +751,7 @@ int kvm_s390_inject_vm(struct kvm *kvm, trace_kvm_s390_inject_vm(s390int->type, s390int->parm, s390int->parm64, 2); - mutex_lock(&kvm->lock); - fi = &kvm->arch.float_int; - spin_lock(&fi->lock); - if (!is_ioint(inti->type)) - list_add_tail(&inti->list, &fi->list); - else { - u64 isc_bits = int_word_to_isc_bits(inti->io.io_int_word); - - /* Keep I/O interrupts sorted in isc order. */ - list_for_each_entry(iter, &fi->list, list) { - if (!is_ioint(iter->type)) - continue; - if (int_word_to_isc_bits(iter->io.io_int_word) - <= isc_bits) - continue; - break; - } - list_add_tail(&inti->list, &iter->list); - } - atomic_set(&fi->active, 1); - sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS); - if (sigcpu == KVM_MAX_VCPUS) { - do { - sigcpu = fi->next_rr_cpu++; - if (sigcpu == KVM_MAX_VCPUS) - sigcpu = fi->next_rr_cpu = 0; - } while (fi->local_int[sigcpu] == NULL); - } - li = fi->local_int[sigcpu]; - spin_lock_bh(&li->lock); - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); - if (waitqueue_active(li->wq)) - wake_up_interruptible(li->wq); - spin_unlock_bh(&li->lock); - spin_unlock(&fi->lock); - mutex_unlock(&kvm->lock); + __inject_vm(kvm, inti); return 0; } @@ -841,3 +839,207 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, mutex_unlock(&vcpu->kvm->lock); return 0; } + +static void clear_floating_interrupts(struct kvm *kvm) +{ + struct kvm_s390_float_interrupt *fi; + struct kvm_s390_interrupt_info *n, *inti = NULL; + + mutex_lock(&kvm->lock); + fi = &kvm->arch.float_int; + spin_lock(&fi->lock); + list_for_each_entry_safe(inti, n, &fi->list, list) { + list_del(&inti->list); + kfree(inti); + } + atomic_set(&fi->active, 0); + spin_unlock(&fi->lock); + mutex_unlock(&kvm->lock); +} + +static inline int copy_irq_to_user(struct kvm_s390_interrupt_info *inti, + u8 *addr) +{ + struct kvm_s390_irq __user *uptr = (struct kvm_s390_irq __user *) addr; + struct kvm_s390_irq irq = {0}; + + irq.type = inti->type; + switch (inti->type) { + case KVM_S390_INT_VIRTIO: + case KVM_S390_INT_SERVICE: + irq.u.ext = inti->ext; + break; + case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: + irq.u.io = inti->io; + break; + case KVM_S390_MCHK: + irq.u.mchk = inti->mchk; + break; + default: + return -EINVAL; + } + + if (copy_to_user(uptr, &irq, sizeof(irq))) + return -EFAULT; + + return 0; +} + +static int get_all_floating_irqs(struct kvm *kvm, __u8 *buf, __u64 len) +{ + struct kvm_s390_interrupt_info *inti; + struct kvm_s390_float_interrupt *fi; + int ret = 0; + int n = 0; + + mutex_lock(&kvm->lock); + fi = &kvm->arch.float_int; + spin_lock(&fi->lock); + + list_for_each_entry(inti, &fi->list, list) { + if (len < sizeof(struct kvm_s390_irq)) { + /* signal userspace to try again */ + ret = -ENOMEM; + break; + } + ret = copy_irq_to_user(inti, buf); + if (ret) + break; + buf += sizeof(struct kvm_s390_irq); + len -= sizeof(struct kvm_s390_irq); + n++; + } + + spin_unlock(&fi->lock); + mutex_unlock(&kvm->lock); + + return ret < 0 ? ret : n; +} + +static int flic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) +{ + int r; + + switch (attr->group) { + case KVM_DEV_FLIC_GET_ALL_IRQS: + r = get_all_floating_irqs(dev->kvm, (u8 *) attr->addr, + attr->attr); + break; + default: + r = -EINVAL; + } + + return r; +} + +static inline int copy_irq_from_user(struct kvm_s390_interrupt_info *inti, + u64 addr) +{ + struct kvm_s390_irq __user *uptr = (struct kvm_s390_irq __user *) addr; + void *target = NULL; + void __user *source; + u64 size; + + if (get_user(inti->type, (u64 __user *)addr)) + return -EFAULT; + + switch (inti->type) { + case KVM_S390_INT_VIRTIO: + case KVM_S390_INT_SERVICE: + target = (void *) &inti->ext; + source = &uptr->u.ext; + size = sizeof(inti->ext); + break; + case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: + target = (void *) &inti->io; + source = &uptr->u.io; + size = sizeof(inti->io); + break; + case KVM_S390_MCHK: + target = (void *) &inti->mchk; + source = &uptr->u.mchk; + size = sizeof(inti->mchk); + break; + default: + return -EINVAL; + } + + if (copy_from_user(target, source, size)) + return -EFAULT; + + return 0; +} + +static int enqueue_floating_irq(struct kvm_device *dev, + struct kvm_device_attr *attr) +{ + struct kvm_s390_interrupt_info *inti = NULL; + int r = 0; + int len = attr->attr; + + if (len % sizeof(struct kvm_s390_irq) != 0) + return -EINVAL; + else if (len > KVM_S390_FLIC_MAX_BUFFER) + return -EINVAL; + + while (len >= sizeof(struct kvm_s390_irq)) { + inti = kzalloc(sizeof(*inti), GFP_KERNEL); + if (!inti) + return -ENOMEM; + + r = copy_irq_from_user(inti, attr->addr); + if (r) { + kfree(inti); + return r; + } + __inject_vm(dev->kvm, inti); + len -= sizeof(struct kvm_s390_irq); + attr->addr += sizeof(struct kvm_s390_irq); + } + + return r; +} + +static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) +{ + int r = 0; + + switch (attr->group) { + case KVM_DEV_FLIC_ENQUEUE: + r = enqueue_floating_irq(dev, attr); + break; + case KVM_DEV_FLIC_CLEAR_IRQS: + r = 0; + clear_floating_interrupts(dev->kvm); + break; + default: + r = -EINVAL; + } + + return r; +} + +static int flic_create(struct kvm_device *dev, u32 type) +{ + if (!dev) + return -EINVAL; + if (dev->kvm->arch.flic) + return -EINVAL; + dev->kvm->arch.flic = dev; + return 0; +} + +static void flic_destroy(struct kvm_device *dev) +{ + dev->kvm->arch.flic = NULL; + kfree(dev); +} + +/* s390 floating irq controller (flic) */ +struct kvm_device_ops kvm_flic_ops = { + .name = "kvm-flic", + .get_attr = flic_get_attr, + .set_attr = flic_set_attr, + .create = flic_create, + .destroy = flic_destroy, +}; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index e0676f390d57..782420f3c4d5 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -157,6 +157,7 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_ENABLE_CAP: case KVM_CAP_S390_CSS_SUPPORT: case KVM_CAP_IOEVENTFD: + case KVM_CAP_DEVICE_CTRL: r = 1; break; case KVM_CAP_NR_VCPUS: diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index b8e9a43e501a..c0102ef2de48 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1064,6 +1064,7 @@ extern struct kvm_device_ops kvm_mpic_ops; extern struct kvm_device_ops kvm_xics_ops; extern struct kvm_device_ops kvm_vfio_ops; extern struct kvm_device_ops kvm_arm_vgic_v2_ops; +extern struct kvm_device_ops kvm_flic_ops; #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 86faf47ae494..19f717b15297 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -918,6 +918,7 @@ struct kvm_device_attr { #define KVM_DEV_VFIO_GROUP_ADD 1 #define KVM_DEV_VFIO_GROUP_DEL 2 #define KVM_DEV_TYPE_ARM_VGIC_V2 5 +#define KVM_DEV_TYPE_FLIC 6 /* * ioctls for VM fds diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 03a0381b1cb7..a9e999a48e43 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2283,6 +2283,11 @@ static int kvm_ioctl_create_device(struct kvm *kvm, case KVM_DEV_TYPE_ARM_VGIC_V2: ops = &kvm_arm_vgic_v2_ops; break; +#endif +#ifdef CONFIG_S390 + case KVM_DEV_TYPE_FLIC: + ops = &kvm_flic_ops; + break; #endif default: return -ENODEV; -- cgit v1.3-8-gc7d7 From e0ead41a6dac09f86675ce07a66e4b253a9b7bd5 Mon Sep 17 00:00:00 2001 From: Dominik Dingel Date: Thu, 6 Jun 2013 15:32:37 +0200 Subject: KVM: async_pf: Provide additional direct page notification By setting a Kconfig option, the architecture can control when guest notifications will be presented by the apf backend. There is the default batch mechanism, working as before, where the vcpu thread should pull in this information. Opposite to this, there is now the direct mechanism, that will push the information to the guest. This way s390 can use an already existing architecture interface. Still the vcpu thread should call check_completion to cleanup leftovers. Signed-off-by: Dominik Dingel Signed-off-by: Christian Borntraeger --- arch/x86/kvm/mmu.c | 2 +- include/linux/kvm_host.h | 2 +- virt/kvm/Kconfig | 4 ++++ virt/kvm/async_pf.c | 20 ++++++++++++++++++-- 4 files changed, 24 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index e50425d0f5f7..aaa60f347b73 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -3328,7 +3328,7 @@ static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn) arch.direct_map = vcpu->arch.mmu.direct_map; arch.cr3 = vcpu->arch.mmu.get_cr3(vcpu); - return kvm_setup_async_pf(vcpu, gva, gfn, &arch); + return kvm_setup_async_pf(vcpu, gva, gfn_to_hva(vcpu->kvm, gfn), &arch); } static bool can_do_async_pf(struct kvm_vcpu *vcpu) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index c0102ef2de48..f5937b8188b4 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -192,7 +192,7 @@ struct kvm_async_pf { void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu); void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu); -int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn, +int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, unsigned long hva, struct kvm_arch_async_pf *arch); int kvm_async_pf_wakeup_all(struct kvm_vcpu *vcpu); #endif diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig index fbe1a48bd629..13f2d19793e3 100644 --- a/virt/kvm/Kconfig +++ b/virt/kvm/Kconfig @@ -22,6 +22,10 @@ config KVM_MMIO config KVM_ASYNC_PF bool +# Toggle to switch between direct notification and batch job +config KVM_ASYNC_PF_SYNC + bool + config HAVE_KVM_MSI bool diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c index 8631d9c14320..00980ab02c45 100644 --- a/virt/kvm/async_pf.c +++ b/virt/kvm/async_pf.c @@ -28,6 +28,21 @@ #include "async_pf.h" #include +static inline void kvm_async_page_present_sync(struct kvm_vcpu *vcpu, + struct kvm_async_pf *work) +{ +#ifdef CONFIG_KVM_ASYNC_PF_SYNC + kvm_arch_async_page_present(vcpu, work); +#endif +} +static inline void kvm_async_page_present_async(struct kvm_vcpu *vcpu, + struct kvm_async_pf *work) +{ +#ifndef CONFIG_KVM_ASYNC_PF_SYNC + kvm_arch_async_page_present(vcpu, work); +#endif +} + static struct kmem_cache *async_pf_cache; int kvm_async_pf_init(void) @@ -69,6 +84,7 @@ static void async_pf_execute(struct work_struct *work) down_read(&mm->mmap_sem); get_user_pages(current, mm, addr, 1, 1, 0, NULL, NULL); up_read(&mm->mmap_sem); + kvm_async_page_present_sync(vcpu, apf); unuse_mm(mm); spin_lock(&vcpu->async_pf.lock); @@ -138,7 +154,7 @@ void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu) } } -int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn, +int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, unsigned long hva, struct kvm_arch_async_pf *arch) { struct kvm_async_pf *work; @@ -159,7 +175,7 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn, work->wakeup_all = false; work->vcpu = vcpu; work->gva = gva; - work->addr = gfn_to_hva(vcpu->kvm, gfn); + work->addr = hva; work->arch = *arch; work->mm = current->mm; atomic_inc(&work->mm->mm_count); -- cgit v1.3-8-gc7d7 From 8cc7212a036118fcb5cfbbdb013c5032677bbd23 Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Thu, 30 Jan 2014 19:57:54 +0400 Subject: idr: remove unused prototype of idr_free() There is no such function. Remove the redundant prototype. Signed-off-by: Vladimir Davydov Acked-by: Tejun Heo Signed-off-by: Jiri Kosina --- include/linux/idr.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/idr.h b/include/linux/idr.h index 871a213a8477..ff94a4875e1c 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h @@ -82,7 +82,6 @@ int idr_for_each(struct idr *idp, void *idr_get_next(struct idr *idp, int *nextid); void *idr_replace(struct idr *idp, void *ptr, int id); void idr_remove(struct idr *idp, int id); -void idr_free(struct idr *idp, int id); void idr_destroy(struct idr *idp); void idr_init(struct idr *idp); -- cgit v1.3-8-gc7d7 From fc0a5921561c71be2c334a335c1680f7930434d7 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 20 Dec 2013 22:41:07 +0100 Subject: reset: Add of_reset_control_get In some cases, you might need to deassert from reset an hardware block that doesn't associated to a struct device (CPUs, timers, etc.). Add a small helper to retrieve the reset controller from the device tree without the need to pass a struct device. Signed-off-by: Maxime Ripard Signed-off-by: Philipp Zabel --- drivers/reset/core.c | 39 ++++++++++++++++++++++++++++++--------- include/linux/reset.h | 4 ++++ 2 files changed, 34 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 217d2fa4fd95..baeaf82d40d9 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -126,15 +126,16 @@ int reset_control_deassert(struct reset_control *rstc) EXPORT_SYMBOL_GPL(reset_control_deassert); /** - * reset_control_get - Lookup and obtain a reference to a reset controller. - * @dev: device to be reset by the controller + * of_reset_control_get - Lookup and obtain a reference to a reset controller. + * @node: device to be reset by the controller * @id: reset line name * * Returns a struct reset_control or IS_ERR() condition containing errno. * * Use of id names is optional. */ -struct reset_control *reset_control_get(struct device *dev, const char *id) +struct reset_control *of_reset_control_get(struct device_node *node, + const char *id) { struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER); struct reset_controller_dev *r, *rcdev; @@ -143,13 +144,10 @@ struct reset_control *reset_control_get(struct device *dev, const char *id) int rstc_id; int ret; - if (!dev) - return ERR_PTR(-EINVAL); - if (id) - index = of_property_match_string(dev->of_node, + index = of_property_match_string(node, "reset-names", id); - ret = of_parse_phandle_with_args(dev->of_node, "resets", "#reset-cells", + ret = of_parse_phandle_with_args(node, "resets", "#reset-cells", index, &args); if (ret) return ERR_PTR(ret); @@ -184,12 +182,35 @@ struct reset_control *reset_control_get(struct device *dev, const char *id) return ERR_PTR(-ENOMEM); } - rstc->dev = dev; rstc->rcdev = rcdev; rstc->id = rstc_id; return rstc; } +EXPORT_SYMBOL_GPL(of_reset_control_get); + +/** + * reset_control_get - Lookup and obtain a reference to a reset controller. + * @dev: device to be reset by the controller + * @id: reset line name + * + * Returns a struct reset_control or IS_ERR() condition containing errno. + * + * Use of id names is optional. + */ +struct reset_control *reset_control_get(struct device *dev, const char *id) +{ + struct reset_control *rstc; + + if (!dev) + return ERR_PTR(-EINVAL); + + rstc = of_reset_control_get(dev->of_node, id); + if (!IS_ERR(rstc)) + rstc->dev = dev; + + return rstc; +} EXPORT_SYMBOL_GPL(reset_control_get); /** diff --git a/include/linux/reset.h b/include/linux/reset.h index 6082247feab1..a398025d1138 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -1,6 +1,8 @@ #ifndef _LINUX_RESET_H_ #define _LINUX_RESET_H_ +#include + struct device; struct reset_control; @@ -8,6 +10,8 @@ int reset_control_reset(struct reset_control *rstc); int reset_control_assert(struct reset_control *rstc); int reset_control_deassert(struct reset_control *rstc); +struct reset_control *of_reset_control_get(struct device_node *node, + const char *id); struct reset_control *reset_control_get(struct device *dev, const char *id); void reset_control_put(struct reset_control *rstc); struct reset_control *devm_reset_control_get(struct device *dev, const char *id); -- cgit v1.3-8-gc7d7 From 588453c69dace39351129a038dd2796608f74bb3 Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Fri, 8 Nov 2013 17:03:56 +0200 Subject: of: Introduce device tree node flag helpers. Helper functions for working with device node flags. Signed-off-by: Pantelis Antoniou Signed-off-by: Grant Likely --- include/linux/of.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'include/linux') diff --git a/include/linux/of.h b/include/linux/of.h index 70c64ba17fa5..3d0593943f47 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -114,6 +114,26 @@ static inline void of_node_set_flag(struct device_node *n, unsigned long flag) set_bit(flag, &n->_flags); } +static inline void of_node_clear_flag(struct device_node *n, unsigned long flag) +{ + clear_bit(flag, &n->_flags); +} + +static inline int of_property_check_flag(struct property *p, unsigned long flag) +{ + return test_bit(flag, &p->_flags); +} + +static inline void of_property_set_flag(struct property *p, unsigned long flag) +{ + set_bit(flag, &p->_flags); +} + +static inline void of_property_clear_flag(struct property *p, unsigned long flag) +{ + clear_bit(flag, &p->_flags); +} + extern struct device_node *of_find_all_nodes(struct device_node *prev); /* -- cgit v1.3-8-gc7d7 From a028c6da34d434e35ba8322568c756ea97ff3c18 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sat, 14 Dec 2013 16:23:51 +0100 Subject: ARM: shmobile: wait for MSTP clock status to toggle, when enabling it On r-/sh-mobile SoCs MSTP clocks are used by the runtime PM to dynamically enable and disable peripheral clocks. To make sure the clock has really started we have to read back its status register until it confirms success. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Simon Horman --- drivers/sh/clk/cpg.c | 38 ++++++++++++++++++++++++++++++++++++++ include/linux/sh_clk.h | 19 ++++++++++++------- 2 files changed, 50 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c index 1ebe67cd1833..7442bc130055 100644 --- a/drivers/sh/clk/cpg.c +++ b/drivers/sh/clk/cpg.c @@ -36,9 +36,47 @@ static void sh_clk_write(int value, struct clk *clk) iowrite32(value, clk->mapped_reg); } +static unsigned int r8(const void __iomem *addr) +{ + return ioread8(addr); +} + +static unsigned int r16(const void __iomem *addr) +{ + return ioread16(addr); +} + +static unsigned int r32(const void __iomem *addr) +{ + return ioread32(addr); +} + static int sh_clk_mstp_enable(struct clk *clk) { sh_clk_write(sh_clk_read(clk) & ~(1 << clk->enable_bit), clk); + if (clk->status_reg) { + unsigned int (*read)(const void __iomem *addr); + int i; + void __iomem *mapped_status = (phys_addr_t)clk->status_reg - + (phys_addr_t)clk->enable_reg + clk->mapped_reg; + + if (clk->flags & CLK_ENABLE_REG_8BIT) + read = r8; + else if (clk->flags & CLK_ENABLE_REG_16BIT) + read = r16; + else + read = r32; + + for (i = 1000; + (read(mapped_status) & (1 << clk->enable_bit)) && i; + i--) + cpu_relax(); + if (!i) { + pr_err("cpg: failed to enable %p[%d]\n", + clk->enable_reg, clk->enable_bit); + return -ETIMEDOUT; + } + } return 0; } diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h index 60c72395ec6b..1f208b2a1ed6 100644 --- a/include/linux/sh_clk.h +++ b/include/linux/sh_clk.h @@ -52,6 +52,7 @@ struct clk { unsigned long flags; void __iomem *enable_reg; + void __iomem *status_reg; unsigned int enable_bit; void __iomem *mapped_reg; @@ -116,22 +117,26 @@ long clk_round_parent(struct clk *clk, unsigned long target, unsigned long *best_freq, unsigned long *parent_freq, unsigned int div_min, unsigned int div_max); -#define SH_CLK_MSTP(_parent, _enable_reg, _enable_bit, _flags) \ +#define SH_CLK_MSTP(_parent, _enable_reg, _enable_bit, _status_reg, _flags) \ { \ .parent = _parent, \ .enable_reg = (void __iomem *)_enable_reg, \ .enable_bit = _enable_bit, \ + .status_reg = _status_reg, \ .flags = _flags, \ } -#define SH_CLK_MSTP32(_p, _r, _b, _f) \ - SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_32BIT) +#define SH_CLK_MSTP32(_p, _r, _b, _f) \ + SH_CLK_MSTP(_p, _r, _b, 0, _f | CLK_ENABLE_REG_32BIT) -#define SH_CLK_MSTP16(_p, _r, _b, _f) \ - SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_16BIT) +#define SH_CLK_MSTP32_STS(_p, _r, _b, _s, _f) \ + SH_CLK_MSTP(_p, _r, _b, _s, _f | CLK_ENABLE_REG_32BIT) -#define SH_CLK_MSTP8(_p, _r, _b, _f) \ - SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_8BIT) +#define SH_CLK_MSTP16(_p, _r, _b, _f) \ + SH_CLK_MSTP(_p, _r, _b, 0, _f | CLK_ENABLE_REG_16BIT) + +#define SH_CLK_MSTP8(_p, _r, _b, _f) \ + SH_CLK_MSTP(_p, _r, _b, 0, _f | CLK_ENABLE_REG_8BIT) int sh_clk_mstp_register(struct clk *clks, int nr); -- cgit v1.3-8-gc7d7 From cb2518ca9f06dfcfa3d175773631bfb1e461bdc7 Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Wed, 15 Jan 2014 09:50:13 +0100 Subject: can: add ability to allocate CANFD frame in skb data This patch adds the ability of allocating a CANFD frame data structure in the skb data area. Signed-off-by: Stephane Grosjean Acked-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 24 ++++++++++++++++++++++++ include/linux/can/dev.h | 2 ++ 2 files changed, 26 insertions(+) (limited to 'include/linux') diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 13a909822e25..cb584ea00331 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -521,6 +521,30 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) } EXPORT_SYMBOL_GPL(alloc_can_skb); +struct sk_buff *alloc_canfd_skb(struct net_device *dev, + struct canfd_frame **cfd) +{ + struct sk_buff *skb; + + skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + + sizeof(struct canfd_frame)); + if (unlikely(!skb)) + return NULL; + + skb->protocol = htons(ETH_P_CANFD); + skb->pkt_type = PACKET_BROADCAST; + skb->ip_summed = CHECKSUM_UNNECESSARY; + + can_skb_reserve(skb); + can_skb_prv(skb)->ifindex = dev->ifindex; + + *cfd = (struct canfd_frame *)skb_put(skb, sizeof(struct canfd_frame)); + memset(*cfd, 0, sizeof(struct canfd_frame)); + + return skb; +} +EXPORT_SYMBOL_GPL(alloc_canfd_skb); + struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf) { struct sk_buff *skb; diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index fb0ab651a041..dc5f9026b67f 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -124,6 +124,8 @@ unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx); void can_free_echo_skb(struct net_device *dev, unsigned int idx); struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf); +struct sk_buff *alloc_canfd_skb(struct net_device *dev, + struct canfd_frame **cfd); struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf); -- cgit v1.3-8-gc7d7 From d8ca16db6bb23d03fcb794df44bae64ae976f27c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Jan 2014 16:20:29 +0100 Subject: mac80211: add length check in ieee80211_is_robust_mgmt_frame() A few places weren't checking that the frame passed to the function actually has enough data even though the function clearly documents it must have a payload byte. Make this safer by changing the function to take an skb and checking the length inside. The old version is preserved for now as the rtl* drivers use it and don't have a correct skb. Signed-off-by: Johannes Berg --- drivers/net/wireless/rtlwifi/rtl8188ee/trx.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192ce/trx.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192se/trx.c | 2 +- drivers/net/wireless/rtlwifi/rtl8723ae/trx.c | 2 +- include/linux/ieee80211.h | 15 +++++++++++++-- net/mac80211/rx.c | 13 ++++++------- net/mac80211/tx.c | 9 ++++----- net/mac80211/wpa.c | 2 +- 8 files changed, 28 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c index aece6c9cccf1..27ace3054d56 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c @@ -452,7 +452,7 @@ bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw, /* During testing, hdr was NULL */ return false; } - if ((ieee80211_is_robust_mgmt_frame(hdr)) && + if ((_ieee80211_is_robust_mgmt_frame(hdr)) && (ieee80211_has_protected(hdr->frame_control))) rx_status->flag &= ~RX_FLAG_DECRYPTED; else diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index 52abf0a862fa..114858d46158 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -393,7 +393,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, /* In testing, hdr was NULL here */ return false; } - if ((ieee80211_is_robust_mgmt_frame(hdr)) && + if ((_ieee80211_is_robust_mgmt_frame(hdr)) && (ieee80211_has_protected(hdr->frame_control))) rx_status->flag &= ~RX_FLAG_DECRYPTED; else diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index 27efbcdac6a9..163a681962c6 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c @@ -310,7 +310,7 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, /* during testing, hdr was NULL here */ return false; } - if ((ieee80211_is_robust_mgmt_frame(hdr)) && + if ((_ieee80211_is_robust_mgmt_frame(hdr)) && (ieee80211_has_protected(hdr->frame_control))) rx_status->flag &= ~RX_FLAG_DECRYPTED; else diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c index 50b7be3f3a60..721162cacc3a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c @@ -334,7 +334,7 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw, /* during testing, hdr could be NULL here */ return false; } - if ((ieee80211_is_robust_mgmt_frame(hdr)) && + if ((_ieee80211_is_robust_mgmt_frame(hdr)) && (ieee80211_has_protected(hdr->frame_control))) rx_status->flag &= ~RX_FLAG_DECRYPTED; else diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index e526a8cecb70..923c478030a3 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2192,10 +2192,10 @@ static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr) } /** - * ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame + * _ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame * @hdr: the frame (buffer must include at least the first octet of payload) */ -static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr) +static inline bool _ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr) { if (ieee80211_is_disassoc(hdr->frame_control) || ieee80211_is_deauth(hdr->frame_control)) @@ -2223,6 +2223,17 @@ static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr) return false; } +/** + * ieee80211_is_robust_mgmt_frame - check if skb contains a robust mgmt frame + * @skb: the skb containing the frame, length will be checked + */ +static inline bool ieee80211_is_robust_mgmt_frame(struct sk_buff *skb) +{ + if (skb->len < 25) + return false; + return _ieee80211_is_robust_mgmt_frame((void *)skb->data); +} + /** * ieee80211_is_public_action - check if frame is a public action frame * @hdr: the frame diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c24ca0d0f469..3b7a750ebc70 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -599,10 +599,10 @@ static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - if (skb->len < 24 || is_multicast_ether_addr(hdr->addr1)) + if (is_multicast_ether_addr(hdr->addr1)) return 0; - return ieee80211_is_robust_mgmt_frame(hdr); + return ieee80211_is_robust_mgmt_frame(skb); } @@ -610,10 +610,10 @@ static int ieee80211_is_multicast_robust_mgmt_frame(struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - if (skb->len < 24 || !is_multicast_ether_addr(hdr->addr1)) + if (!is_multicast_ether_addr(hdr->addr1)) return 0; - return ieee80211_is_robust_mgmt_frame(hdr); + return ieee80211_is_robust_mgmt_frame(skb); } @@ -626,7 +626,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) return -1; - if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr)) + if (!ieee80211_is_robust_mgmt_frame(skb)) return -1; /* not a robust management frame */ mmie = (struct ieee80211_mmie *) @@ -1845,8 +1845,7 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) * having configured keys. */ if (unlikely(ieee80211_is_action(fc) && !rx->key && - ieee80211_is_robust_mgmt_frame( - (struct ieee80211_hdr *) rx->skb->data))) + ieee80211_is_robust_mgmt_frame(rx->skb))) return -EACCES; } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index bb990ecfa655..07a7f38dc348 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -452,8 +452,7 @@ static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta, if (sta == NULL || !test_sta_flag(sta, WLAN_STA_MFP)) return 0; - if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) - skb->data)) + if (!ieee80211_is_robust_mgmt_frame(skb)) return 0; return 1; @@ -567,7 +566,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) tx->key = key; else if (ieee80211_is_mgmt(hdr->frame_control) && is_multicast_ether_addr(hdr->addr1) && - ieee80211_is_robust_mgmt_frame(hdr) && + ieee80211_is_robust_mgmt_frame(tx->skb) && (key = rcu_dereference(tx->sdata->default_mgmt_key))) tx->key = key; else if (is_multicast_ether_addr(hdr->addr1) && @@ -582,12 +581,12 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) tx->key = NULL; else if (tx->skb->protocol == tx->sdata->control_port_protocol) tx->key = NULL; - else if (ieee80211_is_robust_mgmt_frame(hdr) && + else if (ieee80211_is_robust_mgmt_frame(tx->skb) && !(ieee80211_is_action(hdr->frame_control) && tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP))) tx->key = NULL; else if (ieee80211_is_mgmt(hdr->frame_control) && - !ieee80211_is_robust_mgmt_frame(hdr)) + !ieee80211_is_robust_mgmt_frame(tx->skb)) tx->key = NULL; else { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 4aed45c8ee3b..b8600e3c29c8 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -494,7 +494,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) hdrlen = ieee80211_hdrlen(hdr->frame_control); if (!ieee80211_is_data(hdr->frame_control) && - !ieee80211_is_robust_mgmt_frame(hdr)) + !ieee80211_is_robust_mgmt_frame(skb)) return RX_CONTINUE; data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN - -- cgit v1.3-8-gc7d7 From b4ba544c8c1349afd44e10aebec03c90e9b71d98 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jan 2014 14:41:44 +0100 Subject: mac80211: fix bufferable MMPDU RX handling Action, disassoc and deauth frames are bufferable, and as such don't have the PM bit in the frame control field reserved which means we need to react to the bit when receiving in such a frame. Fix this by introducing a new helper ieee80211_is_bufferable_mmpdu() and using it for the RX path that currently ignores the PM bit in any non-data frames for doze->wake transitions, but listens to it in all frames for wake->doze transitions, both of which are wrong. Also use the new helper in the TX path to clean up the code. Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 14 ++++++++++++++ net/mac80211/rx.c | 19 ++++++++----------- net/mac80211/tx.c | 5 +---- 3 files changed, 23 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 923c478030a3..1e3912d1b029 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -596,6 +596,20 @@ static inline int ieee80211_is_qos_nullfunc(__le16 fc) cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC); } +/** + * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU + * @fc: frame control field in little-endian byteorder + */ +static inline bool ieee80211_is_bufferable_mmpdu(__le16 fc) +{ + /* IEEE 802.11-2012, definition of "bufferable management frame"; + * note that this ignores the IBSS special case. */ + return ieee80211_is_mgmt(fc) && + (ieee80211_is_action(fc) || + ieee80211_is_disassoc(fc) || + ieee80211_is_deauth(fc)); +} + /** * ieee80211_is_first_frag - check if IEEE80211_SCTL_FRAG is not set * @seq_ctrl: frame sequence control bytes in little-endian byteorder diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 3b7a750ebc70..79a89fe9d616 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1311,18 +1311,15 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) !ieee80211_has_morefrags(hdr->frame_control) && !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && (rx->sdata->vif.type == NL80211_IFTYPE_AP || - rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { + rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && + /* PM bit is only checked in frames where it isn't reserved, + * in AP mode it's reserved in non-bufferable management frames + * (cf. IEEE 802.11-2012 8.2.4.1.7 Power Management field) + */ + (!ieee80211_is_mgmt(hdr->frame_control) || + ieee80211_is_bufferable_mmpdu(hdr->frame_control))) { if (test_sta_flag(sta, WLAN_STA_PS_STA)) { - /* - * Ignore doze->wake transitions that are - * indicated by non-data frames, the standard - * is unclear here, but for example going to - * PS mode and then scanning would cause a - * doze->wake transition for the probe request, - * and that is clearly undesirable. - */ - if (ieee80211_is_data(hdr->frame_control) && - !ieee80211_has_pm(hdr->frame_control)) + if (!ieee80211_has_pm(hdr->frame_control)) sta_ps_end(sta); } else { if (ieee80211_has_pm(hdr->frame_control)) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 07a7f38dc348..5476a69b45c9 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -522,11 +522,8 @@ ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx) if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED)) return TX_CONTINUE; - /* only deauth, disassoc and action are bufferable MMPDUs */ if (ieee80211_is_mgmt(hdr->frame_control) && - !ieee80211_is_deauth(hdr->frame_control) && - !ieee80211_is_disassoc(hdr->frame_control) && - !ieee80211_is_action(hdr->frame_control)) { + !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) { if (tx->flags & IEEE80211_TX_UNICAST) info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; return TX_CONTINUE; -- cgit v1.3-8-gc7d7 From b66548e2a9baf65ccebeb3750f0ab9ddbef500f6 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 17 Jan 2014 12:08:30 +0100 Subject: of: Increase MAX_PHANDLE_ARGS arm-smmu driver uses of_parse_phandle_with_args when parsing DT information to determine stream IDs for a master device. Thus the number of stream IDs per master device is bound by MAX_PHANDLE_ARGS. To support Calxeda ECX-2000 hardware arm-smmu driver requires a slightly higher value for MAX_PHANDLE_ARGS as this hardware has 10 stream IDs for one master device. Increasing it to 16 seems a reasonable choice. Cc: Grant Likely Cc: Rob Herring Cc: devicetree@vger.kernel.org Cc: Andreas Herrmann Acked-by: Rob Herring Signed-off-by: Andreas Herrmann Signed-off-by: Grant Likely --- include/linux/of.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/of.h b/include/linux/of.h index 3d0593943f47..0ea516ed22c0 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -67,7 +67,7 @@ struct device_node { #endif }; -#define MAX_PHANDLE_ARGS 8 +#define MAX_PHANDLE_ARGS 16 struct of_phandle_args { struct device_node *np; int args_count; -- cgit v1.3-8-gc7d7 From 8c78e38025060a00155a73bf722152c156242490 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 4 Feb 2014 09:41:04 +0100 Subject: wireless: sort and extend element ID list The element ID list is currently almost sorted by amendment or similar topic, but the order is difficult to maintain and not very transparent. Sort the list by ID instead, and add a lot of missing IDs. Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 170 +++++++++++++++++++++++++++++----------------- 1 file changed, 106 insertions(+), 64 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 1e3912d1b029..5f349355ee54 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1650,51 +1650,22 @@ enum ieee80211_reasoncode { enum ieee80211_eid { WLAN_EID_SSID = 0, WLAN_EID_SUPP_RATES = 1, - WLAN_EID_FH_PARAMS = 2, + WLAN_EID_FH_PARAMS = 2, /* reserved now */ WLAN_EID_DS_PARAMS = 3, WLAN_EID_CF_PARAMS = 4, WLAN_EID_TIM = 5, WLAN_EID_IBSS_PARAMS = 6, - WLAN_EID_CHALLENGE = 16, - WLAN_EID_COUNTRY = 7, WLAN_EID_HP_PARAMS = 8, WLAN_EID_HP_TABLE = 9, WLAN_EID_REQUEST = 10, - WLAN_EID_QBSS_LOAD = 11, WLAN_EID_EDCA_PARAM_SET = 12, WLAN_EID_TSPEC = 13, WLAN_EID_TCLAS = 14, WLAN_EID_SCHEDULE = 15, - WLAN_EID_TS_DELAY = 43, - WLAN_EID_TCLAS_PROCESSING = 44, - WLAN_EID_QOS_CAPA = 46, - /* 802.11z */ - WLAN_EID_LINK_ID = 101, - /* 802.11s */ - WLAN_EID_MESH_CONFIG = 113, - WLAN_EID_MESH_ID = 114, - WLAN_EID_LINK_METRIC_REPORT = 115, - WLAN_EID_CONGESTION_NOTIFICATION = 116, - WLAN_EID_PEER_MGMT = 117, - WLAN_EID_CHAN_SWITCH_PARAM = 118, - WLAN_EID_MESH_AWAKE_WINDOW = 119, - WLAN_EID_BEACON_TIMING = 120, - WLAN_EID_MCCAOP_SETUP_REQ = 121, - WLAN_EID_MCCAOP_SETUP_RESP = 122, - WLAN_EID_MCCAOP_ADVERT = 123, - WLAN_EID_MCCAOP_TEARDOWN = 124, - WLAN_EID_GANN = 125, - WLAN_EID_RANN = 126, - WLAN_EID_PREQ = 130, - WLAN_EID_PREP = 131, - WLAN_EID_PERR = 132, - WLAN_EID_PXU = 137, - WLAN_EID_PXUC = 138, - WLAN_EID_AUTH_MESH_PEER_EXCH = 139, - WLAN_EID_MIC = 140, - + WLAN_EID_CHALLENGE = 16, + /* 17-31 reserved for challenge text extension */ WLAN_EID_PWR_CONSTRAINT = 32, WLAN_EID_PWR_CAPABILITY = 33, WLAN_EID_TPC_REQUEST = 34, @@ -1705,66 +1676,114 @@ enum ieee80211_eid { WLAN_EID_MEASURE_REPORT = 39, WLAN_EID_QUIET = 40, WLAN_EID_IBSS_DFS = 41, - WLAN_EID_ERP_INFO = 42, - WLAN_EID_EXT_SUPP_RATES = 50, - + WLAN_EID_TS_DELAY = 43, + WLAN_EID_TCLAS_PROCESSING = 44, WLAN_EID_HT_CAPABILITY = 45, - WLAN_EID_HT_OPERATION = 61, - WLAN_EID_SECONDARY_CHANNEL_OFFSET = 62, - + WLAN_EID_QOS_CAPA = 46, + /* 47 reserved for Broadcom */ WLAN_EID_RSN = 48, - WLAN_EID_MMIE = 76, - WLAN_EID_VENDOR_SPECIFIC = 221, - WLAN_EID_QOS_PARAMETER = 222, - + WLAN_EID_802_15_COEX = 49, + WLAN_EID_EXT_SUPP_RATES = 50, WLAN_EID_AP_CHAN_REPORT = 51, WLAN_EID_NEIGHBOR_REPORT = 52, WLAN_EID_RCPI = 53, + WLAN_EID_MOBILITY_DOMAIN = 54, + WLAN_EID_FAST_BSS_TRANSITION = 55, + WLAN_EID_TIMEOUT_INTERVAL = 56, + WLAN_EID_RIC_DATA = 57, + WLAN_EID_DSE_REGISTERED_LOCATION = 58, + WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59, + WLAN_EID_EXT_CHANSWITCH_ANN = 60, + WLAN_EID_HT_OPERATION = 61, + WLAN_EID_SECONDARY_CHANNEL_OFFSET = 62, WLAN_EID_BSS_AVG_ACCESS_DELAY = 63, WLAN_EID_ANTENNA_INFO = 64, WLAN_EID_RSNI = 65, WLAN_EID_MEASUREMENT_PILOT_TX_INFO = 66, WLAN_EID_BSS_AVAILABLE_CAPACITY = 67, WLAN_EID_BSS_AC_ACCESS_DELAY = 68, + WLAN_EID_TIME_ADVERTISEMENT = 69, WLAN_EID_RRM_ENABLED_CAPABILITIES = 70, WLAN_EID_MULTIPLE_BSSID = 71, WLAN_EID_BSS_COEX_2040 = 72, WLAN_EID_OVERLAP_BSS_SCAN_PARAM = 74, - WLAN_EID_EXT_CAPABILITY = 127, - - WLAN_EID_MOBILITY_DOMAIN = 54, - WLAN_EID_FAST_BSS_TRANSITION = 55, - WLAN_EID_TIMEOUT_INTERVAL = 56, - WLAN_EID_RIC_DATA = 57, WLAN_EID_RIC_DESCRIPTOR = 75, - - WLAN_EID_DSE_REGISTERED_LOCATION = 58, - WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59, - WLAN_EID_EXT_CHANSWITCH_ANN = 60, - - WLAN_EID_VHT_CAPABILITY = 191, - WLAN_EID_VHT_OPERATION = 192, - WLAN_EID_OPMODE_NOTIF = 199, - WLAN_EID_WIDE_BW_CHANNEL_SWITCH = 194, - WLAN_EID_CHANNEL_SWITCH_WRAPPER = 196, - WLAN_EID_EXTENDED_BSS_LOAD = 193, - WLAN_EID_VHT_TX_POWER_ENVELOPE = 195, - WLAN_EID_AID = 197, - WLAN_EID_QUIET_CHANNEL = 198, - - /* 802.11ad */ + WLAN_EID_MMIE = 76, + WLAN_EID_ASSOC_COMEBACK_TIME = 77, + WLAN_EID_EVENT_REQUEST = 78, + WLAN_EID_EVENT_REPORT = 79, + WLAN_EID_DIAGNOSTIC_REQUEST = 80, + WLAN_EID_DIAGNOSTIC_REPORT = 81, + WLAN_EID_LOCATION_PARAMS = 82, WLAN_EID_NON_TX_BSSID_CAP = 83, + WLAN_EID_SSID_LIST = 84, + WLAN_EID_MULTI_BSSID_IDX = 85, + WLAN_EID_FMS_DESCRIPTOR = 86, + WLAN_EID_FMS_REQUEST = 87, + WLAN_EID_FMS_RESPONSE = 88, + WLAN_EID_QOS_TRAFFIC_CAPA = 89, + WLAN_EID_BSS_MAX_IDLE_PERIOD = 90, + WLAN_EID_TSF_REQUEST = 91, + WLAN_EID_TSF_RESPOSNE = 92, + WLAN_EID_WNM_SLEEP_MODE = 93, + WLAN_EID_TIM_BCAST_REQ = 94, + WLAN_EID_TIM_BCAST_RESP = 95, + WLAN_EID_COLL_IF_REPORT = 96, + WLAN_EID_CHANNEL_USAGE = 97, + WLAN_EID_TIME_ZONE = 98, + WLAN_EID_DMS_REQUEST = 99, + WLAN_EID_DMS_RESPONSE = 100, + WLAN_EID_LINK_ID = 101, + WLAN_EID_WAKEUP_SCHEDUL = 102, + /* 103 reserved */ + WLAN_EID_CHAN_SWITCH_TIMING = 104, + WLAN_EID_PTI_CONTROL = 105, + WLAN_EID_PU_BUFFER_STATUS = 106, + WLAN_EID_INTERWORKING = 107, + WLAN_EID_ADVERTISEMENT_PROTOCOL = 108, + WLAN_EID_EXPEDITED_BW_REQ = 109, + WLAN_EID_QOS_MAP_SET = 110, + WLAN_EID_ROAMING_CONSORTIUM = 111, + WLAN_EID_EMERGENCY_ALERT = 112, + WLAN_EID_MESH_CONFIG = 113, + WLAN_EID_MESH_ID = 114, + WLAN_EID_LINK_METRIC_REPORT = 115, + WLAN_EID_CONGESTION_NOTIFICATION = 116, + WLAN_EID_PEER_MGMT = 117, + WLAN_EID_CHAN_SWITCH_PARAM = 118, + WLAN_EID_MESH_AWAKE_WINDOW = 119, + WLAN_EID_BEACON_TIMING = 120, + WLAN_EID_MCCAOP_SETUP_REQ = 121, + WLAN_EID_MCCAOP_SETUP_RESP = 122, + WLAN_EID_MCCAOP_ADVERT = 123, + WLAN_EID_MCCAOP_TEARDOWN = 124, + WLAN_EID_GANN = 125, + WLAN_EID_RANN = 126, + WLAN_EID_EXT_CAPABILITY = 127, + /* 128, 129 reserved for Agere */ + WLAN_EID_PREQ = 130, + WLAN_EID_PREP = 131, + WLAN_EID_PERR = 132, + /* 133-136 reserved for Cisco */ + WLAN_EID_PXU = 137, + WLAN_EID_PXUC = 138, + WLAN_EID_AUTH_MESH_PEER_EXCH = 139, + WLAN_EID_MIC = 140, + WLAN_EID_DESTINATION_URI = 141, + WLAN_EID_UAPSD_COEX = 142, WLAN_EID_WAKEUP_SCHEDULE = 143, WLAN_EID_EXT_SCHEDULE = 144, WLAN_EID_STA_AVAILABILITY = 145, WLAN_EID_DMG_TSPEC = 146, WLAN_EID_DMG_AT = 147, WLAN_EID_DMG_CAP = 148, + /* 149-150 reserved for Cisco */ WLAN_EID_DMG_OPERATION = 151, WLAN_EID_DMG_BSS_PARAM_CHANGE = 152, WLAN_EID_DMG_BEAM_REFINEMENT = 153, WLAN_EID_CHANNEL_MEASURE_FEEDBACK = 154, + /* 155-156 reserved for Cisco */ WLAN_EID_AWAKE_WINDOW = 157, WLAN_EID_MULTI_BAND = 158, WLAN_EID_ADDBA_EXT = 159, @@ -1781,11 +1800,34 @@ enum ieee80211_eid { WLAN_EID_MULTIPLE_MAC_ADDR = 170, WLAN_EID_U_PID = 171, WLAN_EID_DMG_LINK_ADAPT_ACK = 172, + /* 173 reserved for Symbol */ + WLAN_EID_MCCAOP_ADV_OVERVIEW = 174, WLAN_EID_QUIET_PERIOD_REQ = 175, + /* 176 reserved for Symbol */ WLAN_EID_QUIET_PERIOD_RESP = 177, + /* 178-179 reserved for Symbol */ + /* 180 reserved for ISO/IEC 20011 */ WLAN_EID_EPAC_POLICY = 182, WLAN_EID_CLISTER_TIME_OFF = 183, + WLAN_EID_INTER_AC_PRIO = 184, + WLAN_EID_SCS_DESCRIPTOR = 185, + WLAN_EID_QLOAD_REPORT = 186, + WLAN_EID_HCCA_TXOP_UPDATE_COUNT = 187, + WLAN_EID_HL_STREAM_ID = 188, + WLAN_EID_GCR_GROUP_ADDR = 189, WLAN_EID_ANTENNA_SECTOR_ID_PATTERN = 190, + WLAN_EID_VHT_CAPABILITY = 191, + WLAN_EID_VHT_OPERATION = 192, + WLAN_EID_EXTENDED_BSS_LOAD = 193, + WLAN_EID_WIDE_BW_CHANNEL_SWITCH = 194, + WLAN_EID_VHT_TX_POWER_ENVELOPE = 195, + WLAN_EID_CHANNEL_SWITCH_WRAPPER = 196, + WLAN_EID_AID = 197, + WLAN_EID_QUIET_CHANNEL = 198, + WLAN_EID_OPMODE_NOTIF = 199, + + WLAN_EID_VENDOR_SPECIFIC = 221, + WLAN_EID_QOS_PARAMETER = 222, }; /* Action category code */ -- cgit v1.3-8-gc7d7 From 006e983bbc805431c44e2135e13841f66059a045 Mon Sep 17 00:00:00 2001 From: Sricharan R Date: Tue, 3 Dec 2013 15:57:22 +0530 Subject: DRIVERS: IRQCHIP: IRQ-GIC: Add support for routable irqs In some socs the gic can be preceded by a crossbar IP which routes the peripheral interrupts to the gic inputs. The peripheral interrupts are associated with a fixed crossbar input line and the crossbar routes that to one of the free gic input line. The DT entries for peripherals provides the fixed crossbar input line as its interrupt number and the mapping code should associate this with a free gic input line. This patch adds the support inside the gic irqchip to handle such routable irqs. The routable irqs are registered in a linear domain. The registered routable domain's callback should be implemented to get a free irq and to configure the IP to route it. Cc: Thomas Gleixner Cc: Linus Walleij Cc: Santosh Shilimkar Cc: Russell King Cc: Tony Lindgren Cc: Rajendra Nayak Cc: Marc Zyngier Cc: Grant Likely Cc: Rob Herring Signed-off-by: Sricharan R Reviewed-by: Thomas Gleixner Acked-by: Santosh Shilimkar Acked-by: Linus Walleij --- Documentation/devicetree/bindings/arm/gic.txt | 6 ++ drivers/irqchip/irq-gic.c | 82 +++++++++++++++++++++++---- include/linux/irqchip/arm-gic.h | 7 ++- 3 files changed, 84 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt index bae0d87a38b2..5573c08d3180 100644 --- a/Documentation/devicetree/bindings/arm/gic.txt +++ b/Documentation/devicetree/bindings/arm/gic.txt @@ -50,6 +50,11 @@ Optional regions, used when the GIC doesn't have banked registers. The offset is cpu-offset * cpu-nr. +- arm,routable-irqs : Total number of gic irq inputs which are not directly + connected from the peripherals, but are routed dynamically + by a crossbar/multiplexer preceding the GIC. The GIC irq + input line is assigned dynamically when the corresponding + peripheral's crossbar line is mapped. Example: intc: interrupt-controller@fff11000 { @@ -57,6 +62,7 @@ Example: #interrupt-cells = <3>; #address-cells = <1>; interrupt-controller; + arm,routable-irqs = <160>; reg = <0xfff11000 0x1000>, <0xfff10100 0x100>; }; diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 341c6016812d..07a7050841ec 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -824,16 +824,25 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_set_chip_and_handler(irq, &gic_chip, handle_fasteoi_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + + gic_routable_irq_domain_ops->map(d, irq, hw); } irq_set_chip_data(irq, d->host_data); return 0; } +static void gic_irq_domain_unmap(struct irq_domain *d, unsigned int irq) +{ + gic_routable_irq_domain_ops->unmap(d, irq); +} + static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *controller, const u32 *intspec, unsigned int intsize, unsigned long *out_hwirq, unsigned int *out_type) { + unsigned long ret = 0; + if (d->of_node != controller) return -EINVAL; if (intsize < 3) @@ -843,11 +852,20 @@ static int gic_irq_domain_xlate(struct irq_domain *d, *out_hwirq = intspec[1] + 16; /* For SPIs, we need to add 16 more to get the GIC irq ID number */ - if (!intspec[0]) - *out_hwirq += 16; + if (!intspec[0]) { + ret = gic_routable_irq_domain_ops->xlate(d, controller, + intspec, + intsize, + out_hwirq, + out_type); + + if (IS_ERR_VALUE(ret)) + return ret; + } *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; - return 0; + + return ret; } #ifdef CONFIG_SMP @@ -871,9 +889,41 @@ static struct notifier_block gic_cpu_notifier = { const struct irq_domain_ops gic_irq_domain_ops = { .map = gic_irq_domain_map, + .unmap = gic_irq_domain_unmap, .xlate = gic_irq_domain_xlate, }; +/* Default functions for routable irq domain */ +static int gic_routable_irq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + return 0; +} + +static void gic_routable_irq_domain_unmap(struct irq_domain *d, + unsigned int irq) +{ +} + +static int gic_routable_irq_domain_xlate(struct irq_domain *d, + struct device_node *controller, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + *out_hwirq += 16; + return 0; +} + +const struct irq_domain_ops gic_default_routable_irq_domain_ops = { + .map = gic_routable_irq_domain_map, + .unmap = gic_routable_irq_domain_unmap, + .xlate = gic_routable_irq_domain_xlate, +}; + +const struct irq_domain_ops *gic_routable_irq_domain_ops = + &gic_default_routable_irq_domain_ops; + void __init gic_init_bases(unsigned int gic_nr, int irq_start, void __iomem *dist_base, void __iomem *cpu_base, u32 percpu_offset, struct device_node *node) @@ -881,6 +931,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, irq_hw_number_t hwirq_base; struct gic_chip_data *gic; int gic_irqs, irq_base, i; + int nr_routable_irqs; BUG_ON(gic_nr >= MAX_GIC_NR); @@ -946,14 +997,25 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, gic->gic_irqs = gic_irqs; gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */ - irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id()); - if (IS_ERR_VALUE(irq_base)) { - WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", - irq_start); - irq_base = irq_start; + + if (of_property_read_u32(node, "arm,routable-irqs", + &nr_routable_irqs)) { + irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, + numa_node_id()); + if (IS_ERR_VALUE(irq_base)) { + WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", + irq_start); + irq_base = irq_start; + } + + gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base, + hwirq_base, &gic_irq_domain_ops, gic); + } else { + gic->domain = irq_domain_add_linear(node, nr_routable_irqs, + &gic_irq_domain_ops, + gic); } - gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base, - hwirq_base, &gic_irq_domain_ops, gic); + if (WARN_ON(!gic->domain)) return; diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 0ceb389dba6c..7ed92d0560d5 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -93,6 +93,11 @@ int gic_get_cpu_id(unsigned int cpu); void gic_migrate_target(unsigned int new_cpu_id); unsigned long gic_get_sgir_physaddr(void); +extern const struct irq_domain_ops *gic_routable_irq_domain_ops; +static inline void __init register_routable_domain_ops + (const struct irq_domain_ops *ops) +{ + gic_routable_irq_domain_ops = ops; +} #endif /* __ASSEMBLY */ - #endif -- cgit v1.3-8-gc7d7 From 96ca848ef7ea1be7e92d1cceb34ef3aa86053828 Mon Sep 17 00:00:00 2001 From: Sricharan R Date: Tue, 3 Dec 2013 15:57:23 +0530 Subject: DRIVERS: IRQCHIP: CROSSBAR: Add support for Crossbar IP Some socs have a large number of interrupts requests to service the needs of its many peripherals and subsystems. All of the interrupt lines from the subsystems are not needed at the same time, so they have to be muxed to the irq-controller appropriately. In such places a interrupt controllers are preceded by an CROSSBAR that provides flexibility in muxing the device requests to the controller inputs. This driver takes care a allocating a free irq and then configuring the crossbar IP as a part of the mpu's irqchip callbacks. crossbar_init should be called right before the irqchip_init, so that it is setup to handle the irqchip callbacks. Cc: Thomas Gleixner Cc: Linus Walleij Cc: Santosh Shilimkar Cc: Russell King Cc: Tony Lindgren Cc: Rajendra Nayak Cc: Marc Zyngier Cc: Grant Likely Cc: Rob Herring Signed-off-by: Sricharan R Acked-by: Kumar Gala (for DT binding portion) Acked-by: Santosh Shilimkar Acked-by: Linus Walleij Acked-by: Thomas Gleixner --- .../devicetree/bindings/arm/omap/crossbar.txt | 27 +++ drivers/irqchip/Kconfig | 8 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-crossbar.c | 208 +++++++++++++++++++++ include/linux/irqchip/irq-crossbar.h | 11 ++ 5 files changed, 255 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/omap/crossbar.txt create mode 100644 drivers/irqchip/irq-crossbar.c create mode 100644 include/linux/irqchip/irq-crossbar.h (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/arm/omap/crossbar.txt b/Documentation/devicetree/bindings/arm/omap/crossbar.txt new file mode 100644 index 000000000000..fb88585cfb93 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/omap/crossbar.txt @@ -0,0 +1,27 @@ +Some socs have a large number of interrupts requests to service +the needs of its many peripherals and subsystems. All of the +interrupt lines from the subsystems are not needed at the same +time, so they have to be muxed to the irq-controller appropriately. +In such places a interrupt controllers are preceded by an CROSSBAR +that provides flexibility in muxing the device requests to the controller +inputs. + +Required properties: +- compatible : Should be "ti,irq-crossbar" +- reg: Base address and the size of the crossbar registers. +- ti,max-irqs: Total number of irqs available at the interrupt controller. +- ti,reg-size: Size of a individual register in bytes. Every individual + register is assumed to be of same size. Valid sizes are 1, 2, 4. +- ti,irqs-reserved: List of the reserved irq lines that are not muxed using + crossbar. These interrupt lines are reserved in the soc, + so crossbar bar driver should not consider them as free + lines. + +Examples: + crossbar_mpu: @4a020000 { + compatible = "ti,irq-crossbar"; + reg = <0x4a002a48 0x130>; + ti,max-irqs = <160>; + ti,reg-size = <2>; + ti,irqs-reserved = <0 1 2 3 5 6 131 132 139 140>; + }; diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 61ffdca96e25..111068782da4 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -69,3 +69,11 @@ config VERSATILE_FPGA_IRQ_NR config XTENSA_MX bool select IRQ_DOMAIN + +config IRQ_CROSSBAR + bool + help + Support for a CROSSBAR ip that preceeds the main interrupt controller. + The primary irqchip invokes the crossbar's callback which inturn allocates + a free irq and configures the IP. Thus the peripheral interrupts are + routed to one of the free irqchip interrupt lines. diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 86b484cb3ec2..3e776cb8dd46 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o +obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c new file mode 100644 index 000000000000..fc817d28d1fe --- /dev/null +++ b/drivers/irqchip/irq-crossbar.c @@ -0,0 +1,208 @@ +/* + * drivers/irqchip/irq-crossbar.c + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * Author: Sricharan R + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include +#include +#include +#include + +#define IRQ_FREE -1 +#define GIC_IRQ_START 32 + +/* + * @int_max: maximum number of supported interrupts + * @irq_map: array of interrupts to crossbar number mapping + * @crossbar_base: crossbar base address + * @register_offsets: offsets for each irq number + */ +struct crossbar_device { + uint int_max; + uint *irq_map; + void __iomem *crossbar_base; + int *register_offsets; + void (*write) (int, int); +}; + +static struct crossbar_device *cb; + +static inline void crossbar_writel(int irq_no, int cb_no) +{ + writel(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); +} + +static inline void crossbar_writew(int irq_no, int cb_no) +{ + writew(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); +} + +static inline void crossbar_writeb(int irq_no, int cb_no) +{ + writeb(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); +} + +static inline int allocate_free_irq(int cb_no) +{ + int i; + + for (i = 0; i < cb->int_max; i++) { + if (cb->irq_map[i] == IRQ_FREE) { + cb->irq_map[i] = cb_no; + return i; + } + } + + return -ENODEV; +} + +static int crossbar_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + cb->write(hw - GIC_IRQ_START, cb->irq_map[hw - GIC_IRQ_START]); + return 0; +} + +static void crossbar_domain_unmap(struct irq_domain *d, unsigned int irq) +{ + irq_hw_number_t hw = irq_get_irq_data(irq)->hwirq; + + if (hw > GIC_IRQ_START) + cb->irq_map[hw - GIC_IRQ_START] = IRQ_FREE; +} + +static int crossbar_domain_xlate(struct irq_domain *d, + struct device_node *controller, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + unsigned long ret; + + ret = allocate_free_irq(intspec[1]); + + if (IS_ERR_VALUE(ret)) + return ret; + + *out_hwirq = ret + GIC_IRQ_START; + return 0; +} + +const struct irq_domain_ops routable_irq_domain_ops = { + .map = crossbar_domain_map, + .unmap = crossbar_domain_unmap, + .xlate = crossbar_domain_xlate +}; + +static int __init crossbar_of_init(struct device_node *node) +{ + int i, size, max, reserved = 0, entry; + const __be32 *irqsr; + + cb = kzalloc(sizeof(struct cb_device *), GFP_KERNEL); + + if (!cb) + return -ENOMEM; + + cb->crossbar_base = of_iomap(node, 0); + if (!cb->crossbar_base) + goto err1; + + of_property_read_u32(node, "ti,max-irqs", &max); + cb->irq_map = kzalloc(max * sizeof(int), GFP_KERNEL); + if (!cb->irq_map) + goto err2; + + cb->int_max = max; + + for (i = 0; i < max; i++) + cb->irq_map[i] = IRQ_FREE; + + /* Get and mark reserved irqs */ + irqsr = of_get_property(node, "ti,irqs-reserved", &size); + if (irqsr) { + size /= sizeof(__be32); + + for (i = 0; i < size; i++) { + of_property_read_u32_index(node, + "ti,irqs-reserved", + i, &entry); + if (entry > max) { + pr_err("Invalid reserved entry\n"); + goto err3; + } + cb->irq_map[entry] = 0; + } + } + + cb->register_offsets = kzalloc(max * sizeof(int), GFP_KERNEL); + if (!cb->register_offsets) + goto err3; + + of_property_read_u32(node, "ti,reg-size", &size); + + switch (size) { + case 1: + cb->write = crossbar_writeb; + break; + case 2: + cb->write = crossbar_writew; + break; + case 4: + cb->write = crossbar_writel; + break; + default: + pr_err("Invalid reg-size property\n"); + goto err4; + break; + } + + /* + * Register offsets are not linear because of the + * reserved irqs. so find and store the offsets once. + */ + for (i = 0; i < max; i++) { + if (!cb->irq_map[i]) + continue; + + cb->register_offsets[i] = reserved; + reserved += size; + } + + register_routable_domain_ops(&routable_irq_domain_ops); + return 0; + +err4: + kfree(cb->register_offsets); +err3: + kfree(cb->irq_map); +err2: + iounmap(cb->crossbar_base); +err1: + kfree(cb); + return -ENOMEM; +} + +static const struct of_device_id crossbar_match[] __initconst = { + { .compatible = "ti,irq-crossbar" }, + {} +}; + +int __init irqcrossbar_init(void) +{ + struct device_node *np; + np = of_find_matching_node(NULL, crossbar_match); + if (!np) + return -ENODEV; + + crossbar_of_init(np); + return 0; +} diff --git a/include/linux/irqchip/irq-crossbar.h b/include/linux/irqchip/irq-crossbar.h new file mode 100644 index 000000000000..e5537b81df8d --- /dev/null +++ b/include/linux/irqchip/irq-crossbar.h @@ -0,0 +1,11 @@ +/* + * drivers/irqchip/irq-crossbar.h + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +int irqcrossbar_init(void); -- cgit v1.3-8-gc7d7 From 781f6d710d4482eab05cfaad50060a0ea8c0e4e0 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Thu, 30 Jan 2014 13:18:57 +0000 Subject: gpio: generic: Add label to platform data When registering more than one platform device, it is useful to set the gpio chip label in the platform data. Signed-off-by: Pawel Moll Signed-off-by: Linus Walleij --- drivers/gpio/gpio-generic.c | 2 ++ include/linux/basic_mmio_gpio.h | 1 + 2 files changed, 3 insertions(+) (limited to 'include/linux') diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index d2196bf73847..8c778afdf49f 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -531,6 +531,8 @@ static int bgpio_pdev_probe(struct platform_device *pdev) return err; if (pdata) { + if (pdata->label) + bgc->gc.label = pdata->label; bgc->gc.base = pdata->base; if (pdata->ngpio > 0) bgc->gc.ngpio = pdata->ngpio; diff --git a/include/linux/basic_mmio_gpio.h b/include/linux/basic_mmio_gpio.h index d8a97ec0e2b8..0e97856b2cff 100644 --- a/include/linux/basic_mmio_gpio.h +++ b/include/linux/basic_mmio_gpio.h @@ -19,6 +19,7 @@ #include struct bgpio_pdata { + const char *label; int base; int ngpio; }; -- cgit v1.3-8-gc7d7 From ef70bbe1aaa612f75360e5df5952fddec50b7ca9 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 7 Jan 2014 12:34:11 +0100 Subject: gpio: make gpiod_direction_output take a logical value The documentation was not clear about whether gpio_direction_output should take a logical value or the physical level on the output line, i.e. whether the ACTIVE_LOW status would be taken into account. This converts gpiod_direction_output to use the logical level and adds a new gpiod_direction_output_raw for the raw value. Signed-off-by: Philipp Zabel Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- Documentation/gpio/consumer.txt | 1 + drivers/gpio/gpiolib.c | 67 +++++++++++++++++++++++++++++------------ include/asm-generic/gpio.h | 2 +- include/linux/gpio/consumer.h | 7 +++++ 4 files changed, 57 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt index e42f77d8d4ca..09854fe59307 100644 --- a/Documentation/gpio/consumer.txt +++ b/Documentation/gpio/consumer.txt @@ -154,6 +154,7 @@ raw line value: void gpiod_set_raw_value(struct gpio_desc *desc, int value) int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value) + int gpiod_direction_output_raw(struct gpio_desc *desc, int value) The active-low state of a GPIO can also be queried using the following call: diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 50c4922fe53a..80da9f1940c9 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -350,9 +350,9 @@ static ssize_t gpio_direction_store(struct device *dev, if (!test_bit(FLAG_EXPORT, &desc->flags)) status = -EIO; else if (sysfs_streq(buf, "high")) - status = gpiod_direction_output(desc, 1); + status = gpiod_direction_output_raw(desc, 1); else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low")) - status = gpiod_direction_output(desc, 0); + status = gpiod_direction_output_raw(desc, 0); else if (sysfs_streq(buf, "in")) status = gpiod_direction_input(desc); else @@ -1590,7 +1590,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) if (flags & GPIOF_DIR_IN) err = gpiod_direction_input(desc); else - err = gpiod_direction_output(desc, + err = gpiod_direction_output_raw(desc, (flags & GPIOF_INIT_HIGH) ? 1 : 0); if (err) @@ -1756,28 +1756,13 @@ fail: } EXPORT_SYMBOL_GPL(gpiod_direction_input); -/** - * gpiod_direction_output - set the GPIO direction to input - * @desc: GPIO to set to output - * @value: initial output value of the GPIO - * - * Set the direction of the passed GPIO to output, such as gpiod_set_value() can - * be called safely on it. The initial value of the output must be specified. - * - * Return 0 in case of success, else an error code. - */ -int gpiod_direction_output(struct gpio_desc *desc, int value) +static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) { unsigned long flags; struct gpio_chip *chip; int status = -EINVAL; int offset; - if (!desc || !desc->chip) { - pr_warn("%s: invalid GPIO\n", __func__); - return -EINVAL; - } - /* GPIOs used for IRQs shall not be set as output */ if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { gpiod_err(desc, @@ -1840,6 +1825,50 @@ fail: gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status); return status; } + +/** + * gpiod_direction_output_raw - set the GPIO direction to output + * @desc: GPIO to set to output + * @value: initial output value of the GPIO + * + * Set the direction of the passed GPIO to output, such as gpiod_set_value() can + * be called safely on it. The initial value of the output must be specified + * as raw value on the physical line without regard for the ACTIVE_LOW status. + * + * Return 0 in case of success, else an error code. + */ +int gpiod_direction_output_raw(struct gpio_desc *desc, int value) +{ + if (!desc || !desc->chip) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + return _gpiod_direction_output_raw(desc, value); +} +EXPORT_SYMBOL_GPL(gpiod_direction_output_raw); + +/** + * gpiod_direction_output - set the GPIO direction to input + * @desc: GPIO to set to output + * @value: initial output value of the GPIO + * + * Set the direction of the passed GPIO to output, such as gpiod_set_value() can + * be called safely on it. The initial value of the output must be specified + * as the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into + * account. + * + * Return 0 in case of success, else an error code. + */ +int gpiod_direction_output(struct gpio_desc *desc, int value) +{ + if (!desc || !desc->chip) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + value = !value; + return _gpiod_direction_output_raw(desc, value); +} EXPORT_SYMBOL_GPL(gpiod_direction_output); /** diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index a5f56a0213a7..23e364538ab5 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -69,7 +69,7 @@ static inline int gpio_direction_input(unsigned gpio) } static inline int gpio_direction_output(unsigned gpio, int value) { - return gpiod_direction_output(gpio_to_desc(gpio), value); + return gpiod_direction_output_raw(gpio_to_desc(gpio), value); } static inline int gpio_set_debounce(unsigned gpio, unsigned debounce) diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 4d34dbbbad4d..387994325122 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -36,6 +36,7 @@ void devm_gpiod_put(struct device *dev, struct gpio_desc *desc); int gpiod_get_direction(const struct gpio_desc *desc); int gpiod_direction_input(struct gpio_desc *desc); int gpiod_direction_output(struct gpio_desc *desc, int value); +int gpiod_direction_output_raw(struct gpio_desc *desc, int value); /* Value get/set from non-sleeping context */ int gpiod_get_value(const struct gpio_desc *desc); @@ -121,6 +122,12 @@ static inline int gpiod_direction_output(struct gpio_desc *desc, int value) WARN_ON(1); return -ENOSYS; } +static inline int gpiod_direction_output_raw(struct gpio_desc *desc, int value) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -ENOSYS; +} static inline int gpiod_get_value(const struct gpio_desc *desc) -- cgit v1.3-8-gc7d7 From f315e3fa1cf5b3317fc948708645fff889ce1e63 Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Mon, 2 Dec 2013 17:49:41 +0900 Subject: slab: restrict the number of objects in a slab To prepare to implement byte sized index for managing the freelist of a slab, we should restrict the number of objects in a slab to be less or equal to 256, since byte only represent 256 different values. Setting the size of object to value equal or more than newly introduced SLAB_OBJ_MIN_SIZE ensures that the number of objects in a slab is less or equal to 256 for a slab with 1 page. If page size is rather larger than 4096, above assumption would be wrong. In this case, we would fall back on 2 bytes sized index. If minimum size of kmalloc is less than 16, we use it as minimum object size and give up this optimization. Signed-off-by: Joonsoo Kim Signed-off-by: Pekka Enberg --- include/linux/slab.h | 11 +++++++++++ mm/slab.c | 21 +++++++++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'include/linux') diff --git a/include/linux/slab.h b/include/linux/slab.h index 9260abdd67df..d015dec02bf3 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -201,6 +201,17 @@ struct kmem_cache { #ifndef KMALLOC_SHIFT_LOW #define KMALLOC_SHIFT_LOW 5 #endif + +/* + * This restriction comes from byte sized index implementation. + * Page size is normally 2^12 bytes and, in this case, if we want to use + * byte sized index which can represent 2^8 entries, the size of the object + * should be equal or greater to 2^12 / 2^8 = 2^4 = 16. + * If minimum size of kmalloc is less than 16, we use it as minimum object + * size and give up to use byte sized index. + */ +#define SLAB_OBJ_MIN_SIZE (KMALLOC_SHIFT_LOW < 4 ? \ + (1 << KMALLOC_SHIFT_LOW) : 16) #endif #ifdef CONFIG_SLUB diff --git a/mm/slab.c b/mm/slab.c index 878354b26b72..9d4c7b50dfdc 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -157,6 +157,17 @@ #define ARCH_KMALLOC_FLAGS SLAB_HWCACHE_ALIGN #endif +#define FREELIST_BYTE_INDEX (((PAGE_SIZE >> BITS_PER_BYTE) \ + <= SLAB_OBJ_MIN_SIZE) ? 1 : 0) + +#if FREELIST_BYTE_INDEX +typedef unsigned char freelist_idx_t; +#else +typedef unsigned short freelist_idx_t; +#endif + +#define SLAB_OBJ_MAX_NUM (1 << sizeof(freelist_idx_t) * BITS_PER_BYTE) + /* * true if a page was allocated from pfmemalloc reserves for network-based * swap @@ -2016,6 +2027,10 @@ static size_t calculate_slab_order(struct kmem_cache *cachep, if (!num) continue; + /* Can't handle number of objects more than SLAB_OBJ_MAX_NUM */ + if (num > SLAB_OBJ_MAX_NUM) + break; + if (flags & CFLGS_OFF_SLAB) { /* * Max number of objs-per-slab for caches which @@ -2258,6 +2273,12 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags) flags |= CFLGS_OFF_SLAB; size = ALIGN(size, cachep->align); + /* + * We should restrict the number of objects in a slab to implement + * byte sized index. Refer comment on SLAB_OBJ_MIN_SIZE definition. + */ + if (FREELIST_BYTE_INDEX && size < SLAB_OBJ_MIN_SIZE) + size = ALIGN(SLAB_OBJ_MIN_SIZE, cachep->align); left_over = calculate_slab_order(cachep, size, cachep->align, flags); -- cgit v1.3-8-gc7d7 From 3ed80a62bf959d34ebd4d553b026fbe7e6fbcc54 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 8 Feb 2014 10:36:58 -0500 Subject: cgroup: drop module support With module supported dropped from net_prio, no controller is using cgroup module support. None of actual resource controllers can be built as a module and we aren't gonna add new controllers which don't control resources. This patch drops module support from cgroup. * cgroup_[un]load_subsys() and cgroup_subsys->module removed. * As there's no point in distinguishing IS_BUILTIN() and IS_MODULE(), cgroup_subsys.h now uses IS_ENABLED() directly. * enum cgroup_subsys_id now exactly matches the list of enabled controllers as ordered in cgroup_subsys.h. * cgroup_subsys[] is now a contiguously occupied array. Size specification is no longer necessary and dropped. * for_each_builtin_subsys() is removed and for_each_subsys() is updated to not require any locking. * module ref handling is removed from rebind_subsystems(). * Module related comments dropped. v2: Rebased on top of fe1217c4f3f7 ("net: net_cls: move cgroupfs classid handling into core"). v3: Added {} around the if (need_forkexit_callback) block in cgroup_post_fork() for readability as suggested by Li. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- block/blk-cgroup.c | 1 - include/linux/cgroup.h | 29 +---- include/linux/cgroup_subsys.h | 24 ++-- kernel/cgroup.c | 284 +++--------------------------------------- net/core/netclassid_cgroup.c | 1 - net/core/netprio_cgroup.c | 1 - 6 files changed, 32 insertions(+), 308 deletions(-) (limited to 'include/linux') diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 4e491d9b5292..660d419918a7 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -914,7 +914,6 @@ struct cgroup_subsys blkio_subsys = { .can_attach = blkcg_can_attach, .subsys_id = blkio_subsys_id, .base_cftypes = blkcg_files, - .module = THIS_MODULE, }; EXPORT_SYMBOL_GPL(blkio_subsys); diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 5c097596104b..d842a737d448 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -37,28 +37,13 @@ extern void cgroup_post_fork(struct task_struct *p); extern void cgroup_exit(struct task_struct *p, int run_callbacks); extern int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry); -extern int cgroup_load_subsys(struct cgroup_subsys *ss); -extern void cgroup_unload_subsys(struct cgroup_subsys *ss); extern int proc_cgroup_show(struct seq_file *, void *); -/* - * Define the enumeration of all cgroup subsystems. - * - * We define ids for builtin subsystems and then modular ones. - */ +/* define the enumeration of all cgroup subsystems */ #define SUBSYS(_x) _x ## _subsys_id, enum cgroup_subsys_id { -#define IS_SUBSYS_ENABLED(option) IS_BUILTIN(option) #include -#undef IS_SUBSYS_ENABLED - CGROUP_BUILTIN_SUBSYS_COUNT, - - __CGROUP_SUBSYS_TEMP_PLACEHOLDER = CGROUP_BUILTIN_SUBSYS_COUNT - 1, - -#define IS_SUBSYS_ENABLED(option) IS_MODULE(option) -#include -#undef IS_SUBSYS_ENABLED CGROUP_SUBSYS_COUNT, }; #undef SUBSYS @@ -370,10 +355,9 @@ struct css_set { struct list_head cgrp_links; /* - * Set of subsystem states, one for each subsystem. This array - * is immutable after creation apart from the init_css_set - * during subsystem registration (at boot time) and modular subsystem - * loading/unloading. + * Set of subsystem states, one for each subsystem. This array is + * immutable after creation apart from the init_css_set during + * subsystem registration (at boot time). */ struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT]; @@ -620,15 +604,10 @@ struct cgroup_subsys { /* base cftypes, automatically [de]registered with subsys itself */ struct cftype *base_cftypes; struct cftype_set base_cftset; - - /* should be defined only by modular subsystems */ - struct module *module; }; #define SUBSYS(_x) extern struct cgroup_subsys _x ## _subsys; -#define IS_SUBSYS_ENABLED(option) IS_BUILTIN(option) #include -#undef IS_SUBSYS_ENABLED #undef SUBSYS /** diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h index 7b99d717411d..11c42f6a25a8 100644 --- a/include/linux/cgroup_subsys.h +++ b/include/linux/cgroup_subsys.h @@ -3,51 +3,51 @@ * * DO NOT ADD ANY SUBSYSTEM WITHOUT EXPLICIT ACKS FROM CGROUP MAINTAINERS. */ -#if IS_SUBSYS_ENABLED(CONFIG_CPUSETS) +#if IS_ENABLED(CONFIG_CPUSETS) SUBSYS(cpuset) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_DEBUG) +#if IS_ENABLED(CONFIG_CGROUP_DEBUG) SUBSYS(debug) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_SCHED) +#if IS_ENABLED(CONFIG_CGROUP_SCHED) SUBSYS(cpu_cgroup) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_CPUACCT) +#if IS_ENABLED(CONFIG_CGROUP_CPUACCT) SUBSYS(cpuacct) #endif -#if IS_SUBSYS_ENABLED(CONFIG_MEMCG) +#if IS_ENABLED(CONFIG_MEMCG) SUBSYS(mem_cgroup) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_DEVICE) +#if IS_ENABLED(CONFIG_CGROUP_DEVICE) SUBSYS(devices) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_FREEZER) +#if IS_ENABLED(CONFIG_CGROUP_FREEZER) SUBSYS(freezer) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_NET_CLASSID) +#if IS_ENABLED(CONFIG_CGROUP_NET_CLASSID) SUBSYS(net_cls) #endif -#if IS_SUBSYS_ENABLED(CONFIG_BLK_CGROUP) +#if IS_ENABLED(CONFIG_BLK_CGROUP) SUBSYS(blkio) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_PERF) +#if IS_ENABLED(CONFIG_CGROUP_PERF) SUBSYS(perf) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_NET_PRIO) +#if IS_ENABLED(CONFIG_CGROUP_NET_PRIO) SUBSYS(net_prio) #endif -#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_HUGETLB) +#if IS_ENABLED(CONFIG_CGROUP_HUGETLB) SUBSYS(hugetlb) #endif /* diff --git a/kernel/cgroup.c b/kernel/cgroup.c index e2f46ba37f72..ccb16b47e293 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -120,15 +119,9 @@ static struct workqueue_struct *cgroup_destroy_wq; */ static struct workqueue_struct *cgroup_pidlist_destroy_wq; -/* - * Generate an array of cgroup subsystem pointers. At boot time, this is - * populated with the built in subsystems, and modular subsystems are - * registered after that. The mutable section of this array is protected by - * cgroup_mutex. - */ +/* generate an array of cgroup subsystem pointers */ #define SUBSYS(_x) [_x ## _subsys_id] = &_x ## _subsys, -#define IS_SUBSYS_ENABLED(option) IS_BUILTIN(option) -static struct cgroup_subsys *cgroup_subsys[CGROUP_SUBSYS_COUNT] = { +static struct cgroup_subsys *cgroup_subsys[] = { #include }; @@ -258,30 +251,13 @@ static int notify_on_release(const struct cgroup *cgrp) else /** - * for_each_subsys - iterate all loaded cgroup subsystems + * for_each_subsys - iterate all enabled cgroup subsystems * @ss: the iteration cursor * @ssid: the index of @ss, CGROUP_SUBSYS_COUNT after reaching the end - * - * Iterates through all loaded subsystems. Should be called under - * cgroup_mutex or cgroup_root_mutex. */ #define for_each_subsys(ss, ssid) \ - for (({ cgroup_assert_mutex_or_root_locked(); (ssid) = 0; }); \ - (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \ - if (!((ss) = cgroup_subsys[(ssid)])) { } \ - else - -/** - * for_each_builtin_subsys - iterate all built-in cgroup subsystems - * @ss: the iteration cursor - * @i: the index of @ss, CGROUP_BUILTIN_SUBSYS_COUNT after reaching the end - * - * Bulit-in subsystems are always present and iteration itself doesn't - * require any synchronization. - */ -#define for_each_builtin_subsys(ss, i) \ - for ((i) = 0; (i) < CGROUP_BUILTIN_SUBSYS_COUNT && \ - (((ss) = cgroup_subsys[i]) || true); (i)++) + for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT && \ + (((ss) = cgroup_subsys[ssid]) || true); (ssid)++) /* iterate across the active hierarchies */ #define for_each_active_root(root) \ @@ -975,50 +951,24 @@ static void cgroup_d_remove_dir(struct dentry *dentry) remove_dir(dentry); } -/* - * Call with cgroup_mutex held. Drops reference counts on modules, including - * any duplicate ones that parse_cgroupfs_options took. If this function - * returns an error, no reference counts are touched. - */ static int rebind_subsystems(struct cgroupfs_root *root, unsigned long added_mask, unsigned removed_mask) { struct cgroup *cgrp = &root->top_cgroup; struct cgroup_subsys *ss; - unsigned long pinned = 0; int i, ret; BUG_ON(!mutex_is_locked(&cgroup_mutex)); BUG_ON(!mutex_is_locked(&cgroup_root_mutex)); /* Check that any added subsystems are currently free */ - for_each_subsys(ss, i) { - if (!(added_mask & (1 << i))) - continue; - - /* is the subsystem mounted elsewhere? */ - if (ss->root != &cgroup_dummy_root) { - ret = -EBUSY; - goto out_put; - } - - /* pin the module */ - if (!try_module_get(ss->module)) { - ret = -ENOENT; - goto out_put; - } - pinned |= 1 << i; - } - - /* subsys could be missing if unloaded between parsing and here */ - if (added_mask != pinned) { - ret = -ENOENT; - goto out_put; - } + for_each_subsys(ss, i) + if ((added_mask & (1 << i)) && ss->root != &cgroup_dummy_root) + return -EBUSY; ret = cgroup_populate_dir(cgrp, added_mask); if (ret) - goto out_put; + return ret; /* * Nothing can fail from this point on. Remove files for the @@ -1057,9 +1007,6 @@ static int rebind_subsystems(struct cgroupfs_root *root, RCU_INIT_POINTER(cgrp->subsys[i], NULL); cgroup_subsys[i]->root = &cgroup_dummy_root; - - /* subsystem is now free - drop reference on module */ - module_put(ss->module); root->subsys_mask &= ~bit; } } @@ -1071,12 +1018,6 @@ static int rebind_subsystems(struct cgroupfs_root *root, root->flags |= CGRP_ROOT_SUBSYS_BOUND; return 0; - -out_put: - for_each_subsys(ss, i) - if (pinned & (1 << i)) - module_put(ss->module); - return ret; } static int cgroup_show_options(struct seq_file *seq, struct dentry *dentry) @@ -4506,7 +4447,7 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry) return ret; } -static void __init_or_module cgroup_init_cftsets(struct cgroup_subsys *ss) +static void __init cgroup_init_cftsets(struct cgroup_subsys *ss) { INIT_LIST_HEAD(&ss->cftsets); @@ -4559,185 +4500,8 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss) BUG_ON(online_css(css)); mutex_unlock(&cgroup_mutex); - - /* this function shouldn't be used with modular subsystems, since they - * need to register a subsys_id, among other things */ - BUG_ON(ss->module); } -/** - * cgroup_load_subsys: load and register a modular subsystem at runtime - * @ss: the subsystem to load - * - * This function should be called in a modular subsystem's initcall. If the - * subsystem is built as a module, it will be assigned a new subsys_id and set - * up for use. If the subsystem is built-in anyway, work is delegated to the - * simpler cgroup_init_subsys. - */ -int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss) -{ - struct cgroup_subsys_state *css; - int i, ret; - struct hlist_node *tmp; - struct css_set *cset; - unsigned long key; - - /* check name and function validity */ - if (ss->name == NULL || strlen(ss->name) > MAX_CGROUP_TYPE_NAMELEN || - ss->css_alloc == NULL || ss->css_free == NULL) - return -EINVAL; - - /* - * we don't support callbacks in modular subsystems. this check is - * before the ss->module check for consistency; a subsystem that could - * be a module should still have no callbacks even if the user isn't - * compiling it as one. - */ - if (ss->fork || ss->exit) - return -EINVAL; - - /* - * an optionally modular subsystem is built-in: we want to do nothing, - * since cgroup_init_subsys will have already taken care of it. - */ - if (ss->module == NULL) { - /* a sanity check */ - BUG_ON(cgroup_subsys[ss->subsys_id] != ss); - return 0; - } - - /* init base cftset */ - cgroup_init_cftsets(ss); - - mutex_lock(&cgroup_mutex); - mutex_lock(&cgroup_root_mutex); - cgroup_subsys[ss->subsys_id] = ss; - - /* - * no ss->css_alloc seems to need anything important in the ss - * struct, so this can happen first (i.e. before the dummy root - * attachment). - */ - css = ss->css_alloc(cgroup_css(cgroup_dummy_top, ss)); - if (IS_ERR(css)) { - /* failure case - need to deassign the cgroup_subsys[] slot. */ - cgroup_subsys[ss->subsys_id] = NULL; - mutex_unlock(&cgroup_root_mutex); - mutex_unlock(&cgroup_mutex); - return PTR_ERR(css); - } - - ss->root = &cgroup_dummy_root; - - /* our new subsystem will be attached to the dummy hierarchy. */ - init_css(css, ss, cgroup_dummy_top); - - /* - * Now we need to entangle the css into the existing css_sets. unlike - * in cgroup_init_subsys, there are now multiple css_sets, so each one - * will need a new pointer to it; done by iterating the css_set_table. - * furthermore, modifying the existing css_sets will corrupt the hash - * table state, so each changed css_set will need its hash recomputed. - * this is all done under the css_set_lock. - */ - write_lock(&css_set_lock); - hash_for_each_safe(css_set_table, i, tmp, cset, hlist) { - /* skip entries that we already rehashed */ - if (cset->subsys[ss->subsys_id]) - continue; - /* remove existing entry */ - hash_del(&cset->hlist); - /* set new value */ - cset->subsys[ss->subsys_id] = css; - /* recompute hash and restore entry */ - key = css_set_hash(cset->subsys); - hash_add(css_set_table, &cset->hlist, key); - } - write_unlock(&css_set_lock); - - ret = online_css(css); - if (ret) { - ss->css_free(css); - goto err_unload; - } - - /* success! */ - mutex_unlock(&cgroup_root_mutex); - mutex_unlock(&cgroup_mutex); - return 0; - -err_unload: - mutex_unlock(&cgroup_root_mutex); - mutex_unlock(&cgroup_mutex); - /* @ss can't be mounted here as try_module_get() would fail */ - cgroup_unload_subsys(ss); - return ret; -} -EXPORT_SYMBOL_GPL(cgroup_load_subsys); - -/** - * cgroup_unload_subsys: unload a modular subsystem - * @ss: the subsystem to unload - * - * This function should be called in a modular subsystem's exitcall. When this - * function is invoked, the refcount on the subsystem's module will be 0, so - * the subsystem will not be attached to any hierarchy. - */ -void cgroup_unload_subsys(struct cgroup_subsys *ss) -{ - struct cgrp_cset_link *link; - struct cgroup_subsys_state *css; - - BUG_ON(ss->module == NULL); - - /* - * we shouldn't be called if the subsystem is in use, and the use of - * try_module_get() in rebind_subsystems() should ensure that it - * doesn't start being used while we're killing it off. - */ - BUG_ON(ss->root != &cgroup_dummy_root); - - mutex_lock(&cgroup_mutex); - mutex_lock(&cgroup_root_mutex); - - css = cgroup_css(cgroup_dummy_top, ss); - if (css) - offline_css(css); - - /* deassign the subsys_id */ - cgroup_subsys[ss->subsys_id] = NULL; - - /* - * disentangle the css from all css_sets attached to the dummy - * top. as in loading, we need to pay our respects to the hashtable - * gods. - */ - write_lock(&css_set_lock); - list_for_each_entry(link, &cgroup_dummy_top->cset_links, cset_link) { - struct css_set *cset = link->cset; - unsigned long key; - - hash_del(&cset->hlist); - cset->subsys[ss->subsys_id] = NULL; - key = css_set_hash(cset->subsys); - hash_add(css_set_table, &cset->hlist, key); - } - write_unlock(&css_set_lock); - - /* - * remove subsystem's css from the cgroup_dummy_top and free it - - * need to free before marking as null because ss->css_free needs - * the cgrp->subsys pointer to find their state. - */ - if (css) - ss->css_free(css); - RCU_INIT_POINTER(cgroup_dummy_top->subsys[ss->subsys_id], NULL); - - mutex_unlock(&cgroup_root_mutex); - mutex_unlock(&cgroup_mutex); -} -EXPORT_SYMBOL_GPL(cgroup_unload_subsys); - /** * cgroup_init_early - cgroup initialization at system boot * @@ -4763,8 +4527,7 @@ int __init cgroup_init_early(void) list_add(&init_cgrp_cset_link.cset_link, &cgroup_dummy_top->cset_links); list_add(&init_cgrp_cset_link.cgrp_link, &init_css_set.cgrp_links); - /* at bootup time, we don't worry about modular subsystems */ - for_each_builtin_subsys(ss, i) { + for_each_subsys(ss, i) { BUG_ON(!ss->name); BUG_ON(strlen(ss->name) > MAX_CGROUP_TYPE_NAMELEN); BUG_ON(!ss->css_alloc); @@ -4797,7 +4560,7 @@ int __init cgroup_init(void) if (err) return err; - for_each_builtin_subsys(ss, i) { + for_each_subsys(ss, i) { if (!ss->early_init) cgroup_init_subsys(ss); } @@ -5032,15 +4795,7 @@ void cgroup_post_fork(struct task_struct *child) * and addition to css_set. */ if (need_forkexit_callback) { - /* - * fork/exit callbacks are supported only for builtin - * subsystems, and the builtin section of the subsys - * array is immutable, so we don't need to lock the - * subsys array here. On the other hand, modular section - * of the array can be freed at module unload, so we - * can't touch that. - */ - for_each_builtin_subsys(ss, i) + for_each_subsys(ss, i) if (ss->fork) ss->fork(child); } @@ -5105,11 +4860,8 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks) RCU_INIT_POINTER(tsk->cgroups, &init_css_set); if (run_callbacks && need_forkexit_callback) { - /* - * fork/exit callbacks are supported only for builtin - * subsystems, see cgroup_post_fork() for details. - */ - for_each_builtin_subsys(ss, i) { + /* see cgroup_post_fork() for details */ + for_each_subsys(ss, i) { if (ss->exit) { struct cgroup_subsys_state *old_css = cset->subsys[i]; struct cgroup_subsys_state *css = task_css(tsk, i); @@ -5228,11 +4980,7 @@ static int __init cgroup_disable(char *str) if (!*token) continue; - /* - * cgroup_disable, being at boot time, can't know about - * module subsystems, so we don't worry about them. - */ - for_each_builtin_subsys(ss, i) { + for_each_subsys(ss, i) { if (!strcmp(token, ss->name)) { ss->disabled = 1; printk(KERN_INFO "Disabling %s control group" diff --git a/net/core/netclassid_cgroup.c b/net/core/netclassid_cgroup.c index 9fc7f90d034c..9e5ad5d74e60 100644 --- a/net/core/netclassid_cgroup.c +++ b/net/core/netclassid_cgroup.c @@ -110,5 +110,4 @@ struct cgroup_subsys net_cls_subsys = { .attach = cgrp_attach, .subsys_id = net_cls_subsys_id, .base_cftypes = ss_files, - .module = THIS_MODULE, }; diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index cc3a31e7dc08..857e1603f9b7 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c @@ -252,7 +252,6 @@ struct cgroup_subsys net_prio_subsys = { .attach = net_prio_attach, .subsys_id = net_prio_subsys_id, .base_cftypes = ss_files, - .module = THIS_MODULE, }; static int netprio_device_event(struct notifier_block *unused, -- cgit v1.3-8-gc7d7 From 073219e995b4a3f8cf1ce8228b7ef440b6994ac0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 8 Feb 2014 10:36:58 -0500 Subject: cgroup: clean up cgroup_subsys names and initialization cgroup_subsys is a bit messier than it needs to be. * The name of a subsys can be different from its internal identifier defined in cgroup_subsys.h. Most subsystems use the matching name but three - cpu, memory and perf_event - use different ones. * cgroup_subsys_id enums are postfixed with _subsys_id and each cgroup_subsys is postfixed with _subsys. cgroup.h is widely included throughout various subsystems, it doesn't and shouldn't have claim on such generic names which don't have any qualifier indicating that they belong to cgroup. * cgroup_subsys->subsys_id should always equal the matching cgroup_subsys_id enum; however, we require each controller to initialize it and then BUG if they don't match, which is a bit silly. This patch cleans up cgroup_subsys names and initialization by doing the followings. * cgroup_subsys_id enums are now postfixed with _cgrp_id, and each cgroup_subsys with _cgrp_subsys. * With the above, renaming subsys identifiers to match the userland visible names doesn't cause any naming conflicts. All non-matching identifiers are renamed to match the official names. cpu_cgroup -> cpu mem_cgroup -> memory perf -> perf_event * controllers no longer need to initialize ->subsys_id and ->name. They're generated in cgroup core and set automatically during boot. * Redundant cgroup_subsys declarations removed. * While updating BUG_ON()s in cgroup_init_early(), convert them to WARN()s. BUGging that early during boot is stupid - the kernel can't print anything, even through serial console and the trap handler doesn't even link stack frame properly for back-tracing. This patch doesn't introduce any behavior changes. v2: Rebased on top of fe1217c4f3f7 ("net: net_cls: move cgroupfs classid handling into core"). Signed-off-by: Tejun Heo Acked-by: Neil Horman Acked-by: "David S. Miller" Acked-by: "Rafael J. Wysocki" Acked-by: Michal Hocko Acked-by: Peter Zijlstra Acked-by: Aristeu Rozanski Acked-by: Ingo Molnar Acked-by: Li Zefan Cc: Johannes Weiner Cc: Balbir Singh Cc: KAMEZAWA Hiroyuki Cc: Serge E. Hallyn Cc: Vivek Goyal Cc: Thomas Graf --- block/blk-cgroup.c | 8 +++----- block/blk-cgroup.h | 2 +- fs/bio.c | 2 +- include/linux/cgroup.h | 7 ++++--- include/linux/cgroup_subsys.h | 6 +++--- include/linux/hugetlb_cgroup.h | 2 +- include/linux/memcontrol.h | 2 +- include/net/cls_cgroup.h | 2 +- include/net/netprio_cgroup.h | 2 +- kernel/cgroup.c | 34 ++++++++++++++++++++-------------- kernel/cgroup_freezer.c | 8 ++------ kernel/cpuset.c | 10 ++++------ kernel/events/core.c | 8 +++----- kernel/sched/core.c | 6 ++---- kernel/sched/cpuacct.c | 6 ++---- mm/hugetlb_cgroup.c | 9 +++------ mm/memcontrol.c | 22 ++++++++++------------ net/core/netclassid_cgroup.c | 6 ++---- net/core/netprio_cgroup.c | 4 +--- net/ipv4/tcp_memcontrol.c | 2 +- security/device_cgroup.c | 8 ++------ 21 files changed, 68 insertions(+), 88 deletions(-) (limited to 'include/linux') diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 660d419918a7..1cef07cf9c21 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -906,16 +906,14 @@ static int blkcg_can_attach(struct cgroup_subsys_state *css, return ret; } -struct cgroup_subsys blkio_subsys = { - .name = "blkio", +struct cgroup_subsys blkio_cgrp_subsys = { .css_alloc = blkcg_css_alloc, .css_offline = blkcg_css_offline, .css_free = blkcg_css_free, .can_attach = blkcg_can_attach, - .subsys_id = blkio_subsys_id, .base_cftypes = blkcg_files, }; -EXPORT_SYMBOL_GPL(blkio_subsys); +EXPORT_SYMBOL_GPL(blkio_cgrp_subsys); /** * blkcg_activate_policy - activate a blkcg policy on a request_queue @@ -1105,7 +1103,7 @@ int blkcg_policy_register(struct blkcg_policy *pol) /* everything is in place, add intf files for the new policy */ if (pol->cftypes) - WARN_ON(cgroup_add_cftypes(&blkio_subsys, pol->cftypes)); + WARN_ON(cgroup_add_cftypes(&blkio_cgrp_subsys, pol->cftypes)); ret = 0; out_unlock: mutex_unlock(&blkcg_pol_mutex); diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h index 86154eab9523..453b528c8e19 100644 --- a/block/blk-cgroup.h +++ b/block/blk-cgroup.h @@ -186,7 +186,7 @@ static inline struct blkcg *css_to_blkcg(struct cgroup_subsys_state *css) static inline struct blkcg *task_blkcg(struct task_struct *tsk) { - return css_to_blkcg(task_css(tsk, blkio_subsys_id)); + return css_to_blkcg(task_css(tsk, blkio_cgrp_id)); } static inline struct blkcg *bio_blkcg(struct bio *bio) diff --git a/fs/bio.c b/fs/bio.c index 75c49a382239..4872102b839e 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -1965,7 +1965,7 @@ int bio_associate_current(struct bio *bio) /* associate blkcg if exists */ rcu_read_lock(); - css = task_css(current, blkio_subsys_id); + css = task_css(current, blkio_cgrp_id); if (css && css_tryget(css)) bio->bi_css = css; rcu_read_unlock(); diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index d842a737d448..cd6611e622fd 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -41,7 +41,7 @@ extern int cgroupstats_build(struct cgroupstats *stats, extern int proc_cgroup_show(struct seq_file *, void *); /* define the enumeration of all cgroup subsystems */ -#define SUBSYS(_x) _x ## _subsys_id, +#define SUBSYS(_x) _x ## _cgrp_id, enum cgroup_subsys_id { #include CGROUP_SUBSYS_COUNT, @@ -573,7 +573,6 @@ struct cgroup_subsys { struct task_struct *task); void (*bind)(struct cgroup_subsys_state *root_css); - int subsys_id; int disabled; int early_init; @@ -592,6 +591,8 @@ struct cgroup_subsys { bool broken_hierarchy; bool warned_broken_hierarchy; + /* the following two fields are initialized automtically during boot */ + int subsys_id; #define MAX_CGROUP_TYPE_NAMELEN 32 const char *name; @@ -606,7 +607,7 @@ struct cgroup_subsys { struct cftype_set base_cftset; }; -#define SUBSYS(_x) extern struct cgroup_subsys _x ## _subsys; +#define SUBSYS(_x) extern struct cgroup_subsys _x ## _cgrp_subsys; #include #undef SUBSYS diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h index 11c42f6a25a8..768fe44e19f0 100644 --- a/include/linux/cgroup_subsys.h +++ b/include/linux/cgroup_subsys.h @@ -12,7 +12,7 @@ SUBSYS(debug) #endif #if IS_ENABLED(CONFIG_CGROUP_SCHED) -SUBSYS(cpu_cgroup) +SUBSYS(cpu) #endif #if IS_ENABLED(CONFIG_CGROUP_CPUACCT) @@ -20,7 +20,7 @@ SUBSYS(cpuacct) #endif #if IS_ENABLED(CONFIG_MEMCG) -SUBSYS(mem_cgroup) +SUBSYS(memory) #endif #if IS_ENABLED(CONFIG_CGROUP_DEVICE) @@ -40,7 +40,7 @@ SUBSYS(blkio) #endif #if IS_ENABLED(CONFIG_CGROUP_PERF) -SUBSYS(perf) +SUBSYS(perf_event) #endif #if IS_ENABLED(CONFIG_CGROUP_NET_PRIO) diff --git a/include/linux/hugetlb_cgroup.h b/include/linux/hugetlb_cgroup.h index 787bba3bf552..0129f89cf98d 100644 --- a/include/linux/hugetlb_cgroup.h +++ b/include/linux/hugetlb_cgroup.h @@ -49,7 +49,7 @@ int set_hugetlb_cgroup(struct page *page, struct hugetlb_cgroup *h_cg) static inline bool hugetlb_cgroup_disabled(void) { - if (hugetlb_subsys.disabled) + if (hugetlb_cgrp_subsys.disabled) return true; return false; } diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index abd0113b6620..eccfb4a4b379 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -162,7 +162,7 @@ extern int do_swap_account; static inline bool mem_cgroup_disabled(void) { - if (mem_cgroup_subsys.disabled) + if (memory_cgrp_subsys.disabled) return true; return false; } diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h index 9cf2d5ef38d9..c15d39456e14 100644 --- a/include/net/cls_cgroup.h +++ b/include/net/cls_cgroup.h @@ -34,7 +34,7 @@ static inline u32 task_cls_classid(struct task_struct *p) return 0; rcu_read_lock(); - classid = container_of(task_css(p, net_cls_subsys_id), + classid = container_of(task_css(p, net_cls_cgrp_id), struct cgroup_cls_state, css)->classid; rcu_read_unlock(); diff --git a/include/net/netprio_cgroup.h b/include/net/netprio_cgroup.h index b7ff5bd3c3c3..f2a9597ff53c 100644 --- a/include/net/netprio_cgroup.h +++ b/include/net/netprio_cgroup.h @@ -33,7 +33,7 @@ static inline u32 task_netprioidx(struct task_struct *p) u32 idx; rcu_read_lock(); - css = task_css(p, net_prio_subsys_id); + css = task_css(p, net_prio_cgrp_id); idx = css->cgroup->id; rcu_read_unlock(); return idx; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index ccb16b47e293..fe3f7253aa90 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -120,10 +120,18 @@ static struct workqueue_struct *cgroup_destroy_wq; static struct workqueue_struct *cgroup_pidlist_destroy_wq; /* generate an array of cgroup subsystem pointers */ -#define SUBSYS(_x) [_x ## _subsys_id] = &_x ## _subsys, +#define SUBSYS(_x) [_x ## _cgrp_id] = &_x ## _cgrp_subsys, static struct cgroup_subsys *cgroup_subsys[] = { #include }; +#undef SUBSYS + +/* array of cgroup subsystem names */ +#define SUBSYS(_x) [_x ## _cgrp_id] = #_x, +static const char *cgroup_subsys_name[] = { +#include +}; +#undef SUBSYS /* * The dummy hierarchy, reserved for the subsystems that are otherwise @@ -1076,7 +1084,7 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) BUG_ON(!mutex_is_locked(&cgroup_mutex)); #ifdef CONFIG_CPUSETS - mask = ~(1UL << cpuset_subsys_id); + mask = ~(1UL << cpuset_cgrp_id); #endif memset(opts, 0, sizeof(*opts)); @@ -4528,15 +4536,15 @@ int __init cgroup_init_early(void) list_add(&init_cgrp_cset_link.cgrp_link, &init_css_set.cgrp_links); for_each_subsys(ss, i) { - BUG_ON(!ss->name); - BUG_ON(strlen(ss->name) > MAX_CGROUP_TYPE_NAMELEN); - BUG_ON(!ss->css_alloc); - BUG_ON(!ss->css_free); - if (ss->subsys_id != i) { - printk(KERN_ERR "cgroup: Subsys %s id == %d\n", - ss->name, ss->subsys_id); - BUG(); - } + WARN(!ss->css_alloc || !ss->css_free || ss->name || ss->subsys_id, + "invalid cgroup_subsys %d:%s css_alloc=%p css_free=%p name:id=%d:%s\n", + i, cgroup_subsys_name[i], ss->css_alloc, ss->css_free, + ss->subsys_id, ss->name); + WARN(strlen(cgroup_subsys_name[i]) > MAX_CGROUP_TYPE_NAMELEN, + "cgroup_subsys_name %s too long\n", cgroup_subsys_name[i]); + + ss->subsys_id = i; + ss->name = cgroup_subsys_name[i]; if (ss->early_init) cgroup_init_subsys(ss); @@ -5167,11 +5175,9 @@ static struct cftype debug_files[] = { { } /* terminate */ }; -struct cgroup_subsys debug_subsys = { - .name = "debug", +struct cgroup_subsys debug_cgrp_subsys = { .css_alloc = debug_css_alloc, .css_free = debug_css_free, - .subsys_id = debug_subsys_id, .base_cftypes = debug_files, }; #endif /* CONFIG_CGROUP_DEBUG */ diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index 6c3154e477f6..98ea26a99076 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c @@ -52,7 +52,7 @@ static inline struct freezer *css_freezer(struct cgroup_subsys_state *css) static inline struct freezer *task_freezer(struct task_struct *task) { - return css_freezer(task_css(task, freezer_subsys_id)); + return css_freezer(task_css(task, freezer_cgrp_id)); } static struct freezer *parent_freezer(struct freezer *freezer) @@ -84,8 +84,6 @@ static const char *freezer_state_strs(unsigned int state) return "THAWED"; }; -struct cgroup_subsys freezer_subsys; - static struct cgroup_subsys_state * freezer_css_alloc(struct cgroup_subsys_state *parent_css) { @@ -473,13 +471,11 @@ static struct cftype files[] = { { } /* terminate */ }; -struct cgroup_subsys freezer_subsys = { - .name = "freezer", +struct cgroup_subsys freezer_cgrp_subsys = { .css_alloc = freezer_css_alloc, .css_online = freezer_css_online, .css_offline = freezer_css_offline, .css_free = freezer_css_free, - .subsys_id = freezer_subsys_id, .attach = freezer_attach, .fork = freezer_fork, .base_cftypes = files, diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 4410ac6a55f1..2d018c795fea 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -119,7 +119,7 @@ static inline struct cpuset *css_cs(struct cgroup_subsys_state *css) /* Retrieve the cpuset for a task */ static inline struct cpuset *task_cs(struct task_struct *task) { - return css_cs(task_css(task, cpuset_subsys_id)); + return css_cs(task_css(task, cpuset_cgrp_id)); } static inline struct cpuset *parent_cs(struct cpuset *cs) @@ -1521,7 +1521,7 @@ static void cpuset_attach(struct cgroup_subsys_state *css, struct task_struct *task; struct task_struct *leader = cgroup_taskset_first(tset); struct cgroup_subsys_state *oldcss = cgroup_taskset_cur_css(tset, - cpuset_subsys_id); + cpuset_cgrp_id); struct cpuset *cs = css_cs(css); struct cpuset *oldcs = css_cs(oldcss); struct cpuset *cpus_cs = effective_cpumask_cpuset(cs); @@ -2024,8 +2024,7 @@ static void cpuset_css_free(struct cgroup_subsys_state *css) kfree(cs); } -struct cgroup_subsys cpuset_subsys = { - .name = "cpuset", +struct cgroup_subsys cpuset_cgrp_subsys = { .css_alloc = cpuset_css_alloc, .css_online = cpuset_css_online, .css_offline = cpuset_css_offline, @@ -2033,7 +2032,6 @@ struct cgroup_subsys cpuset_subsys = { .can_attach = cpuset_can_attach, .cancel_attach = cpuset_cancel_attach, .attach = cpuset_attach, - .subsys_id = cpuset_subsys_id, .base_cftypes = files, .early_init = 1, }; @@ -2699,7 +2697,7 @@ int proc_cpuset_show(struct seq_file *m, void *unused_v) goto out_free; rcu_read_lock(); - css = task_css(tsk, cpuset_subsys_id); + css = task_css(tsk, cpuset_cgrp_id); retval = cgroup_path(css->cgroup, buf, PAGE_SIZE); rcu_read_unlock(); if (retval < 0) diff --git a/kernel/events/core.c b/kernel/events/core.c index 56003c6edfd3..64903731d834 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -342,7 +342,7 @@ struct perf_cgroup { static inline struct perf_cgroup * perf_cgroup_from_task(struct task_struct *task) { - return container_of(task_css(task, perf_subsys_id), + return container_of(task_css(task, perf_event_cgrp_id), struct perf_cgroup, css); } @@ -595,7 +595,7 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event, rcu_read_lock(); - css = css_from_dir(f.file->f_dentry, &perf_subsys); + css = css_from_dir(f.file->f_dentry, &perf_event_cgrp_subsys); if (IS_ERR(css)) { ret = PTR_ERR(css); goto out; @@ -8055,9 +8055,7 @@ static void perf_cgroup_exit(struct cgroup_subsys_state *css, task_function_call(task, __perf_cgroup_move, task); } -struct cgroup_subsys perf_subsys = { - .name = "perf_event", - .subsys_id = perf_subsys_id, +struct cgroup_subsys perf_event_cgrp_subsys = { .css_alloc = perf_cgroup_css_alloc, .css_free = perf_cgroup_css_free, .exit = perf_cgroup_exit, diff --git a/kernel/sched/core.c b/kernel/sched/core.c index b46131ef6aab..d4cfc5561830 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7176,7 +7176,7 @@ void sched_move_task(struct task_struct *tsk) if (unlikely(running)) tsk->sched_class->put_prev_task(rq, tsk); - tg = container_of(task_css_check(tsk, cpu_cgroup_subsys_id, + tg = container_of(task_css_check(tsk, cpu_cgrp_id, lockdep_is_held(&tsk->sighand->siglock)), struct task_group, css); tg = autogroup_task_group(tsk, tg); @@ -7957,8 +7957,7 @@ static struct cftype cpu_files[] = { { } /* terminate */ }; -struct cgroup_subsys cpu_cgroup_subsys = { - .name = "cpu", +struct cgroup_subsys cpu_cgrp_subsys = { .css_alloc = cpu_cgroup_css_alloc, .css_free = cpu_cgroup_css_free, .css_online = cpu_cgroup_css_online, @@ -7966,7 +7965,6 @@ struct cgroup_subsys cpu_cgroup_subsys = { .can_attach = cpu_cgroup_can_attach, .attach = cpu_cgroup_attach, .exit = cpu_cgroup_exit, - .subsys_id = cpu_cgroup_subsys_id, .base_cftypes = cpu_files, .early_init = 1, }; diff --git a/kernel/sched/cpuacct.c b/kernel/sched/cpuacct.c index 622e0818f905..c143ee380e3a 100644 --- a/kernel/sched/cpuacct.c +++ b/kernel/sched/cpuacct.c @@ -41,7 +41,7 @@ static inline struct cpuacct *css_ca(struct cgroup_subsys_state *css) /* return cpu accounting group to which this task belongs */ static inline struct cpuacct *task_ca(struct task_struct *tsk) { - return css_ca(task_css(tsk, cpuacct_subsys_id)); + return css_ca(task_css(tsk, cpuacct_cgrp_id)); } static inline struct cpuacct *parent_ca(struct cpuacct *ca) @@ -275,11 +275,9 @@ void cpuacct_account_field(struct task_struct *p, int index, u64 val) rcu_read_unlock(); } -struct cgroup_subsys cpuacct_subsys = { - .name = "cpuacct", +struct cgroup_subsys cpuacct_cgrp_subsys = { .css_alloc = cpuacct_css_alloc, .css_free = cpuacct_css_free, - .subsys_id = cpuacct_subsys_id, .base_cftypes = files, .early_init = 1, }; diff --git a/mm/hugetlb_cgroup.c b/mm/hugetlb_cgroup.c index cb00829bb466..b135853e68f3 100644 --- a/mm/hugetlb_cgroup.c +++ b/mm/hugetlb_cgroup.c @@ -30,7 +30,6 @@ struct hugetlb_cgroup { #define MEMFILE_IDX(val) (((val) >> 16) & 0xffff) #define MEMFILE_ATTR(val) ((val) & 0xffff) -struct cgroup_subsys hugetlb_subsys __read_mostly; static struct hugetlb_cgroup *root_h_cgroup __read_mostly; static inline @@ -42,7 +41,7 @@ struct hugetlb_cgroup *hugetlb_cgroup_from_css(struct cgroup_subsys_state *s) static inline struct hugetlb_cgroup *hugetlb_cgroup_from_task(struct task_struct *task) { - return hugetlb_cgroup_from_css(task_css(task, hugetlb_subsys_id)); + return hugetlb_cgroup_from_css(task_css(task, hugetlb_cgrp_id)); } static inline bool hugetlb_cgroup_is_root(struct hugetlb_cgroup *h_cg) @@ -358,7 +357,7 @@ static void __init __hugetlb_cgroup_file_init(int idx) cft = &h->cgroup_files[4]; memset(cft, 0, sizeof(*cft)); - WARN_ON(cgroup_add_cftypes(&hugetlb_subsys, h->cgroup_files)); + WARN_ON(cgroup_add_cftypes(&hugetlb_cgrp_subsys, h->cgroup_files)); return; } @@ -402,10 +401,8 @@ void hugetlb_cgroup_migrate(struct page *oldhpage, struct page *newhpage) return; } -struct cgroup_subsys hugetlb_subsys = { - .name = "hugetlb", +struct cgroup_subsys hugetlb_cgrp_subsys = { .css_alloc = hugetlb_cgroup_css_alloc, .css_offline = hugetlb_cgroup_css_offline, .css_free = hugetlb_cgroup_css_free, - .subsys_id = hugetlb_subsys_id, }; diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 53385cd4e6f0..04a97bce2270 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -66,8 +66,8 @@ #include -struct cgroup_subsys mem_cgroup_subsys __read_mostly; -EXPORT_SYMBOL(mem_cgroup_subsys); +struct cgroup_subsys memory_cgrp_subsys __read_mostly; +EXPORT_SYMBOL(memory_cgrp_subsys); #define MEM_CGROUP_RECLAIM_RETRIES 5 static struct mem_cgroup *root_mem_cgroup __read_mostly; @@ -538,7 +538,7 @@ static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id) { struct cgroup_subsys_state *css; - css = css_from_id(id - 1, &mem_cgroup_subsys); + css = css_from_id(id - 1, &memory_cgrp_subsys); return mem_cgroup_from_css(css); } @@ -1072,7 +1072,7 @@ struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p) if (unlikely(!p)) return NULL; - return mem_cgroup_from_css(task_css(p, mem_cgroup_subsys_id)); + return mem_cgroup_from_css(task_css(p, memory_cgrp_id)); } struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm) @@ -1702,7 +1702,7 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p) rcu_read_lock(); mem_cgrp = memcg->css.cgroup; - task_cgrp = task_cgroup(p, mem_cgroup_subsys_id); + task_cgrp = task_cgroup(p, memory_cgrp_id); ret = cgroup_path(task_cgrp, memcg_name, PATH_MAX); if (ret < 0) { @@ -6187,7 +6187,7 @@ static int memcg_write_event_control(struct cgroup_subsys_state *css, ret = -EINVAL; cfile_css = css_from_dir(cfile.file->f_dentry->d_parent, - &mem_cgroup_subsys); + &memory_cgrp_subsys); if (cfile_css == css && css_tryget(css)) ret = 0; @@ -6566,11 +6566,11 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css) * unfortunate state in our controller. */ if (parent != root_mem_cgroup) - mem_cgroup_subsys.broken_hierarchy = true; + memory_cgrp_subsys.broken_hierarchy = true; } mutex_unlock(&memcg_create_mutex); - return memcg_init_kmem(memcg, &mem_cgroup_subsys); + return memcg_init_kmem(memcg, &memory_cgrp_subsys); } /* @@ -7264,9 +7264,7 @@ static void mem_cgroup_bind(struct cgroup_subsys_state *root_css) mem_cgroup_from_css(root_css)->use_hierarchy = true; } -struct cgroup_subsys mem_cgroup_subsys = { - .name = "memory", - .subsys_id = mem_cgroup_subsys_id, +struct cgroup_subsys memory_cgrp_subsys = { .css_alloc = mem_cgroup_css_alloc, .css_online = mem_cgroup_css_online, .css_offline = mem_cgroup_css_offline, @@ -7292,7 +7290,7 @@ __setup("swapaccount=", enable_swap_account); static void __init memsw_file_init(void) { - WARN_ON(cgroup_add_cftypes(&mem_cgroup_subsys, memsw_cgroup_files)); + WARN_ON(cgroup_add_cftypes(&memory_cgrp_subsys, memsw_cgroup_files)); } static void __init enable_swap_cgroup(void) diff --git a/net/core/netclassid_cgroup.c b/net/core/netclassid_cgroup.c index 9e5ad5d74e60..b865662fba71 100644 --- a/net/core/netclassid_cgroup.c +++ b/net/core/netclassid_cgroup.c @@ -23,7 +23,7 @@ static inline struct cgroup_cls_state *css_cls_state(struct cgroup_subsys_state struct cgroup_cls_state *task_cls_state(struct task_struct *p) { - return css_cls_state(task_css(p, net_cls_subsys_id)); + return css_cls_state(task_css(p, net_cls_cgrp_id)); } EXPORT_SYMBOL_GPL(task_cls_state); @@ -102,12 +102,10 @@ static struct cftype ss_files[] = { { } /* terminate */ }; -struct cgroup_subsys net_cls_subsys = { - .name = "net_cls", +struct cgroup_subsys net_cls_cgrp_subsys = { .css_alloc = cgrp_css_alloc, .css_online = cgrp_css_online, .css_free = cgrp_css_free, .attach = cgrp_attach, - .subsys_id = net_cls_subsys_id, .base_cftypes = ss_files, }; diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index 857e1603f9b7..d7d23e28fafd 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c @@ -244,13 +244,11 @@ static struct cftype ss_files[] = { { } /* terminate */ }; -struct cgroup_subsys net_prio_subsys = { - .name = "net_prio", +struct cgroup_subsys net_prio_cgrp_subsys = { .css_alloc = cgrp_css_alloc, .css_online = cgrp_css_online, .css_free = cgrp_css_free, .attach = net_prio_attach, - .subsys_id = net_prio_subsys_id, .base_cftypes = ss_files, }; diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c index f7e522c558ba..20a0aca9131e 100644 --- a/net/ipv4/tcp_memcontrol.c +++ b/net/ipv4/tcp_memcontrol.c @@ -219,7 +219,7 @@ static struct cftype tcp_files[] = { static int __init tcp_memcontrol_init(void) { - WARN_ON(cgroup_add_cftypes(&mem_cgroup_subsys, tcp_files)); + WARN_ON(cgroup_add_cftypes(&memory_cgrp_subsys, tcp_files)); return 0; } __initcall(tcp_memcontrol_init); diff --git a/security/device_cgroup.c b/security/device_cgroup.c index d3b6d2cd3a06..7f88bcde7c61 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -58,11 +58,9 @@ static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s) static inline struct dev_cgroup *task_devcgroup(struct task_struct *task) { - return css_to_devcgroup(task_css(task, devices_subsys_id)); + return css_to_devcgroup(task_css(task, devices_cgrp_id)); } -struct cgroup_subsys devices_subsys; - /* * called under devcgroup_mutex */ @@ -684,13 +682,11 @@ static struct cftype dev_cgroup_files[] = { { } /* terminate */ }; -struct cgroup_subsys devices_subsys = { - .name = "devices", +struct cgroup_subsys devices_cgrp_subsys = { .css_alloc = devcgroup_css_alloc, .css_free = devcgroup_css_free, .css_online = devcgroup_online, .css_offline = devcgroup_offline, - .subsys_id = devices_subsys_id, .base_cftypes = dev_cgroup_files, }; -- cgit v1.3-8-gc7d7 From aec25020f5d4b69aea5317551d1cb7043f6b04fb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 8 Feb 2014 10:36:58 -0500 Subject: cgroup: rename cgroup_subsys->subsys_id to ->id It's no longer referenced outside cgroup core, so renaming is easy. Let's rename it for consistency & brevity. This patch is pure rename. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- include/linux/cgroup.h | 4 ++-- kernel/cgroup.c | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index cd6611e622fd..198c7fcd727e 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -548,7 +548,7 @@ int cgroup_taskset_size(struct cgroup_taskset *tset); (task) = cgroup_taskset_next((tset))) \ if (!(skip_css) || \ cgroup_taskset_cur_css((tset), \ - (skip_css)->ss->subsys_id) != (skip_css)) + (skip_css)->ss->id) != (skip_css)) /* * Control Group subsystem type. @@ -592,7 +592,7 @@ struct cgroup_subsys { bool warned_broken_hierarchy; /* the following two fields are initialized automtically during boot */ - int subsys_id; + int id; #define MAX_CGROUP_TYPE_NAMELEN 32 const char *name; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index fe3f7253aa90..5a77ca0784a6 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -198,7 +198,7 @@ static struct cgroup_subsys_state *cgroup_css(struct cgroup *cgrp, struct cgroup_subsys *ss) { if (ss) - return rcu_dereference_check(cgrp->subsys[ss->subsys_id], + return rcu_dereference_check(cgrp->subsys[ss->id], lockdep_is_held(&cgroup_mutex)); else return &cgrp->dummy_css; @@ -3982,7 +3982,7 @@ static void css_release(struct percpu_ref *ref) struct cgroup_subsys_state *css = container_of(ref, struct cgroup_subsys_state, refcnt); - rcu_assign_pointer(css->cgroup->subsys[css->ss->subsys_id], NULL); + rcu_assign_pointer(css->cgroup->subsys[css->ss->id], NULL); call_rcu(&css->rcu_head, css_free_rcu_fn); } @@ -4014,7 +4014,7 @@ static int online_css(struct cgroup_subsys_state *css) if (!ret) { css->flags |= CSS_ONLINE; css->cgroup->nr_css++; - rcu_assign_pointer(css->cgroup->subsys[ss->subsys_id], css); + rcu_assign_pointer(css->cgroup->subsys[ss->id], css); } return ret; } @@ -4034,7 +4034,7 @@ static void offline_css(struct cgroup_subsys_state *css) css->flags &= ~CSS_ONLINE; css->cgroup->nr_css--; - RCU_INIT_POINTER(css->cgroup->subsys[ss->subsys_id], css); + RCU_INIT_POINTER(css->cgroup->subsys[ss->id], css); } /** @@ -4065,7 +4065,7 @@ static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss) init_css(css, ss, cgrp); - err = cgroup_populate_dir(cgrp, 1 << ss->subsys_id); + err = cgroup_populate_dir(cgrp, 1 << ss->id); if (err) goto err_free; @@ -4292,7 +4292,7 @@ static void css_killed_ref_fn(struct percpu_ref *ref) */ static void kill_css(struct cgroup_subsys_state *css) { - cgroup_clear_dir(css->cgroup, 1 << css->ss->subsys_id); + cgroup_clear_dir(css->cgroup, 1 << css->ss->id); /* * Killing would put the base ref, but we need to keep it alive @@ -4496,7 +4496,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss) * pointer to this state - since the subsystem is * newly registered, all tasks and hence the * init_css_set is in the subsystem's top cgroup. */ - init_css_set.subsys[ss->subsys_id] = css; + init_css_set.subsys[ss->id] = css; need_forkexit_callback |= ss->fork || ss->exit; @@ -4536,14 +4536,14 @@ int __init cgroup_init_early(void) list_add(&init_cgrp_cset_link.cgrp_link, &init_css_set.cgrp_links); for_each_subsys(ss, i) { - WARN(!ss->css_alloc || !ss->css_free || ss->name || ss->subsys_id, + WARN(!ss->css_alloc || !ss->css_free || ss->name || ss->id, "invalid cgroup_subsys %d:%s css_alloc=%p css_free=%p name:id=%d:%s\n", i, cgroup_subsys_name[i], ss->css_alloc, ss->css_free, - ss->subsys_id, ss->name); + ss->id, ss->name); WARN(strlen(cgroup_subsys_name[i]) > MAX_CGROUP_TYPE_NAMELEN, "cgroup_subsys_name %s too long\n", cgroup_subsys_name[i]); - ss->subsys_id = i; + ss->id = i; ss->name = cgroup_subsys_name[i]; if (ss->early_init) -- cgit v1.3-8-gc7d7 From c11baa02c5d6ea06362fa61da070af34b7706c83 Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Fri, 24 Jan 2014 16:18:02 -0600 Subject: crypto: ccp - Move HMAC calculation down to ccp ops file Move the support to perform an HMAC calculation into the CCP operations file. This eliminates the need to perform a synchronous SHA operation used to calculate the HMAC. Signed-off-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-crypto-sha.c | 130 +++++++----------------------------- drivers/crypto/ccp/ccp-crypto.h | 8 +-- drivers/crypto/ccp/ccp-ops.c | 104 ++++++++++++++++++++++++++++- include/linux/ccp.h | 7 ++ 4 files changed, 139 insertions(+), 110 deletions(-) (limited to 'include/linux') diff --git a/drivers/crypto/ccp/ccp-crypto-sha.c b/drivers/crypto/ccp/ccp-crypto-sha.c index 3867290b3531..873f23425245 100644 --- a/drivers/crypto/ccp/ccp-crypto-sha.c +++ b/drivers/crypto/ccp/ccp-crypto-sha.c @@ -24,75 +24,10 @@ #include "ccp-crypto.h" -struct ccp_sha_result { - struct completion completion; - int err; -}; - -static void ccp_sync_hash_complete(struct crypto_async_request *req, int err) -{ - struct ccp_sha_result *result = req->data; - - if (err == -EINPROGRESS) - return; - - result->err = err; - complete(&result->completion); -} - -static int ccp_sync_hash(struct crypto_ahash *tfm, u8 *buf, - struct scatterlist *sg, unsigned int len) -{ - struct ccp_sha_result result; - struct ahash_request *req; - int ret; - - init_completion(&result.completion); - - req = ahash_request_alloc(tfm, GFP_KERNEL); - if (!req) - return -ENOMEM; - - ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - ccp_sync_hash_complete, &result); - ahash_request_set_crypt(req, sg, buf, len); - - ret = crypto_ahash_digest(req); - if ((ret == -EINPROGRESS) || (ret == -EBUSY)) { - ret = wait_for_completion_interruptible(&result.completion); - if (!ret) - ret = result.err; - } - - ahash_request_free(req); - - return ret; -} - -static int ccp_sha_finish_hmac(struct crypto_async_request *async_req) -{ - struct ahash_request *req = ahash_request_cast(async_req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct ccp_ctx *ctx = crypto_ahash_ctx(tfm); - struct ccp_sha_req_ctx *rctx = ahash_request_ctx(req); - struct scatterlist sg[2]; - unsigned int block_size = - crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); - unsigned int digest_size = crypto_ahash_digestsize(tfm); - - sg_init_table(sg, ARRAY_SIZE(sg)); - sg_set_buf(&sg[0], ctx->u.sha.opad, block_size); - sg_set_buf(&sg[1], rctx->ctx, digest_size); - - return ccp_sync_hash(ctx->u.sha.hmac_tfm, req->result, sg, - block_size + digest_size); -} - static int ccp_sha_complete(struct crypto_async_request *async_req, int ret) { struct ahash_request *req = ahash_request_cast(async_req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct ccp_ctx *ctx = crypto_ahash_ctx(tfm); struct ccp_sha_req_ctx *rctx = ahash_request_ctx(req); unsigned int digest_size = crypto_ahash_digestsize(tfm); @@ -112,10 +47,6 @@ static int ccp_sha_complete(struct crypto_async_request *async_req, int ret) if (req->result) memcpy(req->result, rctx->ctx, digest_size); - /* If we're doing an HMAC, we need to perform that on the final op */ - if (rctx->final && ctx->u.sha.key_len) - ret = ccp_sha_finish_hmac(async_req); - e_free: sg_free_table(&rctx->data_sg); @@ -126,6 +57,7 @@ static int ccp_do_sha_update(struct ahash_request *req, unsigned int nbytes, unsigned int final) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct ccp_ctx *ctx = crypto_ahash_ctx(tfm); struct ccp_sha_req_ctx *rctx = ahash_request_ctx(req); struct scatterlist *sg; unsigned int block_size = @@ -196,6 +128,11 @@ static int ccp_do_sha_update(struct ahash_request *req, unsigned int nbytes, rctx->cmd.u.sha.ctx_len = sizeof(rctx->ctx); rctx->cmd.u.sha.src = sg; rctx->cmd.u.sha.src_len = rctx->hash_cnt; + rctx->cmd.u.sha.opad = ctx->u.sha.key_len ? + &ctx->u.sha.opad_sg : NULL; + rctx->cmd.u.sha.opad_len = ctx->u.sha.key_len ? + ctx->u.sha.opad_count : 0; + rctx->cmd.u.sha.first = rctx->first; rctx->cmd.u.sha.final = rctx->final; rctx->cmd.u.sha.msg_bits = rctx->msg_bits; @@ -218,7 +155,6 @@ static int ccp_sha_init(struct ahash_request *req) memset(rctx, 0, sizeof(*rctx)); - memcpy(rctx->ctx, alg->init, sizeof(rctx->ctx)); rctx->type = alg->type; rctx->first = 1; @@ -261,10 +197,13 @@ static int ccp_sha_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int key_len) { struct ccp_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm)); - struct scatterlist sg; - unsigned int block_size = - crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); - unsigned int digest_size = crypto_ahash_digestsize(tfm); + struct crypto_shash *shash = ctx->u.sha.hmac_tfm; + struct { + struct shash_desc sdesc; + char ctx[crypto_shash_descsize(shash)]; + } desc; + unsigned int block_size = crypto_shash_blocksize(shash); + unsigned int digest_size = crypto_shash_digestsize(shash); int i, ret; /* Set to zero until complete */ @@ -277,8 +216,12 @@ static int ccp_sha_setkey(struct crypto_ahash *tfm, const u8 *key, if (key_len > block_size) { /* Must hash the input key */ - sg_init_one(&sg, key, key_len); - ret = ccp_sync_hash(tfm, ctx->u.sha.key, &sg, key_len); + desc.sdesc.tfm = shash; + desc.sdesc.flags = crypto_ahash_get_flags(tfm) & + CRYPTO_TFM_REQ_MAY_SLEEP; + + ret = crypto_shash_digest(&desc.sdesc, key, key_len, + ctx->u.sha.key); if (ret) { crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; @@ -293,6 +236,9 @@ static int ccp_sha_setkey(struct crypto_ahash *tfm, const u8 *key, ctx->u.sha.opad[i] = ctx->u.sha.key[i] ^ 0x5c; } + sg_init_one(&ctx->u.sha.opad_sg, ctx->u.sha.opad, block_size); + ctx->u.sha.opad_count = block_size; + ctx->u.sha.key_len = key_len; return 0; @@ -319,10 +265,9 @@ static int ccp_hmac_sha_cra_init(struct crypto_tfm *tfm) { struct ccp_ctx *ctx = crypto_tfm_ctx(tfm); struct ccp_crypto_ahash_alg *alg = ccp_crypto_ahash_alg(tfm); - struct crypto_ahash *hmac_tfm; + struct crypto_shash *hmac_tfm; - hmac_tfm = crypto_alloc_ahash(alg->child_alg, - CRYPTO_ALG_TYPE_AHASH, 0); + hmac_tfm = crypto_alloc_shash(alg->child_alg, 0, 0); if (IS_ERR(hmac_tfm)) { pr_warn("could not load driver %s need for HMAC support\n", alg->child_alg); @@ -339,35 +284,14 @@ static void ccp_hmac_sha_cra_exit(struct crypto_tfm *tfm) struct ccp_ctx *ctx = crypto_tfm_ctx(tfm); if (ctx->u.sha.hmac_tfm) - crypto_free_ahash(ctx->u.sha.hmac_tfm); + crypto_free_shash(ctx->u.sha.hmac_tfm); ccp_sha_cra_exit(tfm); } -static const __be32 sha1_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = { - cpu_to_be32(SHA1_H0), cpu_to_be32(SHA1_H1), - cpu_to_be32(SHA1_H2), cpu_to_be32(SHA1_H3), - cpu_to_be32(SHA1_H4), 0, 0, 0, -}; - -static const __be32 sha224_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = { - cpu_to_be32(SHA224_H0), cpu_to_be32(SHA224_H1), - cpu_to_be32(SHA224_H2), cpu_to_be32(SHA224_H3), - cpu_to_be32(SHA224_H4), cpu_to_be32(SHA224_H5), - cpu_to_be32(SHA224_H6), cpu_to_be32(SHA224_H7), -}; - -static const __be32 sha256_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = { - cpu_to_be32(SHA256_H0), cpu_to_be32(SHA256_H1), - cpu_to_be32(SHA256_H2), cpu_to_be32(SHA256_H3), - cpu_to_be32(SHA256_H4), cpu_to_be32(SHA256_H5), - cpu_to_be32(SHA256_H6), cpu_to_be32(SHA256_H7), -}; - struct ccp_sha_def { const char *name; const char *drv_name; - const __be32 *init; enum ccp_sha_type type; u32 digest_size; u32 block_size; @@ -377,7 +301,6 @@ static struct ccp_sha_def sha_algs[] = { { .name = "sha1", .drv_name = "sha1-ccp", - .init = sha1_init, .type = CCP_SHA_TYPE_1, .digest_size = SHA1_DIGEST_SIZE, .block_size = SHA1_BLOCK_SIZE, @@ -385,7 +308,6 @@ static struct ccp_sha_def sha_algs[] = { { .name = "sha224", .drv_name = "sha224-ccp", - .init = sha224_init, .type = CCP_SHA_TYPE_224, .digest_size = SHA224_DIGEST_SIZE, .block_size = SHA224_BLOCK_SIZE, @@ -393,7 +315,6 @@ static struct ccp_sha_def sha_algs[] = { { .name = "sha256", .drv_name = "sha256-ccp", - .init = sha256_init, .type = CCP_SHA_TYPE_256, .digest_size = SHA256_DIGEST_SIZE, .block_size = SHA256_BLOCK_SIZE, @@ -460,7 +381,6 @@ static int ccp_register_sha_alg(struct list_head *head, INIT_LIST_HEAD(&ccp_alg->entry); - ccp_alg->init = def->init; ccp_alg->type = def->type; alg = &ccp_alg->alg; diff --git a/drivers/crypto/ccp/ccp-crypto.h b/drivers/crypto/ccp/ccp-crypto.h index b222231b6169..9aa4ae184f7f 100644 --- a/drivers/crypto/ccp/ccp-crypto.h +++ b/drivers/crypto/ccp/ccp-crypto.h @@ -137,11 +137,14 @@ struct ccp_aes_cmac_req_ctx { #define MAX_SHA_BLOCK_SIZE SHA256_BLOCK_SIZE struct ccp_sha_ctx { + struct scatterlist opad_sg; + unsigned int opad_count; + unsigned int key_len; u8 key[MAX_SHA_BLOCK_SIZE]; u8 ipad[MAX_SHA_BLOCK_SIZE]; u8 opad[MAX_SHA_BLOCK_SIZE]; - struct crypto_ahash *hmac_tfm; + struct crypto_shash *hmac_tfm; }; struct ccp_sha_req_ctx { @@ -167,9 +170,6 @@ struct ccp_sha_req_ctx { unsigned int buf_count; u8 buf[MAX_SHA_BLOCK_SIZE]; - /* HMAC support field */ - struct scatterlist pad_sg; - /* CCP driver command */ struct ccp_cmd cmd; }; diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c index c266a7b154bb..9ae006d69df4 100644 --- a/drivers/crypto/ccp/ccp-ops.c +++ b/drivers/crypto/ccp/ccp-ops.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "ccp-dev.h" @@ -132,6 +133,27 @@ struct ccp_op { } u; }; +/* SHA initial context values */ +static const __be32 ccp_sha1_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = { + cpu_to_be32(SHA1_H0), cpu_to_be32(SHA1_H1), + cpu_to_be32(SHA1_H2), cpu_to_be32(SHA1_H3), + cpu_to_be32(SHA1_H4), 0, 0, 0, +}; + +static const __be32 ccp_sha224_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = { + cpu_to_be32(SHA224_H0), cpu_to_be32(SHA224_H1), + cpu_to_be32(SHA224_H2), cpu_to_be32(SHA224_H3), + cpu_to_be32(SHA224_H4), cpu_to_be32(SHA224_H5), + cpu_to_be32(SHA224_H6), cpu_to_be32(SHA224_H7), +}; + +static const __be32 ccp_sha256_init[CCP_SHA_CTXSIZE / sizeof(__be32)] = { + cpu_to_be32(SHA256_H0), cpu_to_be32(SHA256_H1), + cpu_to_be32(SHA256_H2), cpu_to_be32(SHA256_H3), + cpu_to_be32(SHA256_H4), cpu_to_be32(SHA256_H5), + cpu_to_be32(SHA256_H6), cpu_to_be32(SHA256_H7), +}; + /* The CCP cannot perform zero-length sha operations so the caller * is required to buffer data for the final operation. However, a * sha operation for a message with a total length of zero is valid @@ -1411,7 +1433,27 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) if (ret) return ret; - ccp_set_dm_area(&ctx, 0, sha->ctx, 0, sha->ctx_len); + if (sha->first) { + const __be32 *init; + + switch (sha->type) { + case CCP_SHA_TYPE_1: + init = ccp_sha1_init; + break; + case CCP_SHA_TYPE_224: + init = ccp_sha224_init; + break; + case CCP_SHA_TYPE_256: + init = ccp_sha256_init; + break; + default: + ret = -EINVAL; + goto e_ctx; + } + memcpy(ctx.address, init, CCP_SHA_CTXSIZE); + } else + ccp_set_dm_area(&ctx, 0, sha->ctx, 0, sha->ctx_len); + ret = ccp_copy_to_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx, CCP_PASSTHRU_BYTESWAP_256BIT); if (ret) { @@ -1451,6 +1493,66 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) ccp_get_dm_area(&ctx, 0, sha->ctx, 0, sha->ctx_len); + if (sha->final && sha->opad) { + /* HMAC operation, recursively perform final SHA */ + struct ccp_cmd hmac_cmd; + struct scatterlist sg; + u64 block_size, digest_size; + u8 *hmac_buf; + + switch (sha->type) { + case CCP_SHA_TYPE_1: + block_size = SHA1_BLOCK_SIZE; + digest_size = SHA1_DIGEST_SIZE; + break; + case CCP_SHA_TYPE_224: + block_size = SHA224_BLOCK_SIZE; + digest_size = SHA224_DIGEST_SIZE; + break; + case CCP_SHA_TYPE_256: + block_size = SHA256_BLOCK_SIZE; + digest_size = SHA256_DIGEST_SIZE; + break; + default: + ret = -EINVAL; + goto e_data; + } + + if (sha->opad_len != block_size) { + ret = -EINVAL; + goto e_data; + } + + hmac_buf = kmalloc(block_size + digest_size, GFP_KERNEL); + if (!hmac_buf) { + ret = -ENOMEM; + goto e_data; + } + sg_init_one(&sg, hmac_buf, block_size + digest_size); + + scatterwalk_map_and_copy(hmac_buf, sha->opad, 0, block_size, 0); + memcpy(hmac_buf + block_size, ctx.address, digest_size); + + memset(&hmac_cmd, 0, sizeof(hmac_cmd)); + hmac_cmd.engine = CCP_ENGINE_SHA; + hmac_cmd.u.sha.type = sha->type; + hmac_cmd.u.sha.ctx = sha->ctx; + hmac_cmd.u.sha.ctx_len = sha->ctx_len; + hmac_cmd.u.sha.src = &sg; + hmac_cmd.u.sha.src_len = block_size + digest_size; + hmac_cmd.u.sha.opad = NULL; + hmac_cmd.u.sha.opad_len = 0; + hmac_cmd.u.sha.first = 1; + hmac_cmd.u.sha.final = 1; + hmac_cmd.u.sha.msg_bits = (block_size + digest_size) << 3; + + ret = ccp_run_sha_cmd(cmd_q, &hmac_cmd); + if (ret) + cmd->engine_error = hmac_cmd.engine_error; + + kfree(hmac_buf); + } + e_data: ccp_free_data(&src, cmd_q); diff --git a/include/linux/ccp.h b/include/linux/ccp.h index b941ab9f762b..ebcc9d146219 100644 --- a/include/linux/ccp.h +++ b/include/linux/ccp.h @@ -232,6 +232,9 @@ enum ccp_sha_type { * @ctx_len: length in bytes of hash value * @src: data to be used for this operation * @src_len: length in bytes of data used for this operation + * @opad: data to be used for final HMAC operation + * @opad_len: length in bytes of data used for final HMAC operation + * @first: indicates first SHA operation * @final: indicates final SHA operation * @msg_bits: total length of the message in bits used in final SHA operation * @@ -251,6 +254,10 @@ struct ccp_sha_engine { struct scatterlist *src; u64 src_len; /* In bytes */ + struct scatterlist *opad; + u32 opad_len; /* In bytes */ + + u32 first; /* Indicates first sha cmd */ u32 final; /* Indicates final sha cmd */ u64 msg_bits; /* Message length in bits required for * final sha cmd */ -- cgit v1.3-8-gc7d7 From 6039257378e4c84da06e68230b14fef955508ce6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 10 Feb 2014 10:27:11 +1100 Subject: direct-io: add flag to allow aio writes beyond i_size Some filesystems can handle direct I/O writes beyond i_size safely, so allow them to opt into receiving them. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/direct-io.c | 18 ++++++++++++------ include/linux/fs.h | 3 +++ 2 files changed, 15 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/fs/direct-io.c b/fs/direct-io.c index 160a5489a939..a701752dd750 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -1194,13 +1194,19 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, } /* - * For file extending writes updating i_size before data - * writeouts complete can expose uninitialized blocks. So - * even for AIO, we need to wait for i/o to complete before - * returning in this case. + * For file extending writes updating i_size before data writeouts + * complete can expose uninitialized blocks in dumb filesystems. + * In that case we need to wait for I/O completion even if asked + * for an asynchronous write. */ - dio->is_async = !is_sync_kiocb(iocb) && !((rw & WRITE) && - (end > i_size_read(inode))); + if (is_sync_kiocb(iocb)) + dio->is_async = false; + else if (!(dio->flags & DIO_ASYNC_EXTEND) && + (rw & WRITE) && end > i_size_read(inode)) + dio->is_async = false; + else + dio->is_async = true; + dio->inode = inode; dio->rw = rw; diff --git a/include/linux/fs.h b/include/linux/fs.h index 09f553c59813..f7faefcf4843 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2527,6 +2527,9 @@ enum { /* filesystem does not support filling holes */ DIO_SKIP_HOLES = 0x02, + + /* filesystem can handle aio writes beyond i_size */ + DIO_ASYNC_EXTEND = 0x04, }; void dio_end_io(struct bio *bio, int error); -- cgit v1.3-8-gc7d7 From 557fe99d9d490fe01c7aa87494313078c4ff939c Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Jan 2014 08:54:16 +0100 Subject: pwm: Remove obsolete HAVE_PWM Kconfig symbol Before we had the PWM framework we used to have a barebone PWM api. The HAVE_PWM Kconfig symbol used to be selected by the PWM drivers to specify the PWM API is present in the kernel. Since the last legacy driver is gone the HAVE_PWM symbol can go aswell. Signed-off-by: Sascha Hauer Cc: Dmitry Torokhov Cc: Eric Miao Cc: Haojian Zhuang Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: Thierry Reding Cc: linux-pwm@vger.kernel.orig Cc: Russell King Cc: Ralf Baechle Signed-off-by: Thierry Reding --- arch/arm/Kconfig | 4 ---- arch/arm/mach-pxa/Kconfig | 15 --------------- arch/mips/Kconfig | 1 - drivers/input/misc/Kconfig | 4 ++-- include/linux/pwm.h | 2 +- 5 files changed, 3 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e25419817791..cc6ce44064a2 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -113,9 +113,6 @@ config ARM_DMA_IOMMU_ALIGNMENT endif -config HAVE_PWM - bool - config MIGHT_HAVE_PCI bool @@ -632,7 +629,6 @@ config ARCH_LPC32XX select CPU_ARM926T select GENERIC_CLOCKEVENTS select HAVE_IDE - select HAVE_PWM select USB_ARCH_HAS_OHCI select USE_OF help diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index 96100dbf5a2e..b96244c73ea4 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -7,7 +7,6 @@ comment "Intel/Marvell Dev Platforms (sorted by hardware release time)" config MACH_PXA3XX_DT bool "Support PXA3xx platforms from device tree" select CPU_PXA300 - select HAVE_PWM select POWER_SUPPLY select PXA3xx select USE_OF @@ -23,12 +22,10 @@ config ARCH_LUBBOCK config MACH_MAINSTONE bool "Intel HCDDBBVA0 Development Platform (aka Mainstone)" - select HAVE_PWM select PXA27x config MACH_ZYLONITE bool - select HAVE_PWM select PXA3xx config MACH_ZYLONITE300 @@ -69,7 +66,6 @@ config ARCH_PXA_IDP config ARCH_VIPER bool "Arcom/Eurotech VIPER SBC" select ARCOM_PCMCIA - select HAVE_PWM select I2C_GPIO select ISA select PXA25x @@ -120,7 +116,6 @@ config MACH_CM_X300 bool "CompuLab CM-X300 modules" select CPU_PXA300 select CPU_PXA310 - select HAVE_PWM select PXA3xx config MACH_CAPC7117 @@ -211,7 +206,6 @@ config TRIZEPS_PCMCIA config MACH_LOGICPD_PXA270 bool "LogicPD PXA270 Card Engine Development Platform" - select HAVE_PWM select PXA27x config MACH_PCM027 @@ -222,7 +216,6 @@ config MACH_PCM027 config MACH_PCM990_BASEBOARD bool "PHYTEC PCM-990 development board" depends on MACH_PCM027 - select HAVE_PWM choice prompt "display on pcm990" @@ -246,7 +239,6 @@ config MACH_COLIBRI config MACH_COLIBRI_PXA270_INCOME bool "Income s.r.o. PXA270 SBC" depends on MACH_COLIBRI - select HAVE_PWM select PXA27x config MACH_COLIBRI300 @@ -275,7 +267,6 @@ comment "End-user Products (sorted by vendor name)" config MACH_H4700 bool "HP iPAQ hx4700" - select HAVE_PWM select IWMMXT select PXA27x @@ -289,14 +280,12 @@ config MACH_HIMALAYA config MACH_MAGICIAN bool "Enable HTC Magician Support" - select HAVE_PWM select IWMMXT select PXA27x config MACH_MIOA701 bool "Mitac Mio A701 Support" select GPIO_SYSFS - select HAVE_PWM select IWMMXT select PXA27x help @@ -306,7 +295,6 @@ config MACH_MIOA701 config PXA_EZX bool "Motorola EZX Platform" - select HAVE_PWM select IWMMXT select PXA27x @@ -346,7 +334,6 @@ config MACH_MP900C config ARCH_PXA_PALM bool "PXA based Palm PDAs" - select HAVE_PWM config MACH_PALM27X bool @@ -444,7 +431,6 @@ config MACH_TREO680 config MACH_RAUMFELD_RC bool "Raumfeld Controller" select CPU_PXA300 - select HAVE_PWM select POWER_SUPPLY select PXA3xx @@ -608,7 +594,6 @@ config MACH_E800 config MACH_ZIPIT2 bool "Zipit Z2 Handheld" - select HAVE_PWM select PXA27x endmenu diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index dcae3a7035db..d1326032c8c8 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -235,7 +235,6 @@ config MACH_JZ4740 select IRQ_CPU select ARCH_REQUIRE_GPIOLIB select SYS_HAS_EARLY_PRINTK - select HAVE_PWM select HAVE_CLK select GENERIC_IRQ_CHIP diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 7904ab05527a..762e6d2de3c9 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -156,7 +156,7 @@ config INPUT_MAX8925_ONKEY config INPUT_MAX8997_HAPTIC tristate "MAXIM MAX8997 haptic controller support" - depends on PWM && HAVE_PWM && MFD_MAX8997 + depends on PWM && MFD_MAX8997 select INPUT_FF_MEMLESS help This option enables device driver support for the haptic controller @@ -470,7 +470,7 @@ config INPUT_PCF8574 config INPUT_PWM_BEEPER tristate "PWM beeper support" - depends on PWM && HAVE_PWM + depends on PWM help Say Y here to get support for PWM based beeper devices. diff --git a/include/linux/pwm.h b/include/linux/pwm.h index f0feafd184a0..4717f54051cb 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -7,7 +7,7 @@ struct pwm_device; struct seq_file; -#if IS_ENABLED(CONFIG_PWM) || IS_ENABLED(CONFIG_HAVE_PWM) +#if IS_ENABLED(CONFIG_PWM) /* * pwm_request - request a PWM device */ -- cgit v1.3-8-gc7d7 From b0504e39c27b00101c9c1fa2c58fd896ae0f64f5 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 18 Nov 2013 16:48:19 +0100 Subject: ARM: zynq: Map I/O memory on clkc init The clkc has its registers in the range of the slcr. Instead of passing around the slcr base address pointer, let the clkc get the address from the DT. This prepares the slcr to be a real driver with multiple memory ranges (slcr, clocks, pinctrl,...) Signed-off-by: Steffen Trumtrar Signed-off-by: Michal Simek --- .../devicetree/bindings/clock/zynq-7000.txt | 4 +- arch/arm/boot/dts/zynq-7000.dtsi | 42 +++++----- arch/arm/mach-zynq/common.c | 2 +- drivers/clk/zynq/clkc.c | 89 +++++++++++++++------- include/linux/clk/zynq.h | 2 +- 5 files changed, 88 insertions(+), 51 deletions(-) (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/clock/zynq-7000.txt b/Documentation/devicetree/bindings/clock/zynq-7000.txt index 17b4a94916d6..d93746cf2975 100644 --- a/Documentation/devicetree/bindings/clock/zynq-7000.txt +++ b/Documentation/devicetree/bindings/clock/zynq-7000.txt @@ -14,6 +14,7 @@ for all clock consumers of PS clocks. Required properties: - #clock-cells : Must be 1 - compatible : "xlnx,ps7-clkc" + - reg : SLCR offset and size taken via syscon < 0x100 0x100 > - ps-clk-frequency : Frequency of the oscillator providing ps_clk in HZ (usually 33 MHz oscillators are used for Zynq platforms) - clock-output-names : List of strings used to name the clock outputs. Shall be @@ -87,10 +88,11 @@ Clock outputs: 47: dbg_apb Example: - clkc: clkc { + clkc: clkc@100 { #clock-cells = <1>; compatible = "xlnx,ps7-clkc"; ps-clk-frequency = <33333333>; + reg = <0x100 0x100>; clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci", "lqspi", "smc", "pcap", "gem0", "gem1", diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi index 81e5677f25a2..602e12eedb01 100644 --- a/arch/arm/boot/dts/zynq-7000.dtsi +++ b/arch/arm/boot/dts/zynq-7000.dtsi @@ -123,30 +123,28 @@ } ; slcr: slcr@f8000000 { + #address-cells = <1>; + #size-cells = <1>; compatible = "xlnx,zynq-slcr", "syscon"; reg = <0xF8000000 0x1000>; - - clocks { - #address-cells = <1>; - #size-cells = <0>; - - clkc: clkc { - #clock-cells = <1>; - compatible = "xlnx,ps7-clkc"; - ps-clk-frequency = <33333333>; - fclk-enable = <0>; - clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", - "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", - "dci", "lqspi", "smc", "pcap", "gem0", "gem1", - "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1", - "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1", - "dma", "usb0_aper", "usb1_aper", "gem0_aper", - "gem1_aper", "sdio0_aper", "sdio1_aper", - "spi0_aper", "spi1_aper", "can0_aper", "can1_aper", - "i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper", - "gpio_aper", "lqspi_aper", "smc_aper", "swdt", - "dbg_trc", "dbg_apb"; - }; + ranges; + clkc: clkc@100 { + #clock-cells = <1>; + compatible = "xlnx,ps7-clkc"; + ps-clk-frequency = <33333333>; + fclk-enable = <0>; + clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", + "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", + "dci", "lqspi", "smc", "pcap", "gem0", "gem1", + "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1", + "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1", + "dma", "usb0_aper", "usb1_aper", "gem0_aper", + "gem1_aper", "sdio0_aper", "sdio1_aper", + "spi0_aper", "spi1_aper", "can0_aper", "can1_aper", + "i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper", + "gpio_aper", "lqspi_aper", "smc_aper", "swdt", + "dbg_trc", "dbg_apb"; + reg = <0x100 0x100>; }; }; diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 38401cf78383..93ea19b13e6e 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -67,7 +67,7 @@ static void __init zynq_timer_init(void) { zynq_early_slcr_init(); - zynq_clock_init(zynq_slcr_base); + zynq_clock_init(); clocksource_of_init(); } diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c index 09dd0173ea0a..03052d67b197 100644 --- a/drivers/clk/zynq/clkc.c +++ b/drivers/clk/zynq/clkc.c @@ -21,34 +21,35 @@ #include #include #include +#include #include #include #include -static void __iomem *zynq_slcr_base_priv; - -#define SLCR_ARMPLL_CTRL (zynq_slcr_base_priv + 0x100) -#define SLCR_DDRPLL_CTRL (zynq_slcr_base_priv + 0x104) -#define SLCR_IOPLL_CTRL (zynq_slcr_base_priv + 0x108) -#define SLCR_PLL_STATUS (zynq_slcr_base_priv + 0x10c) -#define SLCR_ARM_CLK_CTRL (zynq_slcr_base_priv + 0x120) -#define SLCR_DDR_CLK_CTRL (zynq_slcr_base_priv + 0x124) -#define SLCR_DCI_CLK_CTRL (zynq_slcr_base_priv + 0x128) -#define SLCR_APER_CLK_CTRL (zynq_slcr_base_priv + 0x12c) -#define SLCR_GEM0_CLK_CTRL (zynq_slcr_base_priv + 0x140) -#define SLCR_GEM1_CLK_CTRL (zynq_slcr_base_priv + 0x144) -#define SLCR_SMC_CLK_CTRL (zynq_slcr_base_priv + 0x148) -#define SLCR_LQSPI_CLK_CTRL (zynq_slcr_base_priv + 0x14c) -#define SLCR_SDIO_CLK_CTRL (zynq_slcr_base_priv + 0x150) -#define SLCR_UART_CLK_CTRL (zynq_slcr_base_priv + 0x154) -#define SLCR_SPI_CLK_CTRL (zynq_slcr_base_priv + 0x158) -#define SLCR_CAN_CLK_CTRL (zynq_slcr_base_priv + 0x15c) -#define SLCR_CAN_MIOCLK_CTRL (zynq_slcr_base_priv + 0x160) -#define SLCR_DBG_CLK_CTRL (zynq_slcr_base_priv + 0x164) -#define SLCR_PCAP_CLK_CTRL (zynq_slcr_base_priv + 0x168) -#define SLCR_FPGA0_CLK_CTRL (zynq_slcr_base_priv + 0x170) -#define SLCR_621_TRUE (zynq_slcr_base_priv + 0x1c4) -#define SLCR_SWDT_CLK_SEL (zynq_slcr_base_priv + 0x304) +static void __iomem *zynq_clkc_base; + +#define SLCR_ARMPLL_CTRL (zynq_clkc_base + 0x00) +#define SLCR_DDRPLL_CTRL (zynq_clkc_base + 0x04) +#define SLCR_IOPLL_CTRL (zynq_clkc_base + 0x08) +#define SLCR_PLL_STATUS (zynq_clkc_base + 0x0c) +#define SLCR_ARM_CLK_CTRL (zynq_clkc_base + 0x20) +#define SLCR_DDR_CLK_CTRL (zynq_clkc_base + 0x24) +#define SLCR_DCI_CLK_CTRL (zynq_clkc_base + 0x28) +#define SLCR_APER_CLK_CTRL (zynq_clkc_base + 0x2c) +#define SLCR_GEM0_CLK_CTRL (zynq_clkc_base + 0x40) +#define SLCR_GEM1_CLK_CTRL (zynq_clkc_base + 0x44) +#define SLCR_SMC_CLK_CTRL (zynq_clkc_base + 0x48) +#define SLCR_LQSPI_CLK_CTRL (zynq_clkc_base + 0x4c) +#define SLCR_SDIO_CLK_CTRL (zynq_clkc_base + 0x50) +#define SLCR_UART_CLK_CTRL (zynq_clkc_base + 0x54) +#define SLCR_SPI_CLK_CTRL (zynq_clkc_base + 0x58) +#define SLCR_CAN_CLK_CTRL (zynq_clkc_base + 0x5c) +#define SLCR_CAN_MIOCLK_CTRL (zynq_clkc_base + 0x60) +#define SLCR_DBG_CLK_CTRL (zynq_clkc_base + 0x64) +#define SLCR_PCAP_CLK_CTRL (zynq_clkc_base + 0x68) +#define SLCR_FPGA0_CLK_CTRL (zynq_clkc_base + 0x70) +#define SLCR_621_TRUE (zynq_clkc_base + 0xc4) +#define SLCR_SWDT_CLK_SEL (zynq_clkc_base + 0x204) #define NUM_MIO_PINS 54 @@ -569,8 +570,44 @@ static void __init zynq_clk_setup(struct device_node *np) CLK_OF_DECLARE(zynq_clkc, "xlnx,ps7-clkc", zynq_clk_setup); -void __init zynq_clock_init(void __iomem *slcr_base) +void __init zynq_clock_init(void) { - zynq_slcr_base_priv = slcr_base; + struct device_node *np; + struct device_node *slcr; + struct resource res; + + np = of_find_compatible_node(NULL, NULL, "xlnx,ps7-clkc"); + if (!np) { + pr_err("%s: clkc node not found\n", __func__); + goto np_err; + } + + if (of_address_to_resource(np, 0, &res)) { + pr_err("%s: failed to get resource\n", np->name); + goto np_err; + } + + slcr = of_get_parent(np); + + if (slcr->data) { + zynq_clkc_base = (__force void __iomem *)slcr->data + res.start; + } else { + pr_err("%s: Unable to get I/O memory\n", np->name); + of_node_put(slcr); + goto np_err; + } + + pr_info("%s: clkc starts at %p\n", __func__, zynq_clkc_base); + + of_node_put(slcr); + of_node_put(np); + of_clk_init(NULL); + + return; + +np_err: + of_node_put(np); + BUG(); + return; } diff --git a/include/linux/clk/zynq.h b/include/linux/clk/zynq.h index e062d317ccce..7a5633b71533 100644 --- a/include/linux/clk/zynq.h +++ b/include/linux/clk/zynq.h @@ -22,7 +22,7 @@ #include -void zynq_clock_init(void __iomem *slcr); +void zynq_clock_init(void); struct clk *clk_register_zynq_pll(const char *name, const char *parent, void __iomem *pll_ctrl, void __iomem *pll_status, u8 lock_index, -- cgit v1.3-8-gc7d7 From 9fe21fdc5f3d3aa7d6e78ad25668e234330b6974 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 21 Dec 2013 15:08:00 +0400 Subject: video: imxfb: Use regulator API with LCD class for powering This patch replaces custom lcd_power() callback with regulator API over LCD class. Signed-off-by: Alexander Shiyan Acked-by: Shawn Guo Signed-off-by: Tomi Valkeinen --- .../devicetree/bindings/video/fsl,imx-fb.txt | 1 + arch/arm/mach-imx/mach-mx27ads.c | 55 +++++++++++++++-- drivers/video/imxfb.c | 71 +++++++++++++++++++--- include/linux/platform_data/video-imxfb.h | 1 - 4 files changed, 114 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/video/fsl,imx-fb.txt b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt index 46da08db186a..e6b1ee9b8e2e 100644 --- a/Documentation/devicetree/bindings/video/fsl,imx-fb.txt +++ b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt @@ -15,6 +15,7 @@ Required nodes: - fsl,pcr: LCDC PCR value Optional properties: +- lcd-supply: Regulator for LCD supply voltage. - fsl,dmacr: DMA Control Register value. This is optional. By default, the register is not modified as recommended by the datasheet. - fsl,lscr1: LCDC Sharp Configuration Register value. diff --git a/arch/arm/mach-imx/mach-mx27ads.c b/arch/arm/mach-imx/mach-mx27ads.c index 9821b824dcaf..a7a4a9c67615 100644 --- a/arch/arm/mach-imx/mach-mx27ads.c +++ b/arch/arm/mach-imx/mach-mx27ads.c @@ -21,6 +21,10 @@ #include #include #include + +#include +#include + #include #include #include @@ -195,14 +199,58 @@ static const struct imxi2c_platform_data mx27ads_i2c1_data __initconst = { static struct i2c_board_info mx27ads_i2c_devices[] = { }; -void lcd_power(int on) +static void vgpio_set(struct gpio_chip *chip, unsigned offset, int value) { - if (on) + if (value) __raw_writew(PBC_BCTRL1_LCDON, PBC_BCTRL1_SET_REG); else __raw_writew(PBC_BCTRL1_LCDON, PBC_BCTRL1_CLEAR_REG); } +static int vgpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) +{ + return 0; +} + +#define MX27ADS_LCD_GPIO (6 * 32) + +static struct regulator_consumer_supply mx27ads_lcd_regulator_consumer = + REGULATOR_SUPPLY("lcd", "imx-fb.0"); + +static struct regulator_init_data mx27ads_lcd_regulator_init_data = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, +}, + .consumer_supplies = &mx27ads_lcd_regulator_consumer, + .num_consumer_supplies = 1, +}; + +static struct fixed_voltage_config mx27ads_lcd_regulator_pdata = { + .supply_name = "LCD", + .microvolts = 3300000, + .gpio = MX27ADS_LCD_GPIO, + .init_data = &mx27ads_lcd_regulator_init_data, +}; + +static void __init mx27ads_regulator_init(void) +{ + struct gpio_chip *vchip; + + vchip = kzalloc(sizeof(*vchip), GFP_KERNEL); + vchip->owner = THIS_MODULE; + vchip->label = "LCD"; + vchip->base = MX27ADS_LCD_GPIO; + vchip->ngpio = 1; + vchip->direction_output = vgpio_dir_out; + vchip->set = vgpio_set; + gpiochip_add(vchip); + + platform_device_register_data(&platform_bus, "reg-fixed-voltage", + PLATFORM_DEVID_AUTO, + &mx27ads_lcd_regulator_pdata, + sizeof(mx27ads_lcd_regulator_pdata)); +} + static struct imx_fb_videomode mx27ads_modes[] = { { .mode = { @@ -239,8 +287,6 @@ static const struct imx_fb_platform_data mx27ads_fb_data __initconst = { .pwmr = 0x00A903FF, .lscr1 = 0x00120300, .dmacr = 0x00020010, - - .lcd_power = lcd_power, }; static int mx27ads_sdhc1_init(struct device *dev, irq_handler_t detect_irq, @@ -304,6 +350,7 @@ static void __init mx27ads_board_init(void) i2c_register_board_info(1, mx27ads_i2c_devices, ARRAY_SIZE(mx27ads_i2c_devices)); imx27_add_imx_i2c(1, &mx27ads_i2c1_data); + mx27ads_regulator_init(); imx27_add_imx_fb(&mx27ads_fb_data); imx27_add_mxc_mmc(0, &sdhc1_pdata); imx27_add_mxc_mmc(1, &sdhc2_pdata); diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 44ee678481d5..e50b67fada51 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -30,10 +30,13 @@ #include #include #include +#include #include #include #include +#include + #include